Friday, November 1, 2013

ASAP-3 - Almost Simple As Possible Computer 3

The ASAP-3 is a computer/microprocessor made of discrete TTL logic chips.  It is based upon the SAP-1 (and 2 & 3) computer as described in Digital Computer Electronics by Albert Malvino.  It is an 8-bit computer and uses 55 chips to carry out its function.

Picture album of the assembly of the circuit board.

Picture album of the schematic diagrams.

A .rar file containing the schematics, ROM binaries, source code for the calculator program and an explanation of the instruction set.

The schematic was made using  Proteus Design Suite 8.0.  A demonstration version can be downloaded from the website and can be used to view the schematic file and run a simulation of the hardware.


Video Demonstration

Calculator program with a LED output:

Calculator with a LCD output:

Running with a slow clock and probing the instruction register:


Design Goals

I have been fascinated by projects like Magic-1, Big Mess o' Wires 1, The Duo Series and MyCPU but wanted to build something on my own.  While the schematics are available for several homebrew computers I didn't have enough knowledge to take those and start building.  My research lead me to the SAP-1 design.  Playing around with digital circuit simulations I was able to start making something I actually could understand.  Eventually I decided on building a 4-function calculator with a keypad input and 7-segment output.  The design was simple enough so that it felt like it could be accomplished on my own while giving a tangible result that was more than just some flashing LEDs.

Simple ≠ least amount of chips.  The display could probably be made with a multiplexing type array which would take much less PCB space.  The software side would be more complicated, and my simulation doesn't have animation faster that about 20 fps.  However, with all I have learned about programming it would probably be doable now.  The keypad could be replaced by a PS/2 keyboard and some shift-registers, again shrinking the PCB footprint significantly.  And most damning, it has been shown you don't need a bunch of chips to do interesting things!

I ended up going with an architecture that emulates much of the 8085 instruction set so I could learn extensively from pre-existing code examples instead of translating over to a new instruction set.  The microcoded ROM gives the freedom to configure many different types of addressing modes and operations.  I ended up configuring over 100 instructions, but more types of instructions and addressing modes could be implemented simply by updating the microcode.

Not having much knowledge about programming, it turned out to be almost as complicated as the hardware.  Everything was written in machine code then manually entered into a binary file.  This made for a very time consuming and inefficient way of writing and updating the program.  Doing everything first with the simulation saved a significant amount of time.


Basic Architecture

  • W-bus: A single 8-bit data bus through which all data is transferred between each element of the computer.
  • Instruction Register: Stores the instruction currently being executed.
  • Controller/Sequencer:  A counter which keeps track of which micro-instruction to execute next (T-State).  It is a 5-bit counter so it can count up to 32.  The first 4 T-states are always the fetch cycle, which means each OpCode may contain up to 28 micro-instructions.
  • Microcode ROMs: Three Flash ROMs with an 8-bit output, which decode the instruction and T-State into the appropriate set of control signals.
  • Program Counter: A 16-bit register composed of four 4-bit synchronous counters, which can be preset for Jump and Call operations
  • Memory Address Register: A 16-bit register that sets the address of the memory
  • 32kB Program ROM: A 128kB flash ROM that occupies the lower half of the memory address space.  Using manual jumpers, 4 sets of programs can be stored and used.
  • 32kB RAM: A single static RAM chip.
  • Stack Pointer: An 8-bit register, the stack can grow to 256 entries, it is fixed at the very top memory page (FFF0-FFFFh).  Its main purpose is to automatically save the program counter when jumping to a subroutine.  After returning the address can be automatically reloaded.
  • Accumulator: A register for storing the result of all arithmetic and logic operation from the ALU.  This helps simplify the architecture and instruction set.  The stored byte can also be rotated or shifted.
  • B and C registers: Two general purpose storage registers for counting or saving data during an operation.  As a pair they can also indirectly address the memory.
  • Arithmetic Logic Unit: Two 4-bit 74LS181 chips.  It can Add, Subtract, AND, OR and XOR two 8-bit numbers or can Complement, Increment or Decrement a single 8-bit number.
  • Temporary Registers:  Two registers that store data for use within a single instruction.  They cannot be directly used or addressed by a program.
  • Flag Register: 4 flip-flops that keep track of the Sign, Zero and Carry bits and whether the keypad has been pressed.  The conditional Jump and Call instructions are affected by the status of the bits in this register.
  • Keypad Decoder: Two 8-line to 3-bit decoders that translates a single key press into a 4-bit number.  It also sets the keypressed flag, which the programmer can use for detecting when new data is present in the input register.
  • Input Register: Each press of the keypad clocks in the code for the keypress, which can then be loaded by the computer.
  • Output Register/LED display: An 10x8-bit shift register in which each individual register also drives a 7-segment LED display.  Clocking out one byte shifts the display by one character.


Bugs and Problems Encountered

