Level 49: Anatomy of an R-Instruction

Open level →

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 from we + waddr and 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.v must contain a RegBank32 instance with all ports connected;
  • x0 is frozen: the wen[0] wire must be built through the constant 1'b0 — there is no write path to x0;
  • ram256 and rom are forbidden — only dff flip-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.