Friday, April 18, 2025

Entry 31: Instruction decoder part 1

Setting up ROM to hold control signals

In the previous section, we created "ROM256x16". The data stored in this ROM is to be control signals for the control pins. In entry 29, we concluded  that we needed a total of 13 control signals / control pins in order to design the simplest possible processor, capable of running the example program that adds 2 numbers. I arbitrarily assign them as follows:

Our ROM has 16 data bits. Bits 13, 14, and 15 are therefore not used at the moment. 

For example, if we have the following data at a given address:

        0011 0000 0000 0000 (Hex 3000)

where bit 2 and bit 3 are high, the decoder will interpret this to mean that PCW = 1 and MARL = 1, that is, the program counter (PC) writes to the address bus and the memory address register (MAR) loads from the data bus (see entry 29). When the clock goes low-to-high, the PC is transferred to MAR. If all bits are 0, no control pin is activated, and nothing happens.

So, we simply connect 13 of the 16 output pins of the ROM to the corresponding control pin:

Let's program ROM so that we have the control signals for T-state 1 at address 0 and the control signals for T-state 2 at address 1. In entry 29, we concluded that

  • T-state 1: PCW = 1 and MARL = 1.
  • T-state 2: RAMW = 1, IRL = 1, COUNT = 1 (instruction to the instruction register (IR), increment PC).
Therefore, the first two rows of our RAM will contain the following data:

  • If we set the ROM address to 0, it will output the correct control signals for T-state 1.
  • If we set the ROM address to 1, it will output the correct control signals for T-state 2

There is no "universal" T-state 3, the control signals for T-state 3 depend on the instruction, the opcode that is in the IR when T-state 2 is completed. In entry 29, we figured out the control signals for all instructions in all T-states:

I will fill ROM with these control signals:

  • At address 2, all bits are 0, consistent with NOP "no operation" (see entry 28). An address with all data bits equal to 0 is labeled "padding".
  • At address 3, we have the control signals for T-state 3 of the instruction LDA. It will move the PC to MAR
  • At address 4, we have the control signals for T-state 4 of the instruction LDA. It will move the content of RAM to the A register and increment count.
  • At address 5, we have a "padding". When the instruction decoder reads all zeros, it is supposed to interpret this as "the end of the instruction". The decoder is then supposed to change the ROM address to 0, restarting T-state 1.
  • Address 6 and 7 deals with the instruction "ADD" (ALU writes the sum, A loads).
  • Address 8-11 (hex) deals with the remaining instructions. Address 12 and onwards is unused.
  • Note that there are no entries for HLT (halt the program). HLT is not an instruction that requires control pins to be set. I will figure out how to handle HLT later.

Creating an instruction decoder

So, this is what we need to do in order to create an instruction decoder.

  • First, we need a counter to keep track of which ROM address we are currently pointing to. Let's call the counter a "micro counter" to distinguish it from the "program counter", see entry 26.
  • Since ROM has an 8 bit address with 256 possible addresses, the micro counter must be an 8 bit counter, counting from 0 to 255 (0 to FF in hex).
  • When the "computer" starts, the micro counter should be equal to 0, pointing to address 0. The control signals are then consistent with T-state 1.
  • When the clock signal goes high-to-low (falling edge), it should increment (this is different from the program counter, which increments on the rising edge).
  • The first time the clock goes high-to-low, the micro counter increments to 1, pointing to T-state 2.
  • The second time the clock goes high-to-low, the micro counter increments to 2. 
    • When the micro counter is equal to 2, it points to NOP, which is not correct (unless the first instruction happens to be a NOP)
    • Therefore, whenever the micro counter is equal to 2, a new value needs to be loaded into the micro counter.
    • What value to load depends on the instruction.
    • We need to load the address of T-state 3 of the particular instruction (which currently resides in the instruction register, due to the completion of T-state 1 and 2).
    • For example, if the instruction is "STA", the micro counter should become equal to 8, pointing to T-state 3 of STA:
  • The third time the clock goes high-to-low, the micro counter increments to 9, pointing to T-state 4 of STA. 
  • The fourth time the clock goes high-to-low, the micro counter increments to A (10), pointing to the "padding" of STA. When all output signals are 0, the micro counter should reset:
  • The cycle starts over again, with T-state 1 followed by T-state 2, fetching the next instruction.

This leaves us with two tasks:

  • When the micro counter outputs the number 2, it need to "load itself" with a new address, an address that depends on the instruction in the IR.
  • When all output pins of ROM are 0, we need to trigger a reset of the micro counter.
In addition, we must figure out how to handle HLT.. all in the next entry.