Close

Register File

A project log for World's first 32bit Homebrew CPU

Creating the world's first 32bit homebrew CPU using 74' series logic.

phil-wrightPhil Wright 11/25/2016 at 00:203 Comments

You can see the specification for the user level RISC-V ISA by going to the http://riscv.org website and looking inside the specifications menu section. We are going to be implementing the RV32E specification. This is a 32 bit machine with the embedded microprocessor (E) extension. It only requires 16 general purpose registers instead of the standard 32 and it also makes optional some of the features that would otherwise be mandatory.

Our first design step is to work on the register file as it is the heart of the processor. It needs to need the following requirements...

Here is out black box diagram for it...


The blue input port (Data In) and output ports (A and B) are both 32 bit buses. The green control lines provide a clock signal (CLK) and a write (W) line. Only if the write line is high does a target register get updated on the clock signal. Most processor instructions do not cause a register to be updated so the W line will only be high for update instructions. The IN control line is 5 bits wide and specifies the target register for the write. The A and B control lines are also 5 bits wide and identify the register to output to the matching port. Five bits gives us 2^5 = 32 possible target registers. Strictly speaking we only need 4 bits to encode the 16 registers but I went with the 5 for a couple of reasons.

The RISC-V instructions have 5 bits assigned to selecting registers and so it becomes natural to pass those instruction bits straight to the register control lines without throwing one away. Plus, in the future it would be easy to expand the processor to have the full 32 registers if I decide to switch from the RV32E to the RV32I specification. It is easy to make it 5 instead of 4 at this stage and we might as well leave future options open by doing so.

If we expand into a high level design we get the following...


To implement the output ports we need to ensure that only 1 of the possible 16 registers outputs to each port at a time. So we use buffer drivers on each port. In order to decide if the buffer should output or be high impedance we use the selection logic on the left side of the diagram. They do a compare against the A and B control lines to decide if this register is selected. To update the memory we need to ensure we are the selected IN register along with the write line being high and the clock high. Only if all three constraints occur should the memory update occur.

Converting this into an actual logic chip design we get...


First you will notice we have split the register into two half's, the left side is performing the selection logic and then the right half is implementing the actual memory and output. This is because there are too many logic chips to fit on a single 100mm x 80mm PCB if it was all implemented at once. So we are forced to split it into more than one board. You will also note that the output buffers suddenly have two control lines going into them.

The 74HC241 buffer driver IC has an odd specification. It has 8 input lines and 8 output lines but they are split into two blocks of 4. The first block output on a high enable value but the second block outputs on a low enable value. So to get all 8 lines to output (or to turn the output off) I need to provide two control lines that are inverted from each other. Hence on the left side of the diagram you will see there are two NOT gates used to provide those inverted values.


Register Select

The left side of the diagram will be implemented as the Register Select board and contain the following components...

Each board will have a DIP switch that is used to define the register number along with 5 pull down resistors for when the switch is in the off position. There are three LED's that indicate the value of the IE, AE and BE output lines. That will help with debugging by allowing us to quickly visually check the results of the board.

To provide the incoming control lines we use two long female headers. One of them will have the port select A and B and the other all the other controls lines. Using long female headers means we can act stack all 16 registers on top of each other (Arduino Shield style). The right angle header carries the outputs to the Register Store board.

I have already created a prototype board, it looks like this...

Register Store

The right side of the diagram will be implemented as the Register Store and contain the following...

No doubt you will have noticed already that this only handles 16 bits and not the full 32. There is not enough room on a 100mm x 80mm to fit the 12 IC's needed to fully implement a 32 bit register. That would be 4 x 8 bit memory chips and 8 x 8 bit buffer drivers. When you add in the 32 incoming data lines and 64 output lines needing headers then it becomes impossible. So instead the board implements exactly half the storage. Then we can daisy chain two of them together to get the full 32 bit wide register.

A right angle male header brings in the control lines in from the Register Select board. A right angle female header on the opposite side of the board sends it out again to the next daisy chained Register Store board. It has three long female headers that bring in 16 data lines and sends out 2 x 16 port lines. Finally there are two right angle female headers that always give the current memory contents output. This is not shown on the design diagram and will be used to help with debugging. By attaching an external board that shows the current value it will be possible to monitor what is happening when single stepping the CPU.

I have created a prototype of this board as well but do not currently have a picture, I will add it later.

Both the boards had small errors that require them to be corrected and remade. I aim to order them in the next week and have them ready for testing at the start of December. I will update with the results when that happens.

Discussions

Phil Wright wrote 11/25/2016 at 01:25 point

This is the first electronics I have done so it was bound to be a bit ropey! The 241 does handle 8 bits it is just that it has two enables to handle the first and the second blocks of 4 separately and with opposite enable logic. Using the 245 looks like it would prevent me needing to use the NOT gates to get the two enable lines with opposite values.

Even better is the use of two 574, which is something I never would have thought of. Logically it would not occur to me to store the value twice because it obviates the need for the buffer drivers. Nice.

I also would never have though to use a de-multiplexer at an earlier stage.

Nice tricks that mean I have to go back and redesign the boards again! But that's the fun!

  Are you sure? yes | no

Yann Guidon / YGDES wrote 11/25/2016 at 01:36 point

here's a couple of sketches:

I've used more tricks for the #Discrete YASEP and I have chosen to use multiplexors instead of tristate. One reason is that instead of latches, some registers are actually counters :-D

  Are you sure? yes | no

Yann Guidon / YGDES wrote 11/25/2016 at 00:48 point

I'm puzzed by several features...

Why only one read address ?

Furthermore, you use 688s all over the place when a few 138 on the control plane would do the work, faster, smaller and cheaper.

Why bother with 241s when the 245 is a full byte ?

They are useless anyway if you consider that the 574 has tristate outputs. Just use a pair of 574 per byte, each being written with the same data but one is tied to port A and the other to port B. 

This should help you cut your circuit count by a significant amount.

  Are you sure? yes | no