16-bit Serial Homebrew CPU - 2023
jiristepanovsky.cz
Return to Index
16-bit Serial Homebrew CPU - 2023
Building a homebrew CPU from scratch takes a large number of logic chips. It is understandable, that implementing registers, program counter, ALU, and other components of the CPU in TTL or CMOS logic does require a substantial amount of chips. But how many exactly?
I've tried to optimize my homebrew CPU for the lowest amount of logic chips possible and answer a question:<br>How few ICs are required for a Turing-complete CPU without a CPU?
My answer is a 16-bit Serial CPU with only 8 ICs , including memory and clock. It has 128kB SRAM, 768kB FLASH, and can be clocked up to 10MHz. It contains only a 1-bit ALU, but the majority of its 52 instructions operate on 16-bit values (serially). At its maximum speed, it executes roughly 12k instructions per second (0.012MIPS) and, among other things, is capable of streaming a video on PCD8544 based (Nokia 5110) LCD at ~10 FPS.
Depending on where you place the line between a state machine and a CPU, my 16-bit system might actually be the CPU with the lowest amount of ICs. Although, some other contestants are Jeff Laughton's 1-bit computer with 1 instruction and 1-bit of memory, and Daniel Thornburgh's Simple CPU with 1 byte-byte-jump instruction and memory simulated on a Raspberry PI.
Hardware:
The architecture is inspired by other CPU builds like James Sharman's JAM-1, Ben Eater's SAP-1, Warren's 4-bit Crazy Small CPU, its 8-bit version, and others. All of them, and many others alike, use a "control" EEPROM, EPROM, or ROM for generating control signals to the CPU components. Because it is way easier than generating them by logic circuits alone, and because it offers more flexibility in the future, I've also decided to use such a "control" memory, specifically, an EPROM. Contrary to the builds mentioned above, I've aimed for the lowest possible chip count, so I've tried to "squeeze" as much data processing inside the memory as possible, to either lower the demands on other CPU components or better yet, eliminate them completely. Here are some key steps taken:
Completely eliminating the ALU and implementing it as a lookup. Because most EPROMs have only 8-bit output and the system also needs other control signals, the data width of the ALU has to be drastically limited. Not to worry, it can be reduced all the way down to a single bit: 1-bit computing is actually all we need.
To get any meaningful computation done, the output from the 1-bit ALU has to be serialized. That is a perfect use case for a serial SRAM, which also brings other benefits. First, it eliminates the need for registers, since all ALU operations can be performed directly on the data in SRAM. Second, serial SRAMs are also addressed serially, so there is no need to latch the source and destination addresses. Third, an arbitrary data processing width can be achieved just by selecting the number of SRAM clock cycles. I chose 16 bits (16 SRAM clock cycles per 1 ALU operation) as a nice compromise between utility and speed.
At least 2 serial SRAM chips are required, one of them has to provide a serialized input to our 1-bit ALU, and, at the same time, the second one has to store the result.
For ALU operations with 2 operands (like ADD/AND/XOR...), 2 serialized inputs are needed. Adding a third SRAM could certainly be an option (2 for ALU inputs, 1 for result), but there is a better solution. If a serial FLASH memory is used instead of an SRAM, the same benefits remain (already serialized data, serialized address), but the FLASH can be used for storing the instructions/program as well as providing the ALU input.
It is unnecessary to add any hardware for a program counter, as there is already plenty of space inside the SRAMs where its value can be stored.
Even with these dramatic simplifications, some additional hardware is still required, however, everything can be built with just 8 chips in total, following the schematic below:
The circuit is built around a 128kB M27C1001-15 EPROM, working at 5V and combining a control state machine with a 1-bit ALU. Its output lines are latched by a 74HC574 every clock cycle and control the two 23LCV512 64kB serial SRAMs and one W25Q80 1MB serial FLASH. There are not enough outputs to control each memory individually, so they share the data line and partially also the chip select line, only the clock lines are kept separate. I could not find a 5V serial FLASH memory, so resistors R3, R4, and R5 limit the current and form a bridge from 5V to 3.3V. I do not count the MCP1703 3.3V voltage regulator as part of the CPU (I consider it, to be a part of a power supply), but with it, my CPU contains 9 chips.
The current instruction is stored in a buffered shift register 74HC595, which has its control lines also partially shared with the memories. Every instruction takes a couple of cycles to complete, so the progress within an instruction is tracked by a "microcode"...