Day 64: Building block: the 2R1W register file
Building block: the 2R1W register file
The register file stores x0–x31 with two combinational read ports and one clocked write port (Stage 1, Day 40). In RTL it's a small memory array with two asynchronous reads and a synchronous write — plus the critical `x0` special case: reads of index 0 return 0, and writes to index 0 are ignored.
module regfile (
input clk,
input [4:0] ra1, ra2, wa,
input [31:0] wd,
input we,
output [31:0] rd1, rd2
);
reg [31:0] regs [1:31]; // index 0 not stored — it is always zero
assign rd1 = (ra1 == 5'd0) ? 32'd0 : regs[ra1];
assign rd2 = (ra2 == 5'd0) ? 32'd0 : regs[ra2];
always @(posedge clk)
if (we && wa != 5'd0) // never write x0
regs[wa] <= wd;
endmoduleWrite-first for the pipeline
In the pipelined core, WB writes a register in the same cycle ID reads it. A common convention is a write-first / internal-forwarding register file (write in the first half-cycle, read the new value in the second) so a register written in WB is visible to a dependent instruction in ID — reducing forwarding cases. Note the choice now; it matters when you pipeline (Day 87).
Ship for Day 64
In the register file RTL, why guard the write with (wa != 5'd0)?