In this part of the series I’ll show you the necessary components for storing and executing programs on our micro processor! I’ll try to keep this part quite short, because I already explained in detail what a micro-instruction is and what it consists of on this CPU in part 2! So, let’s get the ball rolling.
Like discussed in the last part, our CPU will have 256 micro-instructions with a length of 32-Bits each. This means, that it’s possible to store programs with a length of 8.192 Bit.
What I plan to do in my design is to get a ROM where the program is stored on the CPU. The line of code that’s about to be calculated will be loaded in a separate 32-Bit register, which is then connected to the relevant parts.
For example the address, where the result of the next calculation should be stored, is in the line of code. These outputs from the instruction-register will be connected to the R-decoder which will then activate the relevant register and then the result can be stored in the register-file.
Let’s take a look at one micro-instruction and take it apart even further. For now we know, that one instruction will consist of 32-Bits and it will hold the following information. The number in the parentheses is the number of bits needed to store the information:
a) ALU-OP (2)
b) REG-A (4)
c) REG-B (4)
d) REG-R (4)
e) EN-WRITEBACK (1)
f) SHIFT (2)
g) JUMP (2)
h) JMP-ADDR (8)
i) EN-MEM-ADDR (1)
j) EN-MEM-BUFF (1)
k) RW-FLAG (1)
l) MEM-SELECT (1)
m) USE-MEM (1)
And I want to organise one complete instruction like this:
This way the information is nicely grouped. The first 6-Bits are used for control-flow and calculations, the next big portion of 20-Bits are used to address everything, like the registers and the next line of code, when a jump occurred. The last 6-Bits are memory flags of all sorts.
You could organise one instruction in which ever way you want to. But it makes sense to think about the layout of your CPU and where each line will have to go in your hardware. However I wanted mine to be nicely organised.
Let’s say we want to take the registers R12 and R1 and add them together. The result should be stored in R3. There are no external memory-operations in this call.
Our instruction would look like this (in binary):
// ALU-Addition = 10 // R12 = 1100; R1 = 0001; R3 = 0011 aa-ff-gg-hhhhhhhh-bbbb-cccc-dddd-e-i-j-k-l-m 10-00-00-00000000-1100-0001-0011-1-0-0-0-0-0
As you can see, there’s nothing really complicated about this. All the codes, for example for the ALU-Operations can be found in part 2 of the series!
This portion is huge again, but I decided to split it apart and show the relevant parts, as this part of the series did not become too long (yet 😉 ).
Note that, like in part 2, I didn’t build the whole 256-lines, because that would not have only taken a while to do, but it also would have used up a lot of space. I think you’ll get the point and in reality I would use a pre-made ROM-chip, so that’s fine and you can actually even think of the program-storage as a black-box, but I still find it quite interesting to show this, at least once. The ROM with the address-decoder and the current-instruction and instruction-counter registers looks like this:
So in the first clock-period the next instruction is loaded from the ROM and it is then stored in the 32-Bit register below. This register is connected to the respective parts of the circuit. For example the two ALU-OP-Bits go over to the ALU and tell it, what to do next (ADD, AND, NOT or nothing).
Why aren’t the lines directly going from the ROM to the respective parts you might be asking. And it’s a good question for sure! My idea behind this is, that we I don’t the signals to immediately reach their goals. I rather want this to happen in the EXECUTE-step of the clock cycle. Before that happens, the data has to be fetched from the registers and the old result has to be stored.
After the instruction has been loaded into the register, the instruction counter either has to be incremented by one, or, if a jump occurred, it has to be set to another address after the execution of the current instruction has finished. The jumps are managed by the following part of the circuit:
The following adder increments the instruction counter by one, if no jump occurred and the current instruction was executed:
Basically that’s all the additional stuff that I had to say about the program storage. There are only a bunch of connections to be made, but this will happen in the next part of the series.
In the next part …
… I’ll finish the design by adding the shifter, the connections to the ALU and to the instruction-register and by building the 4-phase-clock.