62 / 63 · Concept
Register interfaces and the timing of side effects
Specify addresses, byte writes, and response stalls so each request causes exactly one state-changing action.
Lessons are free to read. Enroll to save your learning progress.
Define what “writing a register” means
Prerequisites: address decodersDecoder A circuit that activates the output line corresponding to a binary code. With an enable input, all outputs can be set to 0 when disabled. Learn more, ready/validHandshake A contract that accepts a transfer when the sender's valid and the receiver's ready are both 1 at the same edge. It also defines how data must be held while waiting. Learn more, enable, and state-update priorities.
Connecting configuration registersRegister A circuit that stores multiple bits of state. The synchronous registers in this course store their specified inputs at a clock edge. Learn more to an external controller requires more than checking an address match. Define when a request is accepted, what must remain stable while a response waits, and what happens on a write to a read-only address. Here we use a simple single-request/single-response interface in one clock domain.
The addresses below are byte addresses with 32-bit alignment. Every request produces exactly one success or error response.
| Address | Name | Behavior |
|---|---|---|
| 0x0 | CONFIG | Read/write, with byte strobes |
| 0x4 | STATUS | Read-only; return the value at acceptance |
| 0x8 | COMMAND | Reads return 0; writing bit 0 of byte 0 produces a start pulse |
| Other | Undefined | Error response; no state change |
Accept when the response slot is empty or becomes empty at the edge
module register_interface (
input logic clk, rst,
input logic req_valid, req_write,
output logic req_ready,
input logic [3:0] req_addr,
input logic [31:0] req_wdata,
input logic [3:0] req_wstrb,
output logic rsp_valid,
input logic rsp_ready,
output logic [31:0] rsp_rdata,
output logic rsp_error,
input logic [31:0] status_value,
output logic [31:0] config_value,
output logic start_pulse
);
assign req_ready = !rsp_valid || rsp_ready;
always_ff @(posedge clk) begin
if (rst) begin
rsp_valid <= 1'b0;
config_value <= 32'd0;
start_pulse <= 1'b0;
end else begin
start_pulse <= 1'b0;
if (req_ready) begin
rsp_valid <= req_valid;
if (req_valid) begin
rsp_rdata <= 32'd0;
rsp_error <= 1'b0;
case (req_addr)
4'h0: begin
if (req_write) begin
for (int i=0; i<4; i++)
if (req_wstrb[i])
config_value[8*i +: 8]
<= req_wdata[8*i +: 8];
end else rsp_rdata <= config_value;
end
4'h4: begin
if (req_write) rsp_error <= 1'b1;
else rsp_rdata <= status_value;
end
4'h8: begin
if (req_write)
start_pulse <= req_wstrb[0] && req_wdata[0];
end
default: rsp_error <= 1'b1;
endcase
end
end
end
end
endmoduleWhen the response stalls, req_ready=0, so the configuration write or command pulse is not executed again. The side effect of an accepted request may already have occurred while only its response remains pending. Unconditionally resending a request because its response is delayed can execute a command twice.
Work out the meaning of byte strobes
With CONFIG=32'h11223344, a write of req_wdata=32'hAABBCCDD and req_wstrb=4'b0101 changes only bytes 0 and 2. The result is 32'h11BB33DD. Check address alignment, bit positions, and memory byte order separately. A write with wstrb=0000 succeeds but changes no value.
From the MSBMSB The bit with the highest place value. Its index depends on the vector's declaration direction, so do not assume it always has the largest index. Learn more, the order is byte 3, 2, 1, 0. strobe=0101 selects bytes 2 and 0, so only BB and DD are newly written. A strobe is a byte-wide write enable, not an enable for a single data bit.
- Old CONFIG: 11 | 22 | 33 | 44
- Write data: AA | BB | CC | DD
- strobe 0101: Keep | replace | keep | replace
- New CONFIG: 11 | BB | 33 | DD
Which instant does a status value represent?
A STATUS read response stores status_value at request acceptance. Even if the actual status changes while the response is stalled afterward, rsp_rdata holds. Directly connecting combinational status to the response while rsp_valid=1 and rsp_ready=0 would change the response contents and violate the protocol.
If req_valid and req_ready are both 1 at consecutive edges, these are two separate requests. After acceptance, the sender must lower valid or update to the next request. It must not hold the same request continuously and expect it to be processed only once.
Three axes of verification
- Addresses and permissions: check errors and side effects for valid addresses, unaligned addresses, STATUS writes, and undefined addresses.
- Data selection: exhaustively test the four strobe bits and check preservation of inactive bytes.
- Flow control: block responses for multiple cycles and check that responses and state hold. Check matching transaction counts when response consumption overlaps acceptance of the next request.
Try it yourself
After a COMMAND write with req_wstrb[0]=1 and req_wdata[0]=1 is accepted, rsp_ready remains 0 for three cycles. Should start_pulse repeat for those three cycles? May a STATUS write change config_value?
Read the explanation
start_pulse is 1 for only one cycle immediately after request acceptance, then returns to 0. A stalled response does not trigger command re-execution. A STATUS write returns an error without changing other state, including config_value. The sender and receiver must also agree on a retry policy before response completion.