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...
- 32 bits per register
- One input port
- Optional write per cycle
- Two output ports working in parallel
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.
The left side of the diagram will be implemented as the Register Select board and contain the following components...
- 3 x 74HC688
- 1 x 74HC08
- 4 x 100nF bypass capacitors
- 1 x 5 position DIP switch
- 5 x 4.7k ohm resistors
- 3 x LED
- 3 x 470 ohm resistors
- 2 x 10P long female headers
- 1 x 8P right angle female header
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...
Read more »