# Register File

A register file comprises a series of parallel load registers and is an integral part of a CPU. The register file outputs the contents of chosen registers to the rest of the CPU and loads registers with input values given by the rest of the CPU.

## Example

Consider a 16-bit CPU with eight parallel load registers. A typical design will at most need to deal with operations giving an input of one value to load into a register and requiring the output of two register values. An example of such an operation could be the adding of two register contents with the result of the addition loaded into a third register. Let's call the two register contents that are output from the register file `A` and `B`. The input value to be loaded into a register we'll call `D` (for destination). The register file will need three 3-bit addresses to select these registers from the eight possible (23=8). Let's call these addresses `AA`, `BA`, and `DA`, and we'll have them as inputs to the register file. Since we have registers which are sequential logic circuits, we will have a clock input called `CLK`. The one remaining input is called `Load`. Its purpose is to enable or disable the loading of the register addressed by `DA`. This is needed as it may be the case that a no register is to be loaded — registers `A` and `B` may be used as memory address and data as part of a memory write operation. In total we have inputs `AA`, `BA`, `DA`, `D`, `CLK`, and `Load`. Our outputs are `A` and `B`.

If the output of each register is fed into a multiplexer, we can use `AA` and `BA` to select the register whose contents is to become the `A` or `B` output. So, we will have two internal multiplexers, `muxa` and `muxb`.

The `D` input needs to be fed into a register so it can be stored on a positive clock edge. The input address, `DA`, can be used to select the Load input of one of the eight registers if we feed `DA` into an octal decoder and connect a decoder output to the Load input of each register. Instead of making this connection directly, we use an AND gate to generate the `Load` input for each register. The inputs to each gate would the the register file's `Load` input and the appropriate decoder output. This would only permit a register load when the register file's `Load` input was `1`.

Our bill of materials is now eight registers, eight AND gates, one decoder, and two multiplexers. A schematic form of the register file which, for the purposes of saving space, has been simplified to show only four registers is shown below.

## Verilog

Below is a Verilog structural model for the example register file (with all eight registers). The code for the flip-flops, multiplexers, and the decoder is also shown for completeness.

```	```
module register_file(A, B, D, AA, BA, DA, Load, CLK);
output [15:0] A;     // Data contents of A reg.
output [15:0] B;     // Data contents of B reg.
input [15:0]  D;     // Data to load into D reg.
input [2:0] 	 AA;    // Address of A reg.
input [2:0] 	 BA;    // Address of B reg.
input [2:0] 	 DA;    // Address of C reg.
input 	 Load;  // Enable loading of D reg - active high.
input 	 CLK;   // Clock.

wire [15:0] 	 Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7;
wire 	 dr0, dr1, dr2, dr3, dr4, dr5, dr6,dr7;

multiplexer_8_1 muxa(A, Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, AA);
multiplexer_8_1 muxb(B, Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, BA);

