Level 49: Anatomy of an R-Instruction
Task
Goal: build the RV32I register file: a bank of 32×32 flip-flops, a write decoder with frozen x0, and two read ports. This circuit stands behind every R-type instruction like add x5, x6, x7. This is the same register file you saw in the level 48 widget — now in hardware.
Build the RV32I register file — the RegFile32 block: a bank of 32 registers, 32 bits each, two read ports and one write on the clock edge. This is the circuit behind every R-type instruction such as add x5, x6, x7: two source registers are read, the destination register is written.
The project is multi-file (tabs on the left); all three files are editable:
regfile.v— main file: the write decoder fromwe+waddrand the bank instance.regbank.v— 32 Reg32 registers, read address decoders and two 32:1 muxes.reg32.v— one 32-bit register with a write enable.
RegFile32 interface: inputs we (write enable), waddr[4:0], wdata[31:0], raddr1[4:0], raddr2[4:0], clk; outputs rdata1[31:0], rdata2[31:0].
Three structural requirements are checked:
regfile.vmust contain aRegBank32instance with all ports connected;- x0 is frozen: the
wen[0]wire must be built through the constant1'b0— there is no write path to x0; ram256andromare forbidden — onlydffflip-flops and gates.
Solution for self-check
First try to build the block yourself. The solution below gives the build and check order.
What you should get: RegFile32 passes the table: a write to x5 reads on both ports, a write to x0 is ignored, we=0 keeps the value — a 32×32 bank with x0 frozen by the 1'b0 constant.
Build order: bottom-up. Reg32 → RegBank32 → RegFile32.
Step 1 — reg32.v: a register with mux feedback. When en=0, the register must keep its value. The idiom: drive the flip-flop input with d = (din & en) | (q & not(en)) — with the enable off, the register reads itself. The bits themselves are dff flip-flops via generate for over 32 bits (the technique from level 37).
Step 2 — regbank.v: the bank and two read ports. Instantiate 32 Reg32 instances — one per wen bit. Decode the read addresses ra1/ra2 into one-hot (the same and-chains as for writes), then build a generate mux per port: 32 AND gates per bit and an or-tree. Both ports work independently: the first can read x6 while the second reads x7 at the same moment.
Step 3 — regfile.v: the write decoder and freezing x0. Five inverters on the waddr bits, and-chains for each wen[i], masked by we. For wen[0] connect the constant 1'b0 — writes to x0 become impossible in hardware. The bank port order is positional: RegBank32 bank(rdata1, rdata2, clk, wen, wdata, raddr1, raddr2).
Step 4 — verify. The level table is orthogonal: no row reads a register written in the same row. Check it yourself: write to x5 and read through both ports; try writing to x0; read x5 and x31 simultaneously; we=0 — the value does not change; overwrite x5 with a new number.
Principle: writing happens on the clk edge, while reading is combinational. That is why two read ports need neither a second cycle nor a second bank of flip-flops — only a second mux.
Check yourself
Why do two read ports not require a second cycle?
Reading is combinational: the address decodes to one-hot and a mux picks the register immediately; writing happens only on the clk edge. The second port is just a second mux over the same bank.