close-circle
Close
0%
0%

One-instruction TTL Computer

A breadboard-able computer which uses only a single instruction - MOVE

Similar projects worth following
This project is my attempt at making a computer which has only one instruction - the move instruction. Specifically, to move data from one location to another location. Those locations can be either registers or RAM or other special functions. This will be my submission for a neat small breadboard computer built by hand.

The specific type of computer is called a Transport Triggered Architecture, but the triggering will be very simple. It works by moving data from one location to another. Every function has a memory location. To perform that function, you only need to move data to those memory locations. For example, to perform an ADD, just move bytes to the two ADD memory location, and the result will show up in the third memory location on the next clock. So the programs will only be a series of source and destination addresses.

https://en.wikipedia.org/wik

Project status:

I have a working version of the architecture simulated in VHDL. It is synthesizable, and I have downloaded it to an Artix-7 development board - the Digilent Cmod. I have a few simple programs running with a UART interface. I have a bootloader running so I can load programs over the UART. I've written a simple assembler to generate machine code I can send to the bootloader. And I've started my breadboard hardware build.

Primary project goals:

  1. Implements only one instruction - move
  2. Can be built on a breadboard using a small number of simple DIP components (74xx TTL circuitry).
  3. All components are active. No obsolete or hard-to-find components. All components in stock at popular distributors.
  4. Useful - it needs to be able to run programs in a short amount of time.

Secondary project goals:

  1. Useful input mechanism. I expect a set of DIP switches for the input, but I'd prefer something more useful like a UART port or maybe a keyboard.
  2. Useful output mechanism. I could do a simple LED numeric display, but I'd prefer something more useful like a UART or at least a 4x20 character display. Perhaps I'd even do a video memory with a separate display.
  3. Easy and natural loading of programs. I'd prefer not to have a roundabout way to load programs into memory. Perhaps even use the above UART to send programs.
  4. Easily expandable for more memory. I'd like to be able to load very large programs.
  5. Write/adapt a compiler/assembler. I'd like to be able to take existing programs and compile them to run on the computer. This would probably be the last thing I do considering the complexity.

Build Plan:

  1. Clock circuit with single-step mode (DONE!)
  2. Program counter (low byte only)
  3. Instruction ROM
  4. Src and Dst registers
  5. Control state machine - 3-bit shift reg
  6. Decoding ROMs
  7. Load reg
  8. ALU A
  9. ALU chips
  10. ALU result reg
  11. AEB/Carry FFs/buffers
  12. Pointer address registers
  13. ROM data tristate buffer (read byte at PC)
  14. Data Ram register (may need to modify to store lower 7 bits of either dst or src so they can be buffered to the ROM)
  15. UART
  16. RAM
  17. PC buffer
  18. Expand PC and data ram high byte

sheet - 13.83 kB - 06/16/2017 at 17:29

download-circle
Download

Clock.pdf

Clock circuit schematic

Adobe Portable Document Format - 119.50 kB - 06/16/2017 at 17:28

eye
Preview
download-circle
Download

  • 1 × Texas Instruments PC16550D UART interface chip
  • 2 × Texas Instruments SN54LS181 4-Bit ALU
  • 4 × Texas Instruments SN54ACT245 8-bit bus transceiver with 3-state outputs
  • 2 × Texas Instruments SN74ALS867A 8-bit counter
  • 9 × Texas Instruments SN54ALS996 8-bit Register with readback and tri-state outputs

