Close

CPU schematic explained

A project log for Kobold K2 - RISC TTL Computer

A 16 bit RISC computer with video display, from just a few TTL and memory chips. Online C compiler and simulator available.

roelhroelh 10/02/2019 at 19:311 Comment

This will be a quite long log....  luckily, it will naturally stop when all 42 IC's have been explained...

This will be a detailed description of the schematic. For a good understanding, first read the first log and the logs that follow it.

The schematic was split into nine sections, that will be discussed:

I want to start with something simple, the ALU, but let's first do the instruction register because allmost every subcircuit is connected to instruction bits.

[edit: this describes an older version of the schematics, it needs an update]

INSTRUCTION REGISTER

The instructions are 16 bits wide. The register gets written during the FETCH cycle. Its outputs are (from top to bottom):

Note that during reset, the instruction is forced to 0x0000. The function of the instruction bits and their combinations can also be found in the Instruction encoding log.

ALU

The ALU is quite simple. There are two input busses, D0-D15 that normally come from memory, and OP0-OP15 that come from one of the data registers D0-D3. Outputs are BUS0-BUS15.

At the left side, you see 16 gates that perform the NOR function on the two inputs. In the middle, four HC283 adders will add both inputs. At the right side, a bunch of multiplexers will choose either the NOR or the ADD as a result on the result signals, called BUS0-BUS15. The IR_M signal comes from the instruction register, and provides the selection signal for the multiplexers. 

Note that the multiplexers that deliver the BUS0-BUS15 signals can be put in high-impedance state with the FN_OE/ signal, and the adder has a carry-in and carry-out, both to be discussed later. 

DATA AND ADDRESS REGISTERS

The data and address registers are built with the 74HC670 (that chip is explained HERE). There are 4 data registers and 4 address registers, these are all 16 bit wide. (These are actually latches instead of registers, to be discussed later).

The input to the registers is shown at their left side. The data bits come from the ALU (they are connected to BUS0-BUS15), and the R0, R1 bits determine which of the four registers in the IC gets written (when DATA_WE/ or ADDR_WE/ is low).

The output of the data registers is connected to the OP0-OP15 bus. One of the four registers is selected with the same R0, R1 signals. Note that the IR_L bit, coming from the instruction register, can disable the register output. The outputs will then be pulled low by pulldown registers (on another part of the schematic). Since the OP0-OP15 bus is one of the inputs to the ALU, this will change an ADD instruction to a MOV and a NOR instruction to MOVC (MOV-complement).

The output of the address registers is selected by P0 and P1 coming from the control section, but when ZPage addressing is selected, this will always be A1 (the workspace pointer WP), so the WP provides the upper address bits for the zero page.

At the right side of the picture you find two multiplexers that connect most of the lower address bits to an alternative source when Zpage addressing is used. Bits A1 and A2 are in that case connected to P0 and P1. Together with the four displacement bits this gives 64 possible "zero page" locations. Address bit A3 will be 1 when the destination is register A0 (PC) or D0, providing another 64 locations as quick jump vectors.

Note that the address outputs can be tri-stated with the ENABLE/ signal. That is connected to the I/O connections of the CPU, and can be activated by another device when it wants to access memory.

SHIFT UNIT

The previous mentioned 74HC670 register chips are cute, but have a disadvantage. They are latches, not registers. So if one of the registers is connected to the ALU, and the ALU result is written back to the same register, this new value immediately goes to the output, creating a feedback loop that makes all logic levels in this loop totally unpredictable.

Therefore, during the execute phase the ALU result is stored in the shift unit (with the EXEC_WE/ signal). During the following fetch phase, the data is copied from the shift unit into the destination register. The correct destination register is still selected because the instruction register contents will be stable until the END of the fetch phase. 

The shift unit is built with 74HC299 register chips. They have each input at the same pin as an output. so by connecting its 8 pins to the BUS signals, we can load data from the bus and also put data on the bus. And instead of loading from the bus, it can also shift its data (in both directions).

So during exec the BUS is driven by the ALU (FN_OE/ signal connected to the muliplexers of the ALU), and during fetch the BUS is driven by the shift unit (SHFT_OE/ control signal connected to HC299).

Two 74HC574 could have been used here to break the feedback loop, but using the HC299 gives us a shift function for free. It is only a bit awkward to use it, because when activated (with SHFT_SHR/ or SHFT_SHL/ signal) the current ALU output is unused, and the ALU output of the previous instruction will be shifted at the rising clock edge and written to the destination in the fetch phase that follows. Since shift is not frequently used, this seems acceptable. In a shift instruction, another specific bit in the instruction tells if a 1 or 0 will be shifted in (ADD_CIN signal).

Finally, the shifter is connected to the reset (RST/). The reset signal also forces the instruction register to 0x0000 (as mentioned before). This instruction selects  the program counter as destination. It does not matter which value the ALU calculates, because the shifter is now zero, and zero will be written to the PC. So after the reset, the CPU will start executing from address zero.

BUFFER UNIT

The buffer unit has two functions:

A set of multiplexers with tri-state output combines both functions. The output-enable (BUF_OE/) is active when instruction bit S is high (in that case, the memory output will be disabled). Instruction bit M is connected to the select input and selects between data register (OP0-OP15) and address register (A0 - A15). Note that for A1-A7 an address is used that is taken before the final Zpage-multiplexers. This is mainly to simplify the pcb routing.