The CPU speed is limited to 500kHz.  Somewhere between 500kHz and 1Mhz some instructions stop working, notably conditional calls and jumps.  At 2MHz and above it seems to stop working altogether.  I don't have a logic analyser so I can only speculate as to the exact cause.  I ended up bread-boarding some of the controller/sequencer and found (with my oscilloscope) that when changing between certain ranges of address, the outputs of the ROM will have a momentary glitch.  These glitches are enough to trigger the asynchronous set or clear inputs of flip-flops and registers.  So basically any input that is not synchronous with the CLK signal is vulnerable to being erroneously triggered (Like the /NOP signal).  Buffering each control word with another register that filters out these glitches may help but this complicates the design.

The tactile switches in the keyboard bounce significantly and don't always get decoded properly.  Pressing hard then releasing quickly minimizes the issue.  Also a significant software delay must be used before resetting the keypressed flag or the still bouncing switch will re-trigger it leading to a double input of the same character.

The switch that changes between an external and internal clock cannot be used while the computer is running. As it doesn't have any de-bounce circuitry, it will actually induce the bouncing into the clock signals.  If you switch to an external clock source while it is running some of the registers can latch up causing a crash.  Also, I should have wired the switches so the Auto/Manual switch overrides the Internal/External switch.  As built, while in external clock mode you cannot switch back to single step mode.

During simulation in Proteus Design Suite, I found that the carry bit from the 74LS181 model did not propagate correctly for certain operations.  This lead to weird results if subtracting two numbers and there was a carry between the upper and low nibbles.  It was fixed by emulating the function of a 74LS181 with a ROM acting as a look-up table for every possible combination of inputs.


Final Thoughts

Overall this was a very humbling experience.  I have spent the majority of my free time over the past year learning about digital electronics, CPU design and programming with machine code and the end result is a device that doesn't even have the functionality of a 99 cent pocket calculator.  And I definitely could not have accomplished this modest height without the extensive knowledge written by those who came before me.  It definitely makes me appreciate all the technology one has at their disposal today.


  1. Saw you on Hack-A-Day. Hope you put some thought into developing a kit, cause without even reading thru all the docs yet, you've got at least one sale already.

    1. I don't think I will be making a kit any time soon. I made one of my last project (search for TTL Tennis on and I have barely broken even on the sales. Plus, my return to full time employment has really cut down my free time. If you (or anyone else) are really interested, email me and we can work something out.

  2. Excellent work! The final result looks very nice. How long did the whole process take you?

    Could there be a bug in the Proteus model of the 74181? I've used two '181s to perform subtraction, and didn't encounter any carry propagation issues between nibbles.

    If you ever do a version 2, I'd suggest using synchronous inputs most places, not asynchronous. Usually a chip has both, or there are two different versions of the chip depending on whether you want synchronous or asynchronous. Any combinatorial circuit like your ROM has the potential to generate glitches, as you discovered.

    What are you going to work on next?

    1. I was aware of the various homebrew computers for years, but didn't truly get started on my own until late December 2012. I had settled on the calculator idea when I found video on youtube of a calculator made of discrete logic chips; it also introduced me to Proteus Design Suite. SAP-1 took about a month to understand and "build" in simulation. The ASAP-2 was my first attempt and it took about two months. I then realized I can simplify things further and still build a working calculator, thus the ASAP-3.

      Hardware/microcode+debugging: 2 months
      Calculator software: 3-4 months
      PCB layout: 1 month

      I became permanently (I hope) employed some time in the middle there so that added a significant delay. Once I figured out the control signals for each type of operation and addressing the microcode was surprisingly simple to figure out.

      The bug with the 74LS181 was only in the simulation.

      Synchronous input is definitely the key to proper CPU operation. I'll probably make a version 2 in simulation, but I don't know if I will build another PCB.

      I want to eventually learn how to write HDL code and try to figure out CPLDs and FPGAs.

  3. Outstanding work! Having done a microcoded CPU myself, I know it's a lot of effort. You're right that synchronizing the output of the microcode PROMs would help, they (used) to make registered PROMs for just that reason. I'm surprised that you were even able to find them...and program them! With registered PROMs, you should be able to run that puppy into the 10s of MHz -- as fast as your RAM will allow.

    There is a carry-lookahead generator for the 181, it's a 182 or 183, I think. That will speed up your ALU carry operation significantly.

    Debouncing the control panel switches is a must, but easily done. Switching clock is possible, but you need to make sure you do it while both clocks are in the same state, to avoid causing glitches.

    Still, very, very nice work! If you're not employed as a hardware designer, you should be! Next project: implement your design in an FPGA (there are Xilinx evaluation boards available quite cheaply)

  4. How do I drive a LCD display using only logic gates? Have a good day.

  5. You are basically sending a series of 4-bit nibbles or 8-bit words (depending on the LCD control mode) to the module to initialize it and enter the characters you want to display. Without building a CPU out of gates, the simplest way might be to use a ROM programmed with the commands. The ROM address could be connected to a counter so that the commands are outputted in sequence.

  6. A very cool project you have there. I am actually thinking to rebuild it, but I couldn't find the key caps that you used. Those are transparent ones with a printed paper under it to name the key, right?