View all 7 components

  • Focus

    Justin Davis07/20/2017 at 15:54 0 comments

    I realize in looking over everything I'm doing for this project, it's actually several projects that are falling under one umbrella. 

    • A TTL design (which is only at the design phase)
    • An FPGA design (which is fully working)
    • An assembler (which is fully working)
    • Software code development to implement macro-functions which emulate normal architecture instructions (significant development)
    • Software code development to implement more advanced features like a stack and ASCII conversion
    • Emulated hardware on a PC for easier debug (not started)
    • Emulated hardware on a PC as a video game (not started)

    Each of these can be a separate project.  Looking over other projects, some people's whole project is to develop an FPGA microprocessor which is only one component for me.  Considering I have very little time/energy to devote to this project, I need to decide which components to focus on.

    However, there is an underlying commonality which is the architecture.  All of these assume a similar architecture even if they have different implementations.  The FPGA doesn't use tri-state buses, but the TTL circuit does.  It doesn't even matter if the TTL version has a single source/destination bus, and the FPGA has two separate ones, or even if it's emulated hardware.  As long as they can all execute the same code, then I would say they are the same.  I have to admit, I'm pretty happy with the FPGA version because I can change it very quickly and have decent debug capabilities with the simulator.

    I guess what I'm saying is I may delay building the TTL version for now, but keep the design so it can easily be built.  I'd like to focus on developing the software and run it on the FPGA.  The software development has been a lot of fun, which is why I keep thinking about making a video game about it similar to Human Resource Machine or the Zachtronics games.  If only I had more time/energy, but my priorities are family->work->hobbies, I'm left with maybe an hour a day for the last one and no energy.  

  • Infamous load function

    Justin Davis07/10/2017 at 13:59 0 comments

      I've been changing my datapath to only have a single source/destination bus. I've run across one problem with the LOAD register. Normally, I will grab the data from the source and store it in the temporary holding register, then write the temp register to the destination on the next cycle.

      When I do a LOAD, I take the source address and put it into the LOAD register. Which means I need to know both the source and destination at the same time. Or, the temp register doesn't have the valid data I need to put into the LOAD register.

      1. The best idea I have come up with so far is to have ANOTHER temporary register which holds the source destination only for the purpose of putting it into the LOAD register. It's not a great solution.
      2. I also thought about doing a look-ahead to see if the next instruction points to the LOAD register.
      3. Or maybe a look behind to pull the previous byte from RAM into the LOAD register. After all, the data is in the RAM - I just need to get it out again. But that means more extra logic which means more chips.
      4. Alternatively, I can ditch the LOAD functionality altogether. Instead just store 256 bytes in the ROM - one for each constant. So a LOAD would then be changing the data ram pointer to the constant area, then copying the correct constant out. And then change the data ram pointer back to where it was previously. It's a less elegant design, but it would be fewer chips. It might be problematic because what if I want to load a constant into the data ram pointer?
      5. Maybe I could change how the LOAD register works. In other words, the LOAD register always contains the previous source location. So the LOAD register would only be valid for one instruction. That may be an acceptable solution. I'll have to check to make sure that logic works without adding more hardware.

  • Decoding addresses with MUXes

    Justin Davis07/03/2017 at 15:25 0 comments

    tossed out all my wired logic. So the next step was how to replace it with TTL logic. I have one circuit which is particularly irritating. I want to decode the SRC/DST register to know if I need to put that onto the SRC/DST bus, or the POINTER ADDRESS instead. In VHDL, it's very easy:

        dstAddr <= ptrReg when dstR=PTRDAT else dstR;
    
    But I need to do the dstR=PTRDAT logic with chips. I want to do this in only one chip. This proved tricky. My address is x08 or 0x00001000. But I couldn't get the logic down to only one chip (NOR or NAND). There's just too many inputs. So I went with a different approach.

    I have a lot of free register space, so I decided to use this to make my logic simpler. I'm going to use the address space 0x20-0x2F to be my new pointer data address. This really means my address is 0b0010XXXX. This means I only need to look at the upper 4 bits. This still didn't simplify it enough to put it in one NAND/NOR chip. So I decided to use the MUX method of logic. I chose a 74LS151 8:1 multiplexer chip. Three of my inputs drive the select lines and the fourth is wired to one input. All other inputs are tied low. And there's a bonus inverted output, so one output goes the select the SRC/DST register and the other goes to select the POINTER ADDRESS register (off screen).

    This should be significantly faster than the wired-OR version with transistor inverters (haven't done the math on that yet). And it'll look better and be more true to the TTL goal. If I needed to decode a single address within the 0x20-0x2F space, I could put a second mux in and chain the enable input.

  • Sacrificing good design

    Justin Davis06/27/2017 at 12:41 0 comments

    I had thought I would save some gates by using wired-AND connections in some places. However, they are really slow (relatively). The TTL chips can go pretty fast, and if I add wired-ANDs or wired-ORs, it's going to lower the maximum frequency the device can operate. And I feel like it's not good design. I thought I would try to maintain good design practices and not put hacks in there.

    I had another idea to use the '374 chips instead of the '996. Those are 8-bit registers with an output enable, but no clock or load enable. So I was thinking I could just AND the clock with the clock enable. While this is logically possible, it's also poor design. One primary rule to digital design is DONT GATE THE CLOCK, and here I'm thinking of violating that rule. I don't think I can do that.

    So I'm reversing some of my bad decisions. I'm going to have to reevaluate my design based on this. I may keep the clock system for now since it's only temporary, and I'm only using that for low-speed operation anyway.

  • One too many?

    Justin Davis06/19/2017 at 20:10 1 comment

    I've been going over the optimization steps of my design, and I'm wondering if I have the right approach with a one-instruction set computer. Ultimately, is there much difference between having multiple instructions and multiple source/destination addresses? Decoding my addresses is very similar to decoding an instruction. I technically do have microcode, but it does the same thing every instruction. I still need multiple clock cycles to do memory fetching and execution.

    I'm wondering if maybe I could optimize my design by going to a no-instruction set computer. In this case, I would do no instruction decoding at all. The bits of the control path are stored directly as the instruction. So the instructions are then very wide. But if I make my datapath simple enough, maybe it wouldn't be that big. Given that I could have a very large memory, perhaps this is a more optimized path. However, this violates the very root of my project - a one instruction computer driven by data transfers with a memory map. I'll have to think on which direction I want to go. I really want a minimal architecture which can be done with couple dozen TTL chips, but still powerful and flexible.

  • Shoot the engineer

    Justin Davis06/19/2017 at 17:43 1 comment

    There's an old saying that goes "In every project there comes a time to shoot the engineers and start production". Well, ya that's kinda true. We always see improvements and want to make changes. I'm thinking of making a significant change to the project to reduce my chip count and complexity. Right now I have a register for the source address and one for the destination address. And they have their own separate busses and will need their own decoding. These two sections are essentially redundant, so I'm thinking of combining these circuits into one.

    The new control flow would go like this:

    • Read the source address from RAM/ROM into the src/dst address register.
    • Copy the source data into a temporary holding register
    • Read the destination address from RAM/ROM into the src/dst address register.
    • Copy the temporary holding register into the destination.

    Now instead of three clocks per instruction, it will go to four. However, again this could be reduced if the RAM/ROM is not the source or destination. So it could still be as little as two, but requires a little more logic. But it would save at least 6 chips even if I'm adding the temporary holding register. There'd now only be one src/dst address to decode. I want to reduce my chip count as much as is reasonable while maintaining an 8-bit databus. I'll have to archive my project in case it doesn't work out.



  • Clock improvement

    Justin Davis06/16/2017 at 17:28 0 comments

    he problem with the clock is the switching mechanism. If you change the clock source when the clock has just gone high, some registers may see a rising clock edge and trigger and some may not. This will cause your system to go into an unknown state which is bad. So I changed my switch mechanism to only change when the oscillator is low. I used the two free OR gates to gate my bistable LM555 inputs with the astable LM555 oscillator. I think my clock circuit is finished for now. I'll upload the full schematic as a PDF.

    Improved circuit:

  • Clock circuit working

    Justin Davis06/16/2017 at 12:36 0 comments

    Finally got my clock circuit up and running. I'm using a wire for the break signal to check it out. When the break is enabled, it overrides the Select button and selects the Step function. Pushing the step button will then step past the break instruction and then return control back to the oscillator. I'm still not totally happy with how it handles the transition between clock domains, so I may end up pulling all this out and starting over. But not yet - I have way too much else to do.

  • Revised program counter

    Justin Davis06/14/2017 at 16:13 0 comments

    I've made some changes to my program counter to incorporate a different counter chip. I found the 74LS593 counter. It's basically the same except it has a single bi-directional bus. This is handy because now I can tri-state my counter output when I want to do data memory access. I ended up completely reworking my block diagram to incorporate it. I needed to add a couple more chips too, but now I believe all of non-control chips are in place. The control logic might be a bit of a bear, but the datapath is nice and clean. I'm also putting together a real schematic, so this is my guide for that.


  • Clock circuit

    Justin Davis06/13/2017 at 14:23 0 comments

    I've started assembling the first part of my clock circuit. I decided to partly follow the steps of Ben Eater.


    I'll have a variable clock using a LM555, then a push button to step one instruction debounced with an LM555, and then a push button to select between the two debounced with an LM555.

    However, I'm departing a bit after that. He has a HALT command to stop the clock until a reset is performed. I think it's more useful to have a BREAK command to stop the clock. The clock can still be manually stepped if the BREAK line is high. This allows you to step past the BREAK command and continue operation. So this can be used as a debug function instead of just stopping the processor until reset. I worked out the digital logic and it looks something like this:

    I decided to use two TTL OR gates, and then a wired-AND and a transistor inverter. I chose the OR gate chip because the clock is going to have a large fan-out, so I want a good driver. I could have done the same thing with another chip or two, but this should be more compact. The pull-up style logic will be slower than a TTL gate, but I'll have to check to see how slowly. Eventually I may tap into the UART chip's crystal to provide my clock, at which point I'll want to replace the wired-AND with a real TTL chip. I may be able to pull it off with a single NAND or NOR.

    I wanted to add one more thing: this is a bad way to design a clock circuit. There can still be glitches when switching between clock domains. If the clock pulses high, then the select line immediately switches to the step mode, there can be a timing violation in the flip-flops (clock too-short). So some flip-flops will switch state and some will not. I haven't fixed it, but I may later.

View all 57 project logs

Enjoy this project?

Share

Discussions

agp.cooper wrote 07/13/2017 at 15:27 point

Hi Justin,
Step back and relook at what a TTA is:
MOV [DST], [SRC] 
---
The machine cycles are:
Fetch SRC (address)
Fetch Data from [SCR]
Fetch DST (address)
Deposit Data to [DST]
This is what the timing diagram of the control signal looks like for the above machine cycle:


---
Sorry there is no load immediate but your assembler can store a constant for you to simulate a load immediate.
---
For indirect addressing (pointer to pointer moves, you will need these at some point), you will need self modifying code. 
That is for another time.
--
If your happy with the above the decoder logic is four chips including the clock.
---
AlanX

  Are you sure? yes | no

Justin Davis wrote 07/13/2017 at 15:46 point

I can see one different in our design strategies.  I've been using the same clock for all my components, but then using the enable lines to control when I want them to do something.  You send each component it's own clock only when you want it to do something.  I've found a lot of TTL components do not have enables, so this makes a lot of sense.

  Are you sure? yes | no

agp.cooper wrote 07/13/2017 at 08:38 point

Hi Justin,

After 56 logs and frustrated by the load instruction do you want some help?

AlanX

  Are you sure? yes | no

Justin Davis wrote 07/13/2017 at 11:48 point

I'm always open to advice.  The load instruction only became a problem when I decided to combine the source and destination buses into one.  It removed like 6 chips, but had to add two back.  So it's not a huge deal - just optimizing the design.

  Are you sure? yes | no

Andrew Starr wrote 04/28/2017 at 00:39 point

Very interesting! TTA has a certain austere simplicity that appeals....

  Are you sure? yes | no

agp.cooper wrote 04/25/2017 at 08:43 point

Hi Justin,

Have a look my Weird CPU it is a true move only CPU build with TTL:

https://hackaday.io/project/12879-weird-cpu


It is a lot more primitive than what you are proposing.

Regards AlanX

  Are you sure? yes | no

Justin Davis wrote 04/25/2017 at 21:53 point

That looks great! And gives me some ideas for my own project.

  Are you sure? yes | no

Justin Davis wrote 04/22/2017 at 11:27 point

well that takes the wind out of my sails a bit.  I may have to review my goals based on these projects to keep mine unique

  Are you sure? yes | no

Yann Guidon / YGDES wrote 04/22/2017 at 13:36 point

no, just continue in your own way, you can only make something unique and discover new ideas if you don't look too much at other things :-)

  Are you sure? yes | no

Justin Davis wrote 04/22/2017 at 17:29 point

Ya, looking over that project and a few others, I still think my direction is unique. I think the one posted today is not a true one-instruction since it decodes the instruction into 4 different functions even taking a different number of clock cycles for each instruction. The others handle branches differently from how I'm planning on doing it. But they did have some good ideas.

  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