MicroComp


Overview:

CPU MicroComp
Data 8 bits
Memory 2x 16 bits
Registers 3 1/2
Architecture Modified Harvard
Technology TTL
Status There is at least one major bug in the TTL version
Successor None
Time period December 2017 - present

Problems:


Lessons:


If you read about Mini Comp, you would know that it failed me and that I replaced it with MicroComp. Yes, I do find it kind of odd that I named a 4-bit computer Mini Comp and a larger 8-bit computer MicroComp. Design went well, but it inherits its predecessor's instruction set style. That is not great, but it works because four times as many instructions are available.

The plan to make MicroComp started around the end of November 2017, but because of my busy schedule at school, design did not actually start until winter break. Just like Mini Comp, MicroComp received a load-store architecture that is very difficult to work with. At least it can manipulate arrays without self-modifying code. To make it a bit easier to program, I planned to make a virtual CPU with an instruction set that only operates on memory. This is a bit similar to Gigatron's vCPU, except that instead of running from data memory, it will be required to run from program memory.

Over spring break I built the computer. At first the wiring didn't bother me, but after spending hours cutting, stripping, and poking the wires into the breadboard, it became quite tedious. I did finish, but I do not think I powered it on until summer arrived.

My original plan was to disconnect all control signals that could possibly cause bus contention before I turned on power. Instead, I got impatient, and I turned the it on anyway. The first thing I noticed was that the computer was drawing over 2 A. TTL is power hungry, but 2 A did not seem right. Assuming each of the 40 chips consumed 20 mA of current, the computer should draw about 800 mA. I suspected that most of the wiring was correct, and that there was probably only a few components to blame. An infrared thermometer was very useful and showed that the capacitors and all of the chips were at a relatively low temperature, except for the flag register 3-state buffer, which read 105 °F. After rotating the chip 180°, the power supply current was about 800 mA. Much better.