You will also notice a gate in the A0 signal. For incrementing the PC, we can increment it with the ALU but that will only increment by 1 (when the carry-in is set), while the PC is a word address and must be incremented by 2. By forcing the A0 signal to 1 before incrementing, the result is that the PC is incremented by 2 (knowing that it always contains an even address). The same method can of course be used to increment other address registers by 2. The gate is controlled by displacement bit IR_D1, that is not used for the displacement in this instruction where the operand comes from an address register and not from memory.

PAGE REGISTERS

Each address register has an associated page register. It is written directly from the databus when the control unit activates PAGE_WE/. Its output value is or'ed with the 4-bit displacement value that comes from the instruction register (described in accessing memory). 

At the right side we see a multiplexer that will:

CONTROL

Here we come to the reason of existence of the Kobold K2. Many TTL CPU designs are microcoded and have several EPROMS with microcode (I've seen up to 7) and a lot of control wiring. Getting rid of the microcode was one of the goals of Kobold 2. You see here that the resulting control system is really simple. It's heart, that is shown here, uses only around 4 TTL chips.

We start with the 'Cycle control' at the left side. It is driven by 3 external signals:

The control system will distribute the clock pulse:

In the upper left part there is a multiplexer that modifies four instruction bits during fetch phase. In the fetch phase, we must be sure that the PC (register A0) is connected to the address bus. This is done by this multiplexer. It forces the address-register select signals P0 and P1 (here called: IR_P0E and IR_P1E) and the Zero-page selection to zero. It also enforces a read from memory (MRD/).

In exec phase, when the S bit is 0 it will enable the memory read (MEM_OE/) and when S is 1 it will enable the buffer ouput (BUF_OE/).

Finally the decoder in the upper right corner generates enable signals to connect either the ALU output (FN_OE/ active) or the shift unit (SHFT_OE/ active) to the BUS0-BUS15 lines.

BYTEWISE MEMORY ACCESS 

For reading a word, MRD/ will be low, and address bit A0 will also be low. So the Y0 output of decoder U37B will be active (low) and the other outputs inactive (high). So the "read high byte" buffer is not activated, the NOR gate U35B will output low, so both UBE/ and LBE/ (upper and lower byte enable) will be active (low). Both bytes in the word will be read.

For reading a byte from memory, the A0 address line can be low or high (for reading LSB or MSB). When reading LSB, the instruction acts exactly the same as for reading a word. So a full word will be read. The programmer might, in the destination register, set the upper bits to zero (in a following instruction) if these bits bother him/her. For reading the MSB from memory, the Y2 output of the decoder is activated, so the "read high byte" buffer will put the D8-D15 bits of the databus to the D0-D7 bits. At the same time, since A0 is now high and connected to LBE/, the lower byte of the memory will be disabled, and that is needed because this lower byte now comes from the "read high byte" buffer.

For writing a word to memory, instruction bit IR_A is 1, and MRD/ wil be inactive (high). No decoder outputs will be actve. Both UBE/ and LBE/ (upper and lower byte enable) will be active (low). Both bytes in the word will be written.

For writing a byte to memory, instruction bit IR_A is 0. The programmer should make sure that the byte is in the LSB as well as in the MSB of the word that is written (because he normally will not know if it is written to an even or odd address). Now all there is to do, activate either LBE/ or UBE/ depending on the value of address bit A0. When A0 is low, output Y1 of the decoder is activated (low), and because IR_A is also low, the NOR gate will put high (inactive) on the UBE/ signal. So the upper byte is disabled and only the lower byte gets written.  When A0 is high LBE/ is also high, the lower byte of the memory will be disabled and only the upper byte gets written.

The assumption is, that bytewise access will be used a lot less than word access. Therefore it was accepted that the programmer has a bit more work to do here, instead of using more TTL to implement the bytewise access fully.

SPECIALS

And finally, some odd ends, that nevertheless are needed for operation.

As mentioned before, there is a register-to-register instruction group that does not reference memory. The displacement bits in the instruction are not used in that case. The multiplexer is used to provide a function for these bits when there is no memory access. The four bits are used as follows:

Displacement bit D1, when 1, sets bit A0 of an address register on its way to the buffer unit. Together with the carry-in, this enables incrementing an address register by 2. This was mentioned in the buffer-unit explanation, but is also mentioned here because it is considered an instruction variant (although this multiplexer is not used for this function).

The multiplexer also generates the WR_REG signal, that is 1 when a register must be written, but 0 when it must not be written because something is stored in memory. The WR_REG signal is used by the control section.

For instructions that read memory, the instruction-variant outputs are set to their default value by the multiplexer for S=0. For the store-to-memory functions, the instruction variant is selected, but that does no harm because the variants only affect ALU output, and the ALU output will not be used in a store-to-memory instruction. 

In the execute phase, the 74HC74 flipflop will be set to the state of the carry-out of the adder in the ALU. In the fetch state that follows, bit N0 (the lowest bit of the instruction slot selection) is forced to 1 when the carry was one. The flipflop will be kept in reset when instruction bit M is zero, no branches in that case. And when bit L=1 (data register output is 0) there will also never be a carry because the adder has 0 (from the data registers) on one of its inputs. Isn't it amazing that you can implement conditionals with just a flipflop and a gate ?

It was long... are you still with me ? I don't hear anything. You must be asleep by now...

[ EDIT 2019115 Several changes were made to the CPU. The above description will have to be changed. ]

Discussions

office wrote 03/09/2021 at 12:58 point

One of best description from Internet ! Congratulations ! How Fetch/, Enable/ signals from Control Unit are generated?Do you monitor Bus activity ?

  Are you sure? yes | no