Close
0%
0%

Nits Processor

8-bit TTL technology processor

CedCed
Similar projects worth following
The goal is to build an 8-bit TTL based CPU and learn from the experience.
It is based on the SAP-1, and Ben Eater and James Bates design with many changes.

This project was triggered by the incredible set of videos from Ben Eater and James Bates. Many thanks to both of them. 

I do not pretend to be an expert in computer hardware. As a professional in the software side of things, I wanted to learn more and build myself a working TTL based CPU to improve and try out ideas.

Even if this build is based on both Ben Eater and James Bates design, I wanted to really understand every bit of the design and therefore I have made many changes along the way. I do not pretend they are better, they are mainly driven by the fact of testing things (different choice in chips, different approach, try an learn).

One thing that was really improved is the instruction set. The choice of having 8bit instructions and 256 bytes of memory really made it possible.

  • 1 × 74HCT00 Four 2-input NAND gate
  • 1 × 74HCT02 Four 2-input NOR gate
  • 1 × 74HCT107 Two J-K flip flop with clear
  • 1 × 74HCT138 3 to 8 line decoder
  • 1 × 74HCT245 8 bit bi-directonal bus transceiver with 3 state output

View all 15 components

  • Selecting the right Register IC

    Ced2 days ago 0 comments

    After watching many Youtube videos on Breadboard TTL computers, I noticed that there is often a misundestanding regarding the type of Register TTL chips available and what are their best use cases.

    The most common is the 74HCT173. This one brings everything you need from a register IC:

    • 4 bit register
    • Common clock signal (rising edge)
    • Input enable signal (/E1 and /E2)
    • Output enable signal (/OE, /OE2)
    • 3 state output
    • Asynchronous master reset

    The only drawbacks are that this IC is only 4 bits and the pinout is really weird.

    However, in many breadboards computer, designers use the 74HCT273 without really understanding the differences. The 273 has the following features:

    • 8 bit register
    • Common clock signal (rising edge)
    • Asynchronous master reset

    This IC has no Input Enable signal and no Output enable signal. What it means is that at EACH clock signal, the input is latched and that the output is always on. In other words : The output mimics the exact value of the input as it was on the previous rising edge of the clock.

    No big deal regarding the output as we can use a 74HCT245 to buffer the bus.

    The issue is with the input. Do we want to latch the input value at each rising edge of the clock ? Most of the time NO !  We want an input enable signal. Some would say, it's easy: just use an AND gate between the clock and the input enable and it will work. This is not true and should not be done. Here's why:

    Example 1, the Input Enable is activated a bit before the clock rises. This is basically what we would expect. The input Enable signal activates the clock, the register latches the value on the bus at the time of the rising edge. The AND between the clock and the Input Signal looks like the clock when activated:

    Example 2, the Input Enable signal is not really aligned with the clock, it misses the first rising edge and stays on for the second (note that the duration of the Input Enable is the same as above):

    In that situation, the AND signal provides 2 rising edges. Therefore the register will latch (if fast enough) the information twice at points in time that are not expected. it will miss the first rising edge of the clock, latch on the rising edge of the Input Enable signal (unexpected) and then latch again on the second clock rising edge.

    It is not recommended to apply gates on the clock signal to enable/disable clocks for the microinstructions. The 74HCT273 is not recommended in our use cases.

    However, there is a nice IC that matches better the needs for typical registers: the 74HCT377. It provides the following features:

    • 8 bit register
    • Common clock signal (rising edge)
    • Input Enable signal (/CLKEN)

    It still lacks some nice features of the 173 (master reset, output enable) but it is quite convenient to get 8 bits with Input Enable.

    Here is a good example of the usage of the 377 for our Instruction Register (it doesn't need to be cleared and the output is always on):

  • More about the clock

    Ced11/06/2019 at 21:49 0 comments

    In a TTL type CPU, there is a need for two rising edges of the clock clearly separated:

    • One rising edge to trigger the decode of the microinstruction and set the action signals
    • One rising edge to trigger the action itself (update the register,  etc)

    Most TTL cpus use a single clock with an inverted signal to produce two rising edges per clock cycle (one from the clock signal, one from the inverted clock signal).


    However, this might be playing dangerously as there are chances that one rising edge happens while the other clock signal is still active, creating situations that are very difficult to trace.

    So one alternative would be to clearly separate the two signals with absolutely no overlaping time.

    Here is an example (all screenshots with a 1 Mhz input clock signals from a quartz oscillator):

    In such a situation, a rising edge can never happen at the same time than the other signal is active.

    So how can you build such a signal ? Lets look at this simple circuit and analyze what is going on:

    Lets input a clock on the JK flip-flop (pin 12). The JK is set with two active J and K signals, meaning that it will toggle its exits (Q at pin 3, inverse Q at pin 2) at each clock signal. Note that the 74LS107 triggers on the falling edge.

    Below is the clock signal (pin 12 of the 74LS107, top signal) and the Q output (pin 3 of the 74LS107, bottom signal). 

    At each falling edge, the J-K flip flop toggles. It is therefore a frequency divider by 2. The output is half the frequency of the clock with a 50% duty cycle (ratio between high and low duration). 

    What happens then if we AND the clock and the Q output ?

    Below is the graph of the clock signal (pin 12 of the 74LS107, top signal) and the output of the AND gate (pin 3 of the 74LS08, bottom signal):

    We get the high part of the clock signal but only once out of two.

    If at the same time, we AND the clock and the inverse Q we get the two reciprocating signals.

    Below is the output of both AND gates (pin 3 of the 74LS08, top signal and pin 6 of the 74LS08, bottom signal) :

    With such 2 clock signals, no chances that you will get a rising edge at the same time the other signal is high. The drawback however is that the clock is now half the frequency.

  • Setting / viewing the bus

    Ced11/05/2019 at 14:10 0 comments

    So we've been talking about the bus for some time. But when building a CPU we need two things from the bus:

    • see what is going on (visualize the value currently set on the bus)
    • manualy input a value if needed (for instance when trying to test a register, we need to set a known value on the bus to make sure the register can store it register_in and send it back register_out)

    For this I have built a simple module that manually sets the value of the bus and displays the value of the bus.


    However, there are a few contraints to take into account when building such a module:

    • You need to set a default value for the bus. if a line of the bus is kept hanging (not connected to anything), there are chances that you will get either random values or unexpected behavior. This is called terminating a bus. It is usually done by connecting each line of the bus to a known value (Ground or VCC - 0V or 5V) through a resistor (called pull down or pull up).
    • It is not a good idea to plug LEDs directlly to the bus as they can draw many milliamps from the bus and eventually overload the IC that is active on the bus. To prevent that, a buffer was added (as usual a 74HCT245).
    • We are using standard DIP switches to set a value, but as explained above, the value is actually not directly connected to the bus but with a 3-state buffer and an action signal

    In the end this module is quite simple with only 2 74HCT245, a bunch of LEDs and resistor networks (it is easyer to use a resistor network than to manually plug 8 resistors).

    [Note: do not forget the pull down resistors on the DIP switches otherwise the line would be seen as hanging when the switch is opened]

    [note : the NAND gate is used as an inverter, juste because there was one available near the module]

    Manual setting of the bus balue:

    Displaying the Bus value and bus termination:

    Preview of the Breadboard prototype (right of the photo):

  • Program Counter Register

    Ced11/05/2019 at 13:03 0 comments

    One register is very specific within the CPU: the Program Counter (PC).

    Here is a definition of the Program Counter

    A program counter is a register in a computer processor that contains the address (location) of the instruction being executed at the current time. As each instruction gets fetched, the program counter increases its stored value by 1. After each instruction is fetched, the program counter points to the next instruction in the sequence.

    So basically, if we read carefully the definition above, we understand that:

    • A Program Counter is a register. It has the capability to store the information
    • It has the capability to address the full scope of the memory that can store program (in some cases, program memory can be stored in a separate memory as data memory - otherwise it is shared memory and the PC can address the full scope of the memory). In our situation, it is shared memory and has 8-bit wide address.
    • A Program Counter can be incremented (add 1 to the current value)

    So for the Program Counter, there is need for a new action signal

    • register_inc : this signal enables the automatic increment of the value of the register

    The other action signals are the same as for a regular register:

    • register_clear
    • register_out
    • register_in

    [see log entry on Registers]

    The IC used for our general purpose registers does not provide a way to increment the current value of the register. Increment could be implemented using gates but it is not such an easy task. Hopefully, there is an IC that provides just that:

    • all the capabilities of a standard register (store, clear, input, output)
    • a special signal to increment the value

    However, the existing IC is 4 bits only, therefore we need to chain 2 ICs to provide an 8-bit register.

    This IC is the 74HCT161:

    • 4 bit inputs D0 to D3 (used to load the value of the register)
    • 4 bit output Q0 to Q3
    • 1 memory reset signal (master reset, this is an asynchronous signal in the 74161, synchronous in the 74163)
    • 1 counter enable signal (synchronous, meaning that when active, the counter will be incremented at the next clock
    • 1 clock signal (as usual the rising edge of the clock is used to synchronize the loading or the increment)
    • 1 terminal count signal (this signal is used to chain 2 IC, when the 4 bit counter reaches the maximum value 1111, the TC signal is set to signal the next chip to increment)
    • 1 parrallel in signal (this signal is used to load the value from the parrallel input)

    When chaining two 74161, the TC signal is used to enable the counter of the next chip.

    As for the general purpose register, the 74HCT245 is used as the 3-state output buffer.

    As always, for learning purposes, the action signal are all set to active high and may need an inverter.

  • Registers - so many choices

    Ced11/05/2019 at 11:05 0 comments

    CPUs are mainly temporary storage stuff with routing capabilites. To perform operations on data there is first the need to locally store this data (coming from memory, ROM or IOs) within the CPU.

    There are even many types of registers in a CPU:

    • general purpose registers (used to manipulate data)
    • intruction registers (storing the instruction that is going to be executed)
    • program counter (a special kind of counting register used to store at which step the program is currently positionned)
    • address registers (pointers to memory)
    • stack registers (also a pointer to memory but used for specific stack instructions)
    • I/O registers used to communicate with external devices
    • etc

    Registers can vary in width depending on the CPU (from 8 bits to 128 bits). In our example they will all be 8-bit wide as we only have 8-bit data and 8-bit address capability.

    In the following we only talk about the general purpose registers (couting registers will be discussed later).

    So what are the functions of a general purpose register in the context of our CPU:

    • load information from the bus when instructed to
    • store the information until an action is performed or power is turned off
    • display the information using LEDs
    • 'publish' the stored information onto the bus when instructed to
    • reset the information (or clear). This means putting all the bits to 0.

    Therefore we can see there is the need for 3 signals to instruct the register what to do:

    • register_in : load the information from the bus
    • register_out : publish the information to the bus
    • register_clear : clear the content of the register

    However, something is key for a register : it's the timing of the loading function. Its has to be performed in a snapshot. This is why registers input the value from the bus on the rising edge of the clock. Therefore there is the need for 2 signals when inputing the values from the bus:

    • the action signal register_in : the signal that informs the registers that it is going to load and store the information available at its input (usually the bus)
    • the clock signal of wich we only use the rising edge to define the precise moment at witch the information is taken from the bus

    There are many ICs in the 74xx series that provide some of these features (so many choices).

    In Ben's videos, he uses the 74LS173 (4 bit register with output enable signal, input enable signal, clock and master reset signal)

    [Update : See my later post on register IC]

    In practice we are not going to use the 3 state output and Output Enable capability of the 173 because we want to display the value of the register at all times on the LEDS. Therefore, the output is kept alway on. A separate chip is ised to provide the output buffering.

    The 74HCT245 IC provides juste that : an octal buffer with 3 state output (it actually is bi-directional but we will use only one direction in this context). Note there is an existing single direction octal buffer, the 74HCT241 however the pinout is not as easy and in order to keep only one reference, we will use only the 245.

    This chip offers 3 state output. This means that it can be seen as:

    • output is activated and the value of the bit is 0 (0V)
    • output is activated and the value of the bit is 1 (5V)
    • output is deactivated and the chip is considered as not connected

    So the outcome is that we need only 3 chips and a bunch of leds and resistors to implement a general purpose register.

    Note that the diagram above shows 2 more elements not mentionned above : the link between the register and the ALU (out of topic for now) and some inverters on the action lines as the chips expect active low signals (this can be optimized later on, but for learning purposes it is better to show uniform active high action signals).

    Preview of the prototype (using the original 74LS173 IC):

  • All about the clock module

    Ced11/05/2019 at 09:28 0 comments

    The clock module is actually more complex than one would expect.

    The main features are:

    • Provide a clean clock signal (square wave), an inverse clock signal (square wave) and a pulse signal (on rising edge of the clock signal)
    • Offer variable clock speed (between 0,75Hz to 500Hz) in order to see what is happening
    • Offer manual clock to ensure a step by step analysis
    • Offer a startup delay (2s) to block clock signal and send master reset signal

    The clock module has two switches:

    • Manual  / Automatic clock selector (choose between automatic pulse with variable speed and a manuel push button)
    • Clock pushbutton

    It has two input signals:

    • HALT signal will stop the clock signal (either in manual or automatic mode).
    • PROG signal will stop the clock signal (when programming the RAM, avoid having the CPU continuing it's job)

    It has 4 output signals:

    • CLK : the clock signal. A square wave. Frequency can vary
    • INVERSE CLK : the inverse of the clock signal.
    • PULSE : a pulse signal derived from the CLK signal
    • MASTER_RESET : this signal sends a global reset to all computer parts at startup to make sure the system is ready to run

    It is mainly built using 555 timers and some logic.

    • A 555 timer in Astable mode will provide the automatic clock. The potentiometer changes the time value.
      • Minimum value (when potentiometer is at 0ohm) : Period = 0,693 x (1kohm + 2 x 1kohm) x 1uF = 0,693 x (1000 + 2000) x 0,000 001 = 0,002079.s That is a frequency of 481Hz
      • Maximum value (when potentiometer is at 1Mohm) : Period = 0,693 x (1kohm + 2 x 1Mohm) x 1uF = 0,693 x (1000 + 2 000 000) x 0,000 001 = 1,38s. That is a frequency of 0,72 Hz
    • A 555 timer is monostable mode will provide the manual switch debouncing (to prevent bounce effect when switch is activated). When switching it will turn on the 555 time for a pre-defined period and it will turn off again, only once. The timer will stay on for a period defined by : period = 1,1 x 1Mohm x 1uF = 1,1 x 1 000 000 x 0,000 001 = 1,1s
    • A 555 timer will provide the startup delay. When power is turned on, 555 is immediately set to on, until the capacitor is charged and then it turns off permanently. Period is defined using the same rule as the monostable above. Delay is 1s.

    A few elements of logic are used to provide a clean signal and a debounced switch between the manual and automatic:

    • Debouncing is performed using an SR latch with two NOR gates.
    • Signal is output only if the following is TRUE : NOT (startup_wait |  PROG | HALT)
    • INVERTED CLOCK signal is provided using an inverter
    • Pulse signal is provided using a RC with a time constant of period = 0,01uF x 1kOhm = 0,000 000 01 x 1000 = 0,000 01 s. Warning : the RC is positionned after a second inverter in order to buffer its effect and prevent poluting the clock signal. Also the double inverter gates provide a small delay compared to the actual rising edge of the clock signal.

    Other chips used in this clock module:

    • 74HCT02: provides four 2-input NOR gates
    • 74HCT08: provides four 2-input AND gates
    • 74HCT32: provdes four 2-input OR gates
    • 74HCT04: provides six NOT gates (inverters)

    Finally a few leds are positonned to show the actual status of each element:

    • orange led show clock signal (automatic, manual, output)
    • red led show the startup wait status
    • blue led show action signals (HALT, PROG)
    • green led show inverted clock signal

    View of the prototype:

  • Design Principles

    Ced10/31/2019 at 16:49 0 comments

    Here are a few design principles:

    • The main objective is the learning experience. Therefore optimisation is not the goal neither in component count nor in performance. Anyway when building a TTL base computer, performance cannot be the goal.
    • All components are 74LS or 74HCT series bought new
    • All is positive logic.
    • Leds are put eveywhere the undestanding of the inner workings is required (bus, status, actions signals, register values, etc). Leds are the better and easy way to display signals. Each led is protected by a 330ohm resistor (5v power supply, 1,4V drop at the led. Therefore 3,6V at the led level. With a 330ohm resistor it allows for a 10mA current)
    • When needed pullup or pulldown resistors are 1kohm
    • Each IC as a 0,1uF capacitor close to it for decoupling and power reserve
    • Each power line has a 100uF capacitor as a power reserve

  • General Architecture

    Ced10/31/2019 at 16:41 0 comments

    The goal is to create a viable CPU with its own language able to run simple programs.

    The main features of this CPU are:

    • 8 bit bus (only one bus)
    • 8 bit general purpose A register
    • 8 bit general purpose B register
    • 8 bit Program Counter register
    • 8 bit Instruction register
    • 8 bit memory address register
    • 256 bytes non volatile static RAM
    • Led visualisation at each level (registers, bus, status, etc)
    • Dip switch manual entry (bus value, memory adrress and data programming)
    • 4 digit 7 segment led display (signed / unsigned values)
    • ALU with add / substract functions and the capability to evolve to more features
    • Flag register with Carry Flag, Zero Flag (and soon other flags)
    • EEPROM based instruction decoder with up to 24 action signals
    • variable speed and step by step clock

    The general architecture will evolve with updates to the project. However here are the basic elements:

    The following modules will be detailed (order may vary):

    • Bus module with bus value display and manual setting
    • A & B registers (General purpose registers)
    • Program Counter
    • Memory including Memory Address register, Manual RAM loader, Ram out driver
    • ALU with it's basic add/substract function, Flags register, R register (ALU result register)
    • Instruction register
    • Instruction decoder, stepper
    • Input / Output, 7 segment display module

    And of course, in order to understand the inner mechanics of the CPU:

    • Micro instructions (action signals)
    • Steps description
    • Macro instruction

View all 8 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates