Electronic – Approaches to storing and addressing microcode for homebrew CPU

computer-architecturehomebrew-cpumicroprocessor

I've been teaching myself about CPU architecture for a while now and have successfully designed a couple myself. They were always based around microcode to drive the CPU's control lines.

The microcode is stored on one ROM chip and addressed by composing an address out of (1 = LSB):

  1. Bank
  2. CPU flag states
  3. Instruction
  4. T-state

Let's take my latest CPU as an example of how the address is constructed:

  1. Bank (3 bits) – There are 48 control lines in my CPU, so I need 6 bytes to store all control line states. The bank part of the address allows me to address 6 bytes in the microcode ROM.
  2. CPU flag states (3 bits) – I narrowed down my flags to zero, carry and compare. Need 3 bits to address all combinations
  3. Instruction (8 bits) – The instruction set requires over 127 op-code, so I choose to go with 8 bits.
  4. T-state (5 bits) – Some instructions take over 16 t-states to complete (complex ones like conditional CALL / RETURN) so with 5 bits I have enough room for up to 32 t-states

The final example microcode ROM address would look something like:

[flags][instruction][t-state][bank]
[000][00000000][00000][000]

Now for my question:
In the above example I seem to have reached the limit of what I can do with this approach. My microcode ROM address is 19 bits long and I have found one chip that supports it (29C040) but it seems that I don't have a lot of options if I want a large address.

I'm thinking about my next CPU which will need more flags (negative, overflow, parity) and who knows, maybe even a few more control lines or an extra bit for T-states.

What would be a better approach of storing and addressing my microcode in that case?

Only thing I can think of right now is to:

  • Add more ROM chips (would only free up 1 extra bit? per chip doesn't seem a good approach)
  • Limit the instruction set (also, would only give me 1 – maybe 2 – extra bits)
  • Limit the amount of control lines, but that would allow for less control over the CPU…

I wonder how this is solved in professional, microcode based CPU's and what I'm missing here.

Best Answer

Your addressing scheme uses completely disjoint areas of microcode memory for every possible instruction. Most CPUs have a lot of microcode that can be shared among instructions. For example, instruction fetch, operand read and result writeback are typically identical across large groups of instructions, with the only difference being the specific ALU operation performed in the middle.

It's also very odd to store the bytes of the microcode word serially — this means that your ROM must cycle 6 times for every "T state". It is much more common to make the microcode memory wide enough so that it cycles at the same rate as the rest of the logic.

Finally, it sounds like you're experimenting with CPU design. Maybe you should consider using wide SRAM for your microcode memory, and loading it up from some external source (an Arduino or equivalent) each time you power up your system. This would make it a lot easier to make changes.