octal_decoder decd(dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7, DA[2], DA[1], DA[0], 1'b1);

endmodule // register_file

output [15:0] Q;
input [15:0]  D;
input 	 CLK;

wire 	 w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12;           // Connecting wires.
wire 	 w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24;  // Connecting wires.
wire 	 w25, w26, w27, w28, w29, w30, w31, w32, w33, w34, w35, w36;  // Connecting wires.
wire 	 w37, w38, w39, w40, w41, w42, w43, w44, w45, w46, w47, w48;  // Connecting wires.
wire [15:0] 	 Qn;   // Unused.

or(w3, w2, w1);

or(w6, w5, w4);

or(w9, w8, w7);

or(w12, w11, w10);

or(w15, w14, w13);

or(w18, w17, w16);

or(w21, w20, w19);

or(w24, w23, w22);

or(w27, w26, w25);

or(w30, w29, w28);

or(w33, w32, w31);

or(w36, w35, w34);

or(w39, w38, w37);

or(w42, w41, w40);

or(w45, w44, w43);

or(w48, w47, w46);

d_flip_flop_edge_triggered dff0(Q[0], Qn[0], CLK, w3);
d_flip_flop_edge_triggered dff1(Q[1], Qn[1], CLK, w6);
d_flip_flop_edge_triggered dff2(Q[2], Qn[2], CLK, w9);
d_flip_flop_edge_triggered dff3(Q[3], Qn[3], CLK, w12);
d_flip_flop_edge_triggered dff4(Q[4], Qn[4], CLK, w15);
d_flip_flop_edge_triggered dff5(Q[5], Qn[5], CLK, w18);
d_flip_flop_edge_triggered dff6(Q[6], Qn[6], CLK, w21);
d_flip_flop_edge_triggered dff7(Q[7], Qn[7], CLK, w24);
d_flip_flop_edge_triggered dff8(Q[8], Qn[8], CLK, w27);
d_flip_flop_edge_triggered dff9(Q[9], Qn[9], CLK, w30);
d_flip_flop_edge_triggered dff10(Q[10], Qn[10], CLK, w33);
d_flip_flop_edge_triggered dff11(Q[11], Qn[11], CLK, w36);
d_flip_flop_edge_triggered dff12(Q[12], Qn[12], CLK, w39);
d_flip_flop_edge_triggered dff13(Q[13], Qn[13], CLK, w42);
d_flip_flop_edge_triggered dff14(Q[14], Qn[14], CLK, w45);
d_flip_flop_edge_triggered dff15(Q[15], Qn[15], CLK, w48);

module d_flip_flop_edge_triggered(Q, Qn, C, D);
output Q;
output Qn;
input  C;
input  D;

wire   Cn;   // Control input to the D latch.
wire   Cnn;  // Control input to the SR latch.
wire   DQ;   // Output from the D latch, inputs to the gated SR latch.
wire   DQn;  // Output from the D latch, inputs to the gated SR latch.

not(Cn, C);
not(Cnn, Cn);
d_latch dl(DQ, DQn, Cn, D);
sr_latch_gated sr(Q, Qn, Cnn, DQ, DQn);
endmodule // d_flip_flop_edge_triggered

module d_latch(Q, Qn, G, D);
output Q;
output Qn;
input  G;
input  D;

wire   Dn;
wire   D1;
wire   Dn1;

not(Dn, D);
and(D1, G, D);
and(Dn1, G, Dn);
nor(Qn, D1, Q);
nor(Q, Dn1, Qn);
endmodule // d_latch

module sr_latch_gated(Q, Qn, G, S, R);
output Q;
output Qn;
input  G;
input  S;
input  R;

wire   S1;
wire   R1;

and(S1, G, S);
and(R1, G, R);
nor(Qn, S1, Q);
nor(Q, R1, Qn);
endmodule // sr_latch_gated

module multiplexer_8_1(X, A0, A1, A2, A3, A4, A5, A6, A7, S);
parameter WIDTH=16;     // How many bits wide are the lines

output [WIDTH-1:0] X;   // The output line

input [WIDTH-1:0]  A7;  // Input line with id 3'b111
input [WIDTH-1:0]  A6;  // Input line with id 3'b110
input [WIDTH-1:0]  A5;  // Input line with id 3'b101
input [WIDTH-1:0]  A4;  // Input line with id 3'b100
input [WIDTH-1:0]  A3;  // Input line with id 3'b011
input [WIDTH-1:0]  A2;  // Input line with id 3'b010
input [WIDTH-1:0]  A1;  // Input line with id 3'b001
input [WIDTH-1:0]  A0;  // Input line with id 3'b000
input [2:0]	      S;

assign X = (S[2] == 0
? (S[1] == 0
? (S[0] == 0
? A0       // {S2,S1,S0} = 3'b000
: A1)      // {S2,S1,S0} = 3'b001
: (S[0] == 0
? A2       // {S2,S1,S0} = 3'b010
: A3))     // {S2,S1,S0} = 3'b011
: (S[1] == 0
? (S[0] == 0
? A4       // {S2,S1,S0} = 3'b100
: A5)      // {S2,S1,S0} = 3'b101
: (S[0] == 0
? A6       // {S2,S1,S0} = 3'b110
: A7)));   // {S2,S1,S0} = 3'b111
endmodule // multiplexer_8_1

module octal_decoder(X0, X1, X2, X3, X4, X5, X6, X7, A2, A1, A0, E);
output X0; // Minterm 0
output X1; // Minterm 1
output X2; // Minterm 2
output X3; // Minterm 3
output X4; // Minterm 4
output X5; // Minterm 5
output X6; // Minterm 6
output X7; // Minterm 7

input  A2;  // Input binary code most significant bit
input  A1;  // Input binary code middle bit
input  A0;  // Input binary code least significant bit

input  E;   // Enable signal

wire   A2n; // A2 negated
wire   A1n; // A1 negated
wire   A0n; // A0 negated

not(A2n, A2);
not(A1n, A1);
not(A0n, A0);

and(X0, A2n, A1n, A0n, E);  // Minterm 0: 000
and(X1, A2n, A1n, A0, E);   // Minterm 1: 001
and(X2, A2n, A1, A0n, E);   // Minterm 2: 010
and(X3, A2n, A1, A0, E);    // Minterm 3: 011
and(X4, A2, A1n, A0n, E);   // Minterm 4: 100
and(X5, A2, A1n, A0, E);    // Minterm 5: 101
and(X6, A2, A1, A0n, E);    // Minterm 6: 110
and(X7, A2, A1, A0, E);     // Minterm 7: 111
endmodule // octal_decoder
```
```

Below we see the waveforms generated by a simple test run which comprised the loading of A5A5 (hex) into register 7 and the outputting of registers 0 and 1. This was followed by the loading of 1234 (hex) into register 7 and the outputting of registers 0 and 7.

## References

Mano, M. Morris, and Kime, Charles R. Logic and Computer Design Fundamentals. 2nd Edition. Prentice Hall, 2000.