After fixing a few wiring errors, it was time to run the test program. The first instruction was LDI 0xDE A with an opcode of 0x01. At least, that is what it should have been. The opcode is located in the upper 5 bits of the instruction byte (resulting in 0x08), but instead I placed it in the lower 5 bits (resulting in 0x01). That meant that the CPU had to sit until the next time I could get to school, since I did not have a sufficient flash programmer (the one I made doesn't count). I don't remember how or when, but I also discovered a few bugs in the microcode that I later fixed.

Since MicroComp did not have any programs it could run, I decided to simulate it when I came across this warning. I found some more bugs in the microcode and in the schematics, which shows just how useful this step is. I fixed the bugs in the microcode and then programed it into flash at school.

MicroComp without microcode or program flash
MicroComp no microcode (jpg)

Once the final version of the microcode and test program were programmed, I went step-by-step through the test program, comparing the predicted result with the actual result. All of the instructions up to the addition instruction were tested, when I found that the low nybble of the ALU was adding 1 when it was not supposed to. My first thought was that the carry in (Cn) was stuck high because of improper wiring. I checked Cn, but it was low. A0 and B0 were in the correct state as well. When I checked the wires connected to the pins I found that they matched the schematic, and the schematic had been verified in simulation using the very same test program. At this point I became suspicious of the ALU (74381), so I took it out and tested it under the same conditions. It worked fine. I rechecked the wiring of Cn, and found that the carry bit in the flag register was not connected to it. Once I made the connection, addition worked fine. So why did Cn act like it was high, but when checked was low? What probably happened is that the pin floated high because it is TTL, but the LED that I tested the pin with pulled the pin low. If I tested the two pins at the same time, it would have taken a lot less time to diagnose the problem.

Testing suspicious 74381
74381 being tested (jpg)

A little before I found the addition bug, I noticed that the instruction SWF A F sometimes moved A to F but not F to A. After the addition bug was fixed, this is the only way it would behave. Unfortunately, I think the only way I can get around this is to load the microcode into a register before the instruction is executed, or to slightly redesign the ISA. I will probably choose the latter. This may involve adding a 3-state output to the C register so that it can be used as an ALU input. This would make arrays a lot easier to implement. I refuse to take this machine apart after I have spent this much time on it. Maybe while I'm at it I'll add DMA.

2019-07-19

I redid the microcode, but I did not want to generate the binary by hand as I had been doing previously, so I wrote a simple microassembler. Besides providing a useful tool to assemble microcode, it also allows me to easily modify the instruction set. Microcode v1.1.0 was slightly better than microcode v0.3, but I think I can vastly improve the ISA by increasing the number of instructions and adding multiple addressing modes to instructions that were formerly only meant for registers. (A few hours later...) The additional addressing modes required the destruction of the contents of some of the registers, so I came up with an instruction set that worked directly on memory. A comparison of Fibonacci using both instruction sets revealed that the load-store version (v1.1.0) was both faster and smaller than the memory-memory version. As a result, the only change I am making to v1.1.0 is to double the number of instructions to 64. I will have unused opcodes, but that is fine since I have plenty of memory in the microcode ROMs.

2019-07-21

Once again, the VHDL simulation is proving helpful with debugging. I seem to have found a bug in Vivado's behavioral simulation though. When I load a new version of the microcode into Vivado, I am able to read it from its text editor, but when I run a simulation using that version of the microcode, nothing changes. To fix this, I have to modify one of the VHDL files. Once I do that, the simulator uses the correct version of the microcode. It seems like this is a problem with caching memory files and not using the original copy. I guess this is a case of a feature that has turned into a bug.

Fibonacci works in simulation! Now I need to figure out how to program the ROMs. I guess I will take a break from MicroComp and work on the flash programmer.

2020-01-08

I have done nothing with the programmer.

The MicroComp hardware has almost reached v1.1. I have made all the changes required to run a Fibonacci program. This leaves the C register data buffer as the only modification left to add. So do we get blinky lights? No we do not. I don't have the annoying swap A and F bug anymore, but I am having a problem where the A register is being loaded without a clock pulse. Hopefully putting capacitors on a few of the clock pins will make it run properly. It should definitely be easier to solve than the Swap bug.

MicroComp as of 2020-01-08. There is now a third board.
MicroComp 2020-01-08 (jpg)
Debugging with a logic analyzer (LA)
MicroComp and logic analyzer (jpg)
Instruction register and microprogram counter during execution of the Fibonacci program. I spy glitches. Pin #2 of the LA is broken, which is why it is low.
MicroComp IR LA trace loop (jpg)
Program start. Pin #3 is unreliable.
MicroComp IR LA trace start (jpg)

I have decided to stop using EAGLE because of its limitations (and that fact that I didn't want to sign in to Autodesk), so the MicroComp schematics are now available for KiCAD as well. I used the built-in conversion tool, so not everything may work correctly.

2020-01-13

I worked on MicroComp a bit more. I tried adding a capacitor to the ACLK signal, and the LEDs started blinking! They are not, however, blinking out the Fibonacci sequence like they are supposed to. Instead they are adding two each iteration.

2024-12-16

I have made a little bit of progress in the last five years. The first thing I did was to add registers on the output of the microcode to prevent the deadly race conditions. I was surprised to find that it worked in simulation on the first try. I can't recall if I needed to change the microcode for that. I think I did and it probably delayed instruction decode by a clock cycle or two. Yes, that's a major hit to performance, but I don't currently care provided the machine works.

The new microcode word synchronization registers
Microcode synchronization registers (jpg)

The lower left side of the left breadboard has the three microcode memories. If you look at older photos of the computer, you may notice that they are thinner. That's because I shocked some of my flash chips and now I only have three total. The computer needs four: three for microcode, one for program. At some point I'll have to order more flash, but for now I'm using SRAM instead. Of course the downside of SRAM is that it has to be loaded each time the computer is powered on, which means I need an additional mechanism to do so.

Microcode loader
Microcode loader (jpg)

The blue microcontroller is an LPC1769. Two digital I/O pins are dedicated to the UART, and nearly all the rest are used to program the SRAMs. The big green and gray board is an Atmel STK500 (Huh. I suppose they're Microchip now.) which I am using solely for the RS-232 to UART converter. Beside the STK500 is the flash programmer, which is not in use.

The LPC1769 is running the duck-lisp virtual machine, which runs bytecode sent to it by my laptop. The laptop compiles a duck-lisp script to bytecode, during which a macro reads the contents of the microcode images into the program. The bytecode is sent to the microcontroller which then executes it. The purpose of this complicated system is to 1) have fun, and 2) allow a tight debug cycle. Once the loader is working properly, I should be able to load the latest microcode, run it on the TTL computer, and when it fails, simply fix the microcode sources and run a single command to compile and load the new microcode. Unfortunately, the loader isn't working yet, due to a couple of the GPIOs acting weirdly. From what I recall, one bit can't go high and another bit can't go low. I haven't yet pulled out my oscilloscope to figure out what's going on.

The hardware isn't the only thing that's had a significant change. It occurred to me that it's going to be a while until I have a computer I can write software for, so I figured I'd write a simulator for it. It is a pretty straightforward conversion of the schematic into C, with some statements reordered so that everything happens in the right order. The other reason I wrote it was that I spent a few years writing duck-lisp, and I recently realized that if I could make a simple bytecode virtual machine for the TTL computer, then I would only have to make a few tweaks to the duck-lisp compiler in order to have a high level language. A bytecode VM also has the advantage that its instruction density is much higher than native machine code, meaning that if I can make the VM small enough, it actually increases the maximum size of the programs that can be run. The trade off is that it will slow down the machine.

The assembler is written in duck-lisp, which is surprisingly well suited to this task. The syntax is the same as native duck-lisp, but looks almost like normal assembly due to parenthesis inference.

I started writing the VM and have got as far as instruction dispatch. Dispatch is done by using the opcode to index a 128 by 2 byte table of addresses that selects the correct subroutine for the corresponding instruction.

A while ago I noticed that adding a single 3-state buffer would allow reads from the C register. I was disappointed about this limitation, since it seemed like such a great gain for just a single chip that I left out of the design simply because I didn't stop and calculate how many chips the feature would actually need. Well after writing some assembly, I've noticed that I haven't needed to read the C register even once so far. I'm not completely sure, but I think it's because there's so few registers, which forces the B and C registers to constantly be loaded with new memory addresses to fetch from and write to. The lack of registers gives the feeling of using a memory-memory architecture, but without the convenience. I might write up a better explanation later. But I don't think I will make it so that C can be read.

I also noticed that I tended to write the instructions ldi (low address) b and ldi (high address) c a lot. Given how often they are used together, it seemed like I could save a byte by creating a new instruction to load both the C and B registers at the same time. So now that code is written ldi address cb. This should slightly increase execution speed and I still have plenty of unused opcodes to spare for future extensions.


New!

All resources are now hosted on GitHub. The last non-GitHub version will be kept below, but I am now pushing new versions to GitHub.
MicroComp scratchwork, tools, and software
MicroComp KiCAD schematics
MicroComp VHDL sources


Files:

MicroComp reference v1.1.1 (txt)
MicroComp reference v1.0 (txt)

MicroComp KiCAD Schematics v1.1.1 (zip)
MicroComp EAGLE Schematics v1.1.1 (sch)
MicroComp v1.0 EAGLE schematics (sch)

Test programs (zip)

Microcode v1.1.1 (zip)
Microcode v1.1.0 (zip)
Microcode v0.3 (zip)
Microcode v0.3 for simulation (zip)
Microcode v0.2 (zip)
Microcode v0.1 (zip)

This microcode assembler detects improper syntax by displaying the text "Segmentation Fault" and exiting.
Buggy microcode assembler (zip)

Note that the VHDL sources include the simulation microcode.
MicroComp v1.1.1 VHDL sources (zip)
MicroComp v1.0 VHDL sources (zip)

The MicroComp simulation sources are dependent upon these 7400 series VHDL modules
7400 series VHDL sources (zip)

Anything related to development of MicroComp.
Development scratch-work (zip)

Updated 2024-12-17