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/wiki/Transport_triggered_archi

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. Currently, I'm developing a bootloader, so I can load programs over the UART. In parallel I'm also planning my 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.

sheet - 13.55 kB - 05/25/2017 at 14:59

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

  • Stack working!

    Justin Davis4 days ago 0 comments

    I have my stack working. It takes a lot of lines to do a pop/push, but that's the nature of a RISC or OISC. I thought about having two dedicated registers for the stack pointer, but I really don't want to increase the hardware complexity when I can do it in software. I assigned the stack pointer to memory locations 0xFFFE and 0xFFFF. Since it contains a memory location, it needs two bytes.

    It initially points to 0xFFFD. So it points to the next available memory location (empty stack style). Then the stack grows down. Pushing to the stack will write the byte first, then increase the stack pointer. Popping from the stack will decrease the stack pointer first, then read the byte there.

    Ok, I have the first test of the routine hardwired to return to a specific address, so I need to update it to grab the Program Counter and then add an offset. The offset changes as I refine the push function, but I can handle that.

    I found that my string output function would be really handy if I could push a memory address onto the stack which contains the pointer to the string, and then call the function (pushing the return address on the stack). So my string function would grab the string pointer off the stack, and at the end pop the return address off the stack.

  • Bootloader

    Justin Davis6 days ago 0 comments

      I think before I get into writing other software, I should focus on a bootloader. I don't like to keep synthesizing my VHDL every time I want to change my program. I need to poke the RAM and execute the program, so I have to give it a memory location and a byte. And it would be VERY useful to have a readback function, but I could do this afterward. So I put together a list of things my bootloader needs to do:

      1. Echo characters back to uart (DONE!)
      2. Keep track of string entered
      3. Process backspace key (subtract one from string pointer if not zero)
      4. Process enter key (don't store in string)
        1. Echo command on a new line (DONE!)
        2. Jump to string processing
      5. Split string into parts: 1st character is command (W - write, R - read, J - jump) (anything else jumps back to top)
      6. Skip anything not a hexnumber (so I can have whitespaces and extra stuff for readability)
      7. Next four hexnumbers are the memory address
      8. If a write, next two hexnumbers are data to write to the above address
      9. if a jump command, set PC to entered memory address (begin executing!)
      10. If a read, grab the memory contents and output them to the uart (converting to ASCII)

      So I have my task list here. It should be easy to test as I go. And I can use everything I've written so far.

  • return of the string (output)

    Justin Davis6 days ago 0 comments

    Finally got my string output working! I found a bug with my compare bit. Now I really need to work on how to call functions and return from them. Then I use this string output as a function to send information over the serial port. It significantly helps my debug capability. To return from function calls, I need to have a simple stack. I'll need to pull the program counter and push it on the stack. I can write a stack in software. It's not necessarily a hardware-only thing even though many processors do it in hardware. The 6502 has a dedicated instruction for it. This means I need to start structuring my RAM. I've never written a software stack, but I know you need a pointer to the top of the stack. And then popping and pushing will need to decrease and increase this pointer. And I'll have to do it a lot, so it'll need to be simple.

  • Pointer oversight

    Justin Davis05/21/2017 at 03:14 0 comments

    I realized I need to use the pointer register to override both the destination and source register. I've finished writing a piece of code which grabs a string from ROM and puts it out to the UART. I use an index variable to the string. So I want to copy that to the pointer register, and then copy the pointer data (the ROM character) to the UART. I can't do it easily in the TTL version because that would mean putting the source and destination and the pointer address to the same bus. So the source and destination would drive onto the same bus at the same time. But I think I will need it. This is why I wanted to start writing some software. You find out very quickly what you need in the hardware when you start writing.

  • Build plan

    Justin Davis05/19/2017 at 21:49 0 comments

      So after being on a pesky vacation for a week, I put together a plan for construction of the TTL version. I wanted to be able to test as I go, so I figured I'd order the module construction sequence so I could check the system functionality before moving to the next part. Now I just have to acquire the parts...

      1. Clock circuit with single-step mode
      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 register
      12. Pointer address register
      13. ROM data tristate buffer (read byte at PC)
      14. PC buffer
      15. 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)
      16. RAM
      17. UART
      18. Expand PC and data ram high byte

  • Chip availability (oh TTL...)

    Justin Davis05/12/2017 at 18:56 0 comments

    I started thinking about how I'm going to implement the chip version of the project. I'm leaning toward solderless breadboard at first. And then maybe a board layout. So I started looking for chips to order online and ran into problems.

    I've been able to find the chips I expected to use, but they are upwards of $60+ per chip. I guess I didn't check the price - only if they were available. And I wasn't expecting it. SOOO I may have to bend my rules a little. I've looked for parts which are drop in replacements even if they aren't active chips. So the spirit of the goal is intact if not the letter.

    However, even those chips are little pricey. The register chips are $6 each, so I may replace them with a cheaper version where I don't need all the functionality. The 74LS374 Octal FF can work in a lot of places just fine and is only 79 cents. I believe I need 8 of these, so it's probably worth it to drop down when I don't need the extra functionality.

    The 8-bit counters are $8.25. So I may drop down to the 74LS161 4-bit counters at 79 cents. I'll just need two for each 8-bit version which ups my chip count. So $16.50 for two or $3.16 for four. But there's only two of these, so it might be worthwhile to go with the more expensive version.

    But at least I can find all the parts I need in some form or another. I'll have to make a mini-roadmap to build this up in small sections so I can debug and verify as I go.

  • ECHO! (Echo.) (echo)

    Justin Davis05/11/2017 at 12:55 0 comments

    Got my second program up and running. It echos what is received over the UART. It looks for the transmitter to be ready, then waits for new data in the receive buffer, then transfers the byte in and out. First step toward a bigger interface. The bigger plan is to have a simple terminal interface where I can write bytes to specific locations in memory. And then be able to load the program counter. This will let me load a program into memory and then execute it. I figure I can copy/paste programs from my laptop. I could have my program jump back to the bootloader after it is done so I can peek/poke memory locations to check its results. And maybe put in breakpoints or something.

    I would also like to get my project into Github which I've never used before. For 1) to share and 2) configuration management. It's in a good state for someone else to download and either simulate or program their own dev board. It's not the cleanest code right now, but I'd like other people to be able to take a look if they'd like. And I'd like it stored somewhere I don't think I'll destroy it. One more tool to learn, but I guess that's part of the point of the project - to learn!

            0 => x"84",        1 => PCTEMP,       -- move new memory page value located at 04 -> PC High Temp
            2 => x"85",        3 => PCLO,         -- move new memory page value located at 05 -> PC Low
            
            4 => x"02",        5 => x"00",        -- constants for new PC
    
            --UART echo
            512 => UARTTX,      513 => PTRADR,        -- mov UART TX status -> pointer addr reg
            514 => TRASH,       515 => PTRDAT,        -- jump back to 512 if busy 
            516 => UARTRX,      517 => PTRADR,        -- mov UART RX status -> pointer addr reg
            518 => x"0C",       519 => LOAD,          -- load forward jump address
            520 => LOAD,        521 => PTRDAT,        -- jump forward if data is ready
            522 => TRASH,       523 => PCLO,          -- jump backward if data is not ready
            524 => UARTDAT,     525 => ALUA,          -- move UART data to holding register
            526 => ALUA,        527 => UARTDAT,       -- move holding register back to UART data
            528 => TRASH,       529 => PCLO,          -- jump back and repeat loop

  • ALU restructuring

    Justin Davis05/10/2017 at 17:20 0 comments

    I think I may restructure my ALU a little bit. I originally had an A register and a result register. Writing to the result location puts the databus into the B port of the ALU and then captures the result into the result register. The problem is that the ALU has functions which don't rely on the B port. Like it has an A+1 function. So if I want A+1, I need to do a dummy write to a this register first, and then I can read out A+1. It would be nicer if I could have an A and B register instead, and then just read whichever result I want. So there's no result register - all results are available which are possible on the A and B registers. So if I want to have a simple up counter, I can just move the A+1 output to the A register and it takes one instruction. In the old way, it would take two. This would be a more elegant solution.

    However, I would need to put a tri-state buffer on the ALU output which would cost me one more chip. A nice thing about the registers I've chosen is they have built-in tri-state buffers. One goal is to minimize my chip count, so I think I may hold off on this change for now. Sure some things cost me an extra instruction, but maybe that's easier to absorb than an extra chip.

  • It lives!

    Justin Davis05/09/2017 at 17:05 8 comments

    I know it doesn't look like much, but it's my first proof that my architecture is valid. After more struggles with my software tools, I was finally able to connect to the Cmod board and download. My first successful download gave me this output. There were a lot of things that needed to go right, but I guess I took care of them beforehand. I wasn't sure the clock was set right, and my UART needed to be running at the right speed, etc.

    My program loaded the value 35 into ALU A, subtracted 3, and moved the result to the UART. This gives me the value 32 which is ASCII 2. I didn't have a stop to the program, so I think it's wrapping around the whole memory space and executing the code again and again. Fortunately, my program is set up so that a command of all zeroes will do nothing (MOV TRASH -> TRASH).

    Next up is writing some software. I should also start thinking about how to do an assembler of sorts. This is where I get into uncharted territory for me. I've never written an assembler. I don't really want to have to worry about keeping track of memory locations for jumps or variables. But maybe that can wait for a little bit. I want to write some programs! Maybe I'll start working toward a bootloader so I can put programs in RAM over the UART.

  • Synthesis successful!

    Justin Davis05/09/2017 at 12:40 0 comments

    Finally have no critical warnings on my synthesis. Turns out my circular reference was my own fault (not surprising). I forgot to put registers on the carry-out and A=B pins from the 74181 module. They fed straight to the databus which fed right back to the 74181. Next up is writing a piece of code which I can verify is working. I may throw for the endzone and send data to the UART first. And then when the ball bounces off the helmet of my receiver, I'll use the LEDs and buttons of the Cmod board. And probably also the GPIO pins and my logic analyzer. I may create an LED register and pass that out. It would make for some good pictures and I think people like those a lot. And prove I'm actually making something...

View all 41 project logs

Enjoy this project?

Share

Discussions

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