Nits Processor

8-bit TTL technology processor

Public Chat
Similar projects worth following
Nits Processor V1
The goal is to build an 8-bit TTL based CPU and learn from the experience.
It is based on the SAP-1, Ben Eater, James Bates and James Sharman's design with many changes and tweeks.

Nits Processor V2
V2 is an improved version of the Nits Processor V1 with expanded ALU, 16-bit address space, more registers, interrupt manager and rich instruction set.

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.

Once the Nits Processor was up and running, I started working on an improved V2.

These log posts are related to Nits V2:

What next?

Improved Address Register

Prototype of the new Address Register

First PCBs

Testing the GPAR using an Arduino

Measuring propagation delay and look-ahead signal

New PCBs for the Address Register

and more to come...

These log posts are related to Nits V1:

General Architecture

Design Principles

The clock Module (Clock part 1)

All about registers (Registers part 1)

Program Counter (Registers part 2)

Setting, Terminating, Displaying the bus

More about the clock (Clock part 2)

Selecting the right register IC (Registers part 3)

Micro Instructions

Decoder register and timing issues (Register part 4)

Switches and debouncing

It's alive

Assembly compiler and memory loader

  • 1 × 74HCT00 Four 2-input NAND gate
  • 1 × 74HCT02 Four 2-input NOR gate
  • 1 × 74HCT125 Four 3-state 1-input bus driver with independant activation signal
  • 1 × 74HCT138 3 to 8 line decoder
  • 1 × 74HCT151 8-input mutliplexer

View all 23 components

  • New PCBs for the Address Register

    Ced11/30/2020 at 18:40 0 comments

    I finally received, checked, solder and tested the new PCBs for the Address Register.

    I built of such registers, one will be the Program Counter and one will be the Stack Pointer and plugged them to the backplane.

    Here is a picture of the two PCB plugged into the backplane with the control lines connected to the arduino (blue cables) for testing purposes. The final Bits CPU V2 will have 2 more such modules for index address registers.

    For more information on the design of the address register, see Testing the Address Register using Arduino.

    The next PCBs are already ordered for the Data registers...

  • Measuring propagation delay and look-ahead signal

    Ced10/24/2020 at 17:34 0 comments

    Still working with the GPAR, the General Purpose Address Register. This design includes 4 chained 74HCT193 up/down counters. Each one handles 4 bits and the Adress Register can handle 16-bits in total.

    For some operations, the four 193 will work in parrallel, such as the RESET function, or the parrallel load.

    But, when using the INCrement or DECrement function, each one has to wait until the previous one is done computing to see if it needs, in turn, to increment or decrement. There is therefore an extended propagation delay for these functions. 

    Using a 100Mhz digital Logic Analyzer, we are going to measure the delay when using the increment or decrement function. Note that this logic analyser can only sample the signal at 100Mhz, therefore the maximum speed is one sample per 10ns. So the results are not very precise but it can illustrate what is going on.

    For this, we plugged the GPAR to a 4Mhz clock, set the DEC function to permanent activation, therefore, the GPAR is decrementing at the speed of the clock, 4 million times per second.

    Schematic of the GPAR

    The DEC function goes first through a NAND (74HCT00) gate to synchronize with the clock then to the CpDw pin of the first 74HCT193, then each 193 is chained using the special purpose output TcUp and TcDw.

    Step 1 - Delay at the NAND gate

    Lets look first at the propagation delay of the 74HCT00: the spec sheet says typical t=10ns, max t=25ns.

    So lets measure the timing diffence between the clock and the output of the NAND gate. First line is the clock, second line is the NAND out signal.

    Here the measure is 10ns (one sample of my analyzer). It's in line with the specs.

    Step 2 - Delay to decrement the first 193

    So now we measure the time it takes to decrement the value of the first counter. We select a specific moment, when both the first bit (D0) and the last bit (D3) of the counter switch (the counter decrements from 0b0000 to 0b1111)

     The propagation delay is measured at 30ns from the clock signal, so lets say 20ns from the NAND out signal for the first bit and 40ns for the last one, this is consistent with the specifications of the 74HCT193:

    Step 3 - Delay to decrement all counters

    For this final measure, we consider the worst case scenario where all counters need to decrement. We measure the difference between the clock, the first bit of the first counter (D0) and the last bit of the last counter (D15):

    We can see the same propagation delay for the first bit D0, but considerably more for the last bit D15:
    • Delay for the first bit: 30ns minus the NAND 10ns = 20ns
    • Delay for the last bit : 60ns minus the NAND 10ns = 60ns

    However, this is strange because how could decrement over 4 chained counters take only 40ns (60ns delay for the last D15 minus 20ns delay for the first D0) when one counter by itself takes 20ns? 

    The great trick of the 74HCT193

    Well this great IC has a trick, it doesn't compute the result of the counting to consider sending a carry signal or a borrow signal to its neighbour. It already know before the computation that it will not be able to perform the compute by itself and sends the signal immediatly. This is called the look-ahead carry or borrow. Basically:

    • If the chip value is 0b0000 and we want to decrement, it can send the borrow signal immediately
    • If the chip value is 0b1111 and we want to increment, it can send the carry signal immediately

    Here is a clear measurement of this features (remember we are decrementing so it is a borrow signal). Look at the area where all the values D0 to D3 are at 0, we can see that the borrow signal mimics the decrement signal. For all the other values of D0-D3, the borrow signal stays high.

  • Testing the Address Register using Arduino

    Ced10/11/2020 at 18:10 0 comments

    While still working on updating the PCBs and fixing some bugs for the build, I started wondering how to massively test the modules (breadboard or pcb) and of course the Arduino came handy.

    The General Purpose Address Register (GPAR) is described in this blog post. It provides a 16-bit wide address register, reset, increment and decrement functions and can publish its values to both the Adress Bus and the Data Bus.

    To test the features we will need to check each functions:

    • Capability to move a 16 bit value to the register using the Data Bus (The Data Bus is only 8-bit wide, therefore we need two steps, moving the MSB-Most Significant Byte and then the LSB-Less Significant Byte)
    • Capability to retrieve a 16 bit value from the register using the Data Bus (same)
    • Capability to increment the value stored in the register
    • Capability to decrement the value stored in the register
    • Reset

    The program must also make sur that the cabling is ok (either within the prototype or between the arduino and the prototype). For this we will light up all the LEDs slowly one by one in a specific order for a visual check.

    The program does the following:

    • Check each action signal by lighting the appropriate LED, this will enable checking the wiring between the arduino and the prototype and the LED capability (8 signals total)
    • Check each register bit by uploading the appropriate value (0, 1, 2, 4, 8, etc) to the register. Each time, the given led should light up. This will again ensure the cabling between the arduino and the prototype is correct and that the inner workings of the register are ok
    • Generate random number between 0 and 65535 and perform the following (many times)
      • Move the value to the register (2 steps)
      • Retrieve the value from the register and compare it (2 steps, retrieved value should be identical)
      • perform an increment (1 step)
      • Retrieve the value from the register and compare it with the locally incremented value(2 steps, retrieved value should be identical)
      • Perform a decrement (1 step)
      • Retrieve the value from the register and compare it (2 steps, retrieved value should be identical to original value)
      • Perform a Reset (1 step) 
      • Retrieve the value from the register and compare it to 0 (2 steps)

    The artduino will stop if an inconsistency between what is retrieved and what is expected is found.

    GPAR being tested by the Arduino and measured

    This photo shows:

    • The GPAR prototype on two breadboards using mainly 74xx193 and 74xx245
    • the arduino mega used to perform the tests
    • A logic analyser to measure the frequencies

    The outcome is very positive from the features perspective : everything performs as expected.

    However, it must be said that the arduino is quite slow and that the maximum test frequency is 9Khz, very far from the target in the Mhz area.

    Here is a full cycle of tests:

    • Line 1 is the clock
    • Line 2 and 3 are the MSB_IN and LSB_IN signals enabling the move of 2 bytes as 1 16-bit value into the register
    • Line 3 and 4 are MSB_OUT and LSB_OUT (active low) enabling the retrieval of the 16-bit value stored in the register as 2 bytes
    • Line 5 is the increment signal
    • Line 6 is the decrement signal
    • The reset signal is not displayed

    Unexpected issue

    The address register is supposed to strictly work between the address x0000 and xFFFF, therefore the is no overflow detection. Therefore when the arduino program generated a value such as xFFFF, it was then incremented to become x0000 (no overflow), and then decremented and it stayed at x0000. Of course, the arduino flagged this as an error. The program was fixed to ignore this issue and consider the value ok.

  • First PCBs

    Ced06/07/2020 at 11:46 3 comments

    The first PCB I wanted to create was dedicated to displaying all the Buses and provide the capability to publish a value to the Data Bus. A helpfull debugging tool.

    This module provides the following:

    • Display the 8-bit X Bus
    • Display the 8-bit Y Bus
    • Display the 16-bit Address Bus
    • Display the 8-bit Data bus
    • Publish a manual value, set using dip switches to the 8-bit Data bus

    In order to minimize impact on the buses when plugging the module all the LEDs are driven by a 74LS245 bus driver.

    The PCB is dual sided, ordered from a well known provider.

    The switch enables the publishing of the Data bus value. No switch debouncing is needed on this test board. It works perfectly.

    The second PCB, also for test purposes is a simple 41612 64  pin connector facilitator. It enables easy access to any pin of the connector to use a dupont-cable.

    I built 2 of thoses, on for the female 41612 connector (seen here), one for the male version (just solder a male connector on the right side of the PCB instead) in order to also test the backplane.

    Here is a preview of the test backplane (connectors not installed). It provide 5 41612 connectors, power supply, decoupling caps, and direct access to some buses (to be used by the bus display above).

    Finally, my big error in design, I built a PCB for the final version of the clock module, quite a complex PCB for my level of expertise and I messed up one chip (used a NOR instead of an OR gate and the pinouts are not compatible). So this is the partially built version. I stopped when I found the error.

    It was supposed to have an 41612 connector, get power from the baclplane and provide reset and clock to the backplane. I will therefore need to design a second version.

    Until the redesign, I will hack this one to make sur the updated design fixes the errors.

  • Prototype of the new Address Register

    Ced04/15/2020 at 08:47 0 comments

    This post is a followup of the Improved Address Register post.

    We have identified 4 asynchronous actions:

    • Publish MSB to data bus: -msb-out, asynchrounous
    • Publish LSB to data bus : -lsb-out, asynchrounous
    • Publish value to Adress bus :  -add-out, asynchrounous
    • Clear value (reset) : -clear,  asynchrounous

    and 4 synchronous actions:

    • load MSB from data bus : -msb-in, on clock rising edge
    • load LSB from data bus : -lsb-in, on clock rising edge
    • Increment value : -inc, on clock falling edge (see note)
    • decrement value : -dec, on clock falling edge (see note)

    However, the 74HCT193 does not provide a clock entry, therefore it has to be built with an NAND gate to synchronise the action signal and the clock. So when activating the INC action, NANDed with the clock, will provide a HIGH-LOW-HIGH transition synchronous with the clock.

    NOTE : the 74HCT193 has a strange behaviour in a way : it needs the clock inputs to be HIGH to count, but it counts on the rising edge. So, in order for intance to have a count UP you will need :

    • CPDw to be HIGH
    • CPUp which was HIGH to first go LOW and then go HIGH.

    This means that the couting will not take place on the clock rising edge but on the clock falling edge after the NAND gate.

    The 4 NAND gates provides 4 clock-synchronous action signals to control the 74HCT193. We need 4 of these to provide 16 bits. The increment and decrement counters are daisy chained to provide the counting capability :

    The reset pin (Mr in the diagram) is just the same signal for all four chips.

    The Pl (parallel load) signal is however distinct because we need to be able to load either the lower 8 bits (LSB) or upper 8 bits (MSB).

    Therefore the output of the NAND gate for the signal REGISTER_X_MSB_IN is routed to the Pl pin of the two left chips and the output of the NAND gate for the signal REGISTER_X_LSB_IN is routed to the Pl pin of the two right chips.

    Finally, for the output, we need to :

    - publish the full address (16 bits) to the address bus. This is done using two 74HCT245 bus drivers with only one publish signal connected to both REGISTER_X_ADD_OUT (active low):

    - publish the upper 8 bits to the data bus. This is done using one 74HCT245 bus driver driven by the REGISTER_X_MSB_OUT (active low) signal

    - publish the lower 8 bits to the data bus. This is done using one 74HCT245 bus driver driven by the REGISTER_X_LSB_OUT (active low) signal

    Overall, there are 9 chips to perform all these features:

    In this diagram we added:

    • 2 LED bargraphs to display the current value of the register
    • 8 pullup/pulldown resistors to ensure that even if not connected the actions signals do not perform any action
    • 8 signal LEDs to display the action sigals

    Here is the prototype using breadboards. It's a bit messy because the 74HCT193 have a very weird pinout.

    The prototype has been tested and is working perfectly. Max tested frequency is 4 Mhz.

    The next step is to build a PCB for this Register and connect it to a bus backplane. We will need 4 of these.

  • Improved Address Registers

    Ced01/20/2020 at 15:28 0 comments

    Our current CPU has many limitations, including on the register level. This post will look at how to improve the registers that handle memory or output addresses.

    First, let's look at the current register capabilities:

    • there are basically only two memory address registers : the Program Counter (PC) and the Memory Address Register MAR)
    • these registers are 8-bit registers, therefore they can only address 256 bytes of memory or IO
    • Only one provides the increment capability (the Program Counter) however it cannot directly address the memory and has to go through the MAR (memory address register)
    • None can decrement
    • There is no stack pointer
    • There is no index register

    So lets try to design a single General Purpose Address Register (GPAR) that would provide:

    • 16 bits in order to address 64k words of memory space
    • increment and decrement capability in order to serve also as PC (Program Counter) and SP (Stack Pointer) without the need of the ALU
    • Read and Write capability from the databus which is only 8-bit, in order to access both MSB (Most Significant Byte, the byte of higher value of the 16-bits) and LSB (Least Significant Byte, the byte of lower value of the 16-bit) 
    • Write capability to the 16-bit address bus

    Now what type of instruction these registers should be able to handle :

    • LD PC-MSB, D2 : meanind load the MSB of the PC address register with the content of register D2
    • LD D2, IX-LSB : meaning load D2 with the content of the LSB of the index pointer IX
    • LD IX-LSB, IY-MSB : meaning load the LSB part of ix with the content of the MCB part of IY
    • INC IX

    This shows that at any given time, it must be possible to output any of the content of any part of the register ***AND*** input any other part of any other register. 

    Possibly even within the same register:

    • LD IX-MSB, IX-LSB: meaning loar the the MSB part of IX with the LSB value of IX

    We therefore need to separate the output action functions from the input action functions.

    For output and reset:

    • Publish MSB to data bus: -msb-out, asynchrounous
    • Publish LSB to data bus : -lsb-out, asynchrounous
    • Publish value to Adress bus :  -add-out, asynchrounous
    • Clear value : -clear,  asynchrounous

    For input and other:

    • load MSB from data bus : -msb-in, on clock rising edge
    • load LSB from data bus : -lsb-in, on clock rising edge
    • Increment value : -inc, on clock rising edge
    • decrement value : -dec, on clock rising edge

    In the end we need:

    • 3 bits to select the output register (value 0b000 serves as not selected)
    • 2 bits to select the output/reset function (MSB, LSB, address bus or reset)
    • 3 bits to select the input register (value 0b000 servers as not selected)
    • 2 bits to select the input/other function (input MSB, input LSB, inc, dec)

    With a total of 10 bits, we can perform any type of function on the General Purpose Address Registers.

    Here is the naming convention for the register select bits:

    • None: code 0b000
    • Program Counter : PC, code 0b001
    • Stack Pointer : SP, code 0b010
    • Index Pointer 1 : IX, code 0b011
    • Index Pointer 2 : IY, code 0b100

    Here is the convention for the output action (all are asynchronous):

    • Publish MSB to data bus: -msb-out, code 0b00
    • Publish LSB to data bus: -lsb-out, code 0b01
    • Publish value to Adress bus :  -add-out, code 0b10
    • Clear value : -clear,  code 0b11

    Here is the convention for the input/other functions (all are on the clock rising edge):

    • load MSB from data bus: -msb-in, code 0b00
    • load LSB from data bus: -lsb-in, code 0b01
    • Increment value : -inc, code 0b10
    • decrement value : -dec, code 0b11

    Lets now review what the 10 bits would be for the instructions listed above:

    • LD PC-MSB, D2
      • select output register NONE: 0b000 (D2 is not consider as we are focusing on the GPAR only)
      • select output function X : 0b0
      • select input register  PC :  0b001
      • select input function -msb-in: 0b00
      • Result is : 0b000000100
    • LD D2, IX-LSB
      • select output register IX: 0b011
      • select output function -lsb-out: 0b0
      • select input register  NONE :  0b000
      • select input function X: 0b00
      • Result...
    Read more »

  • What next?

    Ced01/14/2020 at 10:23 0 comments

    The first version of the Nits Processor is now finished. It is turing complete with a very basic set of instructions, it is possible to upload a program and run it, it can display a result on the 7-segment display.

    Here are a few photos.

    The instruction decoder (3 EEPROMS for 17 signals and a set of gates to decode the flags):

    The memory (256 bytes stored in Non Volatile Static RAM, with the Address Register, the memory value display). 

    The two flat cables come from the memory loader module (Arduino based). One is the Address bus and one is the data bus. They are used in PROG mode to upload the program to the memory.

    It is now time to think about the next steps. What are the current limitations and how can it be improved.

    Improvements can be of 3 sorts:

    • Improve the instrution set
    • Improve the architecture
    • Improve the build

    Improve the instruction set

    The instruction set is very limited and really needs to be expanded to provide usable capabilities. For instance:

    • Add basic logic functions (And, Or, Not, Exclusive or)
    • Add shift functions (Shift, Shift Circular, Shift with carry)
    • Add compare functions (zero, equal, greater than)
    • Add Push and Pop capability (requires a dedicated stack pointer register)
    • Add Call and Return
    • Add bit management (test flags, store flags, bit operations)

    Improve the architecture

    With only 2 registers, the lack of stack pointer and only 256 bytes of memory for both data and program, the current archietcture can really be improved:

    • Expand address bus to 16 bit (hence 64 Kbytes of memory). However this requires many changes because now the address bus can be double the size of the databus and ALU creating a challenge when computing addresses
    • Expand the number of registers, at least to 4 General Purpuse Registers
    • Separate memory from Input-Output. This will provide double the addressing capability
    • Add a way to interact with the system, for instance with a proper serial interface
    • add a ROM with basic functions including initial setup and serial management
    • add a stack pointer and index registers for points in memory
    • add interupt management (is required for serial interface)
    • expand the ALU capabilities

    Improve the buid

    In its current form (build on breadboards), the CPU works well at 1 Mhz, however, when putting a 4 Mhz oscilator, it breaks. And this is normal considering the capacitance of the breadboard and how the cables are set up.

    It would therefore be interresting to improve on the design with:

    • a PCB backplane to handle all the busses and the clocks with proper connectors (I'm investigating the 96pint DIN41612 connector)
    • PCB modules for very stable elements such as registers, clock
    • Keep the breadboards for test modules and modules that keep beeing improved (ALU, IO)
    • improve on test modules

  • Assembly compiler and memory loader

    Ced12/30/2019 at 18:12 0 comments

    Two new pieces were added to the system :

    • A simple software to compile the assembly code into binary
    • An arduino based RAM loader

    Indeed since the beginning of the project I had to manually write the binary code and upload it using dip switches and this is very error prone and it takes forever.

    My assembly compiler is very basic, written in PHP (just because it's the langage I'm more comfortable with). The input is an assembly file such as (custom format):

    ; Brute force find three consecutive integers whose sum is equal to 204
    var x1
    var x2
    var x3
    var result
    const expected 204
    	LD A, 0
    	LD [x1], A
    	; compute the 3 values and total
    	LD A, [x1]
    	LD B, 1
    	ADD A
    	OUT A
    	LD [x1], A

    It handles:

    • comments (anything that follows the semicolon)
    • var definitions (only unsigned bytes)
    • constant definition
    • labels 

    And it produces a binary file and a human readable processed file very useful to debug both the software and the hardware:

    VAR x1 at address 11111111
    VAR x2 at address 11111110
    VAR x3 at address 11111101
    VAR result at address 11111100
    CONST expected = 11001100
    Label init
      00000000  LD A, 0x0                       00100110 00000000
      00000010  LD [x1], A                      01001000 11111111
    Label compute_x
      00000100  LD A, [x1]                      00100101 11111111
      00000110  OUT A                           00011000
      00000111  LD B, 0x1                       00101110 00000001

     Each line of compiled code contains

    • the start address of the  code
    • the assembly code
    • the binary code once compiled (one or two bytes depending on the operand)

    Once the binary file is obtained, it was required to load the code into the memory. For this I used an Arduino nano connected to a 74HC595 in a way very close to Ben Eater's EEPROM programmer.

    The Arduino will take over the Address and Data bus of the memory by activating the PROG mode, this basically disconects the memory from the Bus through 75HCT245 chips. Once the memory is isolated, the arduino will go through all the needed address using the 75HC595 (a shift register) and upload the data.

    Note : 

    • a dedicated signal is used to write the value on the bus to memory
    • Lines A0 to A2 of the arduino are set to digital
    • Yes it would be possible to connect directly all 8 lines of Data and 8 lines of Address to the arduino but I wanted to try out the shift register for the time I will have more lines.

    Overall everything works and it a good way to finish 2019. I hope 2020 will bring new features such as:

    • PCB backplane with a 5A power supply
    • Stack Pointer register with associated Push and Pop
    • new ALU with compare, logic operations, etc

  • It's alive

    Ced12/17/2019 at 11:06 0 comments

    Happy to say that the Nits CPU is now alive and Turing complete. The instruction set is quite small but it runs at both slow (300 Hz) and fast (1 Mhz) speed.

    The instruction set includes:

    • NOP : do nothing
    • HALT : halt the computer, at this stage, only a manual reset can restart it
    • ADD : add content of register A and register B and store the result in register A
    • SUB : substract the value stored in register B from the value stored in register A and store the result in register A
    • OUT A : output the content of register A as a decimal unsigned value on the display
    • OUT B : output the content of register B as a decimal unsigned value on the display
    • LD A, B : copy the content of register B in register A
    • LD A,  x : copy the content of the memory at address x in register A
    • LD A, i: copy the value i in register A
    • LD B, A : copy the content of register A in register B
    • LD B,  x : copy the content of the memory at address x in register B
    • LD B, i: copy the value i in register B
    • LD x, A : copy the content of register A at memory address x
    • LD x, B : copy the content of register B at memory address x
    • JMP x : unconditionnal jump at address x
    • JMPC x : jump at address x if carry flag is set
    • JMPZ x : jump at address x if zero flag is set

    It is now time to improve on it.

  • Switches and debouncing

    Ced12/03/2019 at 16:20 0 comments

    Now that that first version of my CPU is running, it is time to fix some issues. One of them is manual switches and debouncing.

    I will not write one more article about debouncing as all this is very well detailed in the great article by Elliot Williams Debounce your noisy buttons.

    In this first version of my CPU I ended up with the following switches

    • Bus Publish : This pushbutton published the value of a dip switch to the bus
    • Master Reset : This pushbuttons resets the computer
    • Memory manual Write : This pushbutton writes the data set on the data dip switch at the memory address set on the address dip switch [PRO mode only]
    • PROG/BUS selector : this is a two way selector used to program the memory (PROG mode) or to use the memory through the regular bus and Memory Address Register (BUS mode)
    • MANUAL / AUTO clock selector : this is a two way selector used to select between the automatic clock (slow or fast) or the manual pulse pushbutton
    • SLOW / FAST clock selector : this is a two way selector to swicth between the 555 base slow clock (between 0,5Hz and 300 Hz) and the fast cristal oscillator based clock (1 Mhz) [valid for Auto clock mode only]
    • MANUAL / AUTO  uCode selector : this is a two way selector disabling the microcode decoder in order to use manual action signals (debugging purposes only)

    3 are pushbuttons and 4 are two way selectors (slide buttons).

    In is articule, Elliot explains how to debounce using an RC (Resistor/Capacitor) circuit and a schmitt trigger inverter. The inverter can be found in the 74HCT14 IC.

    Here is an example of a complete debouncer. Note that the signal is inverted : when pressing the button, the signal ACTION_MANUAL_BUS goes low.

    Here a short description of how it works :

    When the switch is open, the capacitor is loaded through the 10k + 10k resistors and reaches VCC. The output signal is then 0V (inverted input)

    When the swicth is pressed, the capacitor is unloaded through the 10k resistor, it will therefore take 1 ms to reach 1/3 VCC and trigger the change of state of the inverter

    When the switch is released, the capacitor is loaded again, it will reach 2/3 VCC in 2ms and trigger the change of state of the inverter.

    For the slide swicthes (type is break before make), we need to prevent any oscilation between the two states and prevent an unknown state. The best solution here is a simple SR latch.

    An SR latch (in this cas an SR NOT latch as it is built using 2 NOR gates) can only be in 1 of 2 states. 

    When moving the switch from on position to the other, what may happen is the following:

    • bounce off the first state
    • stay undefined (in between the two states)
    • bounce on the second state

    In such a situation, the SR latch will prevent any oscillation following the reasoning:

    • When the switch bounces off, the latch will stay in the same status (set or reset) 
    • when the swicth is undefined, the latch will stay at the same status
    • the first time the witch touches the other positon the latch will toggle but even if the switch bounces it will stay in that second position.

    So in the end, I have built a dedicated breadboard with all the swicthes, RC circuits and IC to debounce all and have perfectly clean manual signals.

View all 20 project logs

Enjoy this project?



ATmel91 wrote 06/11/2020 at 05:31 point

Holy crap nice! Good luck with your project.

  Are you sure? yes | no

Ced wrote 06/11/2020 at 12:50 point

Thanks. Will keep updating and sharing.

  Are you sure? yes | no

J. Peterson wrote 06/07/2020 at 07:12 point

Wow - 4mhz on a breadboard computer is impressive. I would have expected noise/crosstalk issues to cause problems at that speed.

  Are you sure? yes | no

Ced wrote 06/11/2020 at 12:52 point

I actually had issues with cheap breadboards, but with the good ones and good cables, it seems to be ok. Also, I have a ton of decoupling caps and 100uF reservoir power supply caps.

  Are you sure? yes | no

Ced wrote 10/15/2020 at 09:48 point

Just one more though. The oscilator is at 4Mhz, but in practice, to create a 4-phase clock it divides the frequency by 2. So in practice we are talking a real 2Mhz speed.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

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