Skip to the content
PCBKitNew board
2 layers126.5 × 84 mmControl panel, the printed circuit board in 3D

Design for a DIY computer

Size
126.5 × 84 mm
Copper layers
2
Thickness
1.6 mm
Parts
56
Nets
71
Pads
251
Tracks, vias
431, 25
Pours
2
Routed
Yes
KiCad
KiCad 8.0 (file 20240108)
Created
11 Mar 2024
Updated
26 Sep 2026

Overview

Control panel is an open-source printed circuit board by emperor-hadrian, from the emperor-hadrian/stack_machine repository on GitHub. It is a 2-layer board of 126.5 × 84 mm with 56 parts on 71 nets, routed with 431 tracks and 25 vias.

Its parts include 22 ICs, 13 resistors, 7 switches, 6 capacitors and 4 connectors.

README

README.md

Stack Machine Version 2

Photo of Version 1

Changes from previous version

  • The timing will be completely redone: A single normal clock signal, not the stupid "AB Alternating" I made up for the original.
  • The PC will be incremented and a new instruction fetched during any non-flow-control instructions except when the GPRAM is used and the PC is in the same RAM chip (the RAM chips have 15 address lines each) as whatever is being accessed. The bus timing will also be very flexible and will be faster when possible but still slow when the memory is being accessed twice for example.
  • Bus read/write addresses are both now 5 bits. The WRITE/MOVE instruction formats will remain the same and the extra bit (MSB to be exact) will be set based on duplicate opcodes for WRITE/MOVE that are otherwise interpreted the same. 1 extra WRITE opcode and 3 extra MOVE opcodes.
  • The opcode decoder is actually 3 bits. There will be 4 bits used for extra MOVE/WRITE instructions (see above).
  • Interrupts: There will be seperate interrupt GOTO latches that go to a dedicated interrupt handler function. That function should save the state of everything else (including the regular GOTO latches, which is why interrupt GOTO latches are seperate) onto the stack then do whatever depending on the interrupt code.
  • GOTO latches can be written to the bus (see above). The goto decider doesn't need to be because it's simple to get its value from an IF-ELSE.
  • The control unit will be able to fetch instructions from the GPRAM: Program addresses starting at 2^15 (32,768, halfway through the old flash memory space) will load 2 consecutive bytes (an instruction is 2 bytes) from the GPRAM. The GPRAM address of the first byte (lower byte of the instruction) will be determined by: (prog_addr - 32,768) * 2. Since that will only happen at or above 32,768 then the MSB will not be used in the math and will be used to determine whether to read from flash or GPRAM.
  • Flash program space is selectable: The flash chips have 17 address lines, while 15 are used (see above about half the program address space being mapped to the GPRAM). This means that the top 2 lines can be connected to jumpers to select between 4 different programs.
  • Flash program can be written to from the bus: The programming interface takes 8 data inputs + power and GND. The old interface to plug an Aduino in to program it will still be there of course but it can be selected by a jumper to be either the external pins (to Arduino) or from the bus.
  • The stack is 32k instead of 64k so only one memory chip is used, although 32k is still incredibly excessive.

GPRAM Parallelization

The RAM chips have 15 address lines each so there will be two of them (Lower and Upper Domains). This means that they can be used seperately at the same time, for example fetching the new instruction (If the PC is in the RAM) and also doing GPRAM read/write, as long as these operations are using seperate domains. Memory users will use either (or both) of the lower or upper RAM domains:

  • Program: PC and data read into instruction registers A & B
  • Heap R/W: Exactly the same as the original

Program instructions

Each instruction will be 16 bits and interpreted by the control unit. The first 4 bits (0 - 3) of the instruction will address the below list of operations. The rest of the instruction (bits 4 - 15) may be ignored or used for different things depending on the specific operation.

Here's the current list of the operation codes (opcodes):

  1. MOVE - Bus usage - The rest of the instruction will be interpreted as follows: bits 8 - 11 address the device which will set the state of the bus (TX) and bits 12 - 15 will address the device to read from it (RX). Bits 4 - 7 are sent to the ALU as it's opcode incase the data is comming from it.
  2. WRITE - Writes instruction bits 4 - 11 to the bus. Bits 12 - 15 address the device to read from it.
  3. GOTO - Saves the 2 execution pointer GOTO latches (each of them are 1 byte) to the program counter
  4. GOTO-IF - Reads the LSB of the value in the goto decider latch and does a GOTO only if it is 1, otherwise does nothing
  5. HALT - Stops the clock, usefull for debugging
  6. CALL - Effectively the same as GOTO but also pushes the return address (current value of program counter) onto the call stack. Note: The return address can be copied as-is and does not need to be incremented because it will be incremented normally after each RETURN instruction when it is used. If bit 4 is 1 this means that this call is calling the interrupt handler using the Interrupt GOTO latches.
  7. RETURN - The program counter will be set to the return address popped off the top of the call stack. If bit 4 is 1 this means that this return instruction is returning from the interrupt handler function and will allow interrupts again.
  8. CONFIG-INT - Configure interrupt. Bit 4 enables or disables interrupts. Interrupts are disabled on startup.

The following are treated as either MOVE or WRITE by the sequencer and set the bus TX and RX MSBs. The original MOVE and WRITE have all MSBs = 0.

  1. MOVE - MSBs TX=1, RX=0
  2. MOVE - MSBs TX=0, RX=1
  3. MOVE - MSBs TX=1, RX=1
  4. WRITE - MSBs RX=1

Bus

Up to 15 devices can read the bus and 16 write to it. Devices that can read the bus (RX):

  1. NONE - Nothing reads this so that bytes can be popped from the stack without them going anywhere.
  2. STACK-PUSH - Stack controller (Push)
  3. ALU-A - ALU latch A
  4. ALU-B - ALU latch B
  5. GOTO-A - Control unit - Program counter GOTO latch A (first byte)
  6. GOTO-B - Control unit - Program counter GOTO latch B (second byte)
  7. GOTO-DECIDER - Control unit - GOTO decider latch (For GOTO-IF)
  8. GPRAM - GPRAM - Write
  9. GPRAM-INC-ADDR - GPRAM - Write (++ address)
  10. GPRAM-ADDR-A - GPRAM - Address bits 0 - 7
  11. GPRAM-ADDR-B - GPRAM - Address bits 8 - 15
  12. GPIO-WRITE-A - Writes to GPIO output pins 0 - 7
  13. OFFSET-WRITE - Replaces value in stack at ToS - offset
  14. SET-STACK-OFFSET - Sets the stack offset byte
  15. ALU-C-IN - ALU latch for carry and borrow, only LSB is used. Make sure this is always zero when not being used otherwise additions will be wrong.
  16. GPIO-WRITE-B - Writes to GPIO output pins 8 - 15
  17. INT-GOTO-A - Interrupt GOTO A
  18. INT-GOTO-B - Interrupt GOTO B
  19. VECTORS-A - Vector graphics A input
  20. VECTORS-B - Vector graphics B input
  21. VECTORS-C - Vector graphics C input
  22. VECTORS-D - Vector graphics D input
  23. INT-AND-MAIN-TIMER-ADDRESS - Bits 0 - 1 address 1 of the 4 interrupt timers. Bit 2 will reset the addressed counter to 0.
  24. INT-TIMER-CONFIG-MAX - Sets the start value of one of the interrupt timers
  25. INT-TIMER-CONFIG-TIMEBASE-AND-ENABLE - Configures one of the interrupt timers, see timer_board.md
  26. FLASH - Flash programming interface, same as the arduino connection
  27. RX-26 - Expansion RX 25

...

  1. RX-31 - Expansion RX 31

Devices that can write to the bus (TX):

  1. STACK-POP - Stack controller (pop)
  2. OFFSET-READ - Reads value from stack at ToS - offset, does not affect the ToS
  3. ALU - ALU output
  4. Control unit instruction bits 4 - 11, used for the WRITE instruction
  5. GPRAM - GPRAM - Read
  6. GPRAM-INC-ADDR - GPRAM - Read (++ address)
  7. GPRAM-ADDR-A - GPRAM - Address bits 0 - 7
  8. GPRAM-ADDR-B - GPRAM - Address bits 8 - 15
  9. GPIO-READ-A - Reads GPIO input pins 0 - 7
  10. MAIN-TIMER - 8 bits of the main timer, addressed by INT-AND-MAIN-TIMER-ADDRESS
  11. INT-TIMER - Current value of 1 of the 4 interrupt timers, addressed by INT-AND-MAIN-TIMER-ADDRESS
  12. GPIO-READ-B - Reads GPIO input pins 8 - 15
  13. INT-CODE - Most recent interrupt code, will be cleared upon read
  14. INT-COUNT - Number of interrupts in queue, will overflow past 255
  15. GET-STACK-OFFSET - Retrieves stack offset, needed to save state during interrupt
  16. GET-GOTO-A - Read GOTO Latch A
  17. GET-GOTO-B - Read GOTO Latch B
  18. TX-17 - Expansion TX 17

...

  1. TX-31 - Expansion TX 31

The Stack

The stack will simply be a piece of memory seperate from the GPRAM and managed by hardware, its has 32k x 8-bit words.

There will be two ways to access the stack:

  1. Push and Pop
  2. Using the current ToS pointer - stack offset (OFFSET-WRITE and OFFSET-READ) (does not change ToS). The stack offset will be a 1-byte number set from the bus (SET-STACK-OFFSET) and will not affect pushes and pops.

ALU

The ALU uses 2 8-bit latches for input and has 1 output. The specific operation it does is controlled by 4 bits (2^4 = 16 operations). All operations that result in a boolean output all 0s except for the result which is the LSB.

  1. ADD - Add
  2. ADD-C - Addition carry output (just the LSB will be set), this can be written directly into ALU-C-IN
  3. NOT - Bitwise NOT (latch A)
  4. OR - Bitwise OR
  5. AND - Bitwise AND
  6. XNOR - Bitwise XNOR, whether each pair of bits are equal
  7. SHIFT - Bitshifts A left by the first 3 bits of B, bits that go off the end DO wrap around.
  8. EQ - Whether bytes are equal
  9. A - Contents of A latch
  10. B - Contents of B latch
  11. EXT-10 - Extension (not implemented)
  12. EXT-11 - Extension (not implemented)
  13. EXT-12 - Extension (not implemented)
  14. EXT-13 - Extension (not implemented)
  15. EXT-14 - Extension (not implemented)
  16. EXT-15 - Extension (not implemented)

Flow Control

There are four instructions for flow control: GOTO, GOTO-IF, CALL, and RETURN.

GOTO and GOTO-IF

A GOTO instruction is used to jump to anywhere in the program. it uses the two 8-bit latches (GOTO-A and GOTO-B) to set the 16-bit program counter. Due to how the hardware is set up, the PC will be incremented after each goto instruction. This means that the previous address to where the execution should jump to must be used.

GOTO-IF is a conditional goto which will do what is described above only if the bit set by GOTO-DECIDER from the LSB of the bus is 1, otherwise it does nothing. This is the only instruction that allows the computer to "branch" or "make decisions".

There are macros, @goto(anchor_name) and @goto_if(anchor_name) that make GOTOs a lot easier.

Functions and the call stack

Functions in the machine code are defined by CALL and RETURN instructions. To call a function, make sure the correct pointer to the beginning of the function is stored in the control unit goto A and B latches. Then use the CALL instruction which is basically a GOTO but will first put the current program counter value onto the call stack as the return address. The return instruction pops a return address off of the call stack and continues execution.

There is a macro in the assembly language, @call(function_name) that makes calling a lot easier.

The call stack is a seperate stack memory containing 256 (1 byte address size) 16-bit words. Each word will be a return address - where to set the program counter during a RETURN instruction.

I/O

There are 16 input and 16 seperate output pins accessible with the GPIO-READ-A, -B and GPIO-WRITE-A, -B bus sources/destinations.

Writing to the display

The display has 32 x 32 LEDs, any given row of 8 pixels are written all at once with one byte. These rows of 8 are addressed by a 7-bit number starting at the top-left and going across for 4 per row (32 / 8 = 4) for each of the 32 rows of the display. The display currently is attached to the gpio-write a and b outputs with gpio-write-a being the address (MSB is ignored) and gpio-write-b being the data. The signal to write the address/data to the display's memory is sent by the hardware when gpio-write-b is written to, meaning the address should be written first and then the data.

General purpose static-RAM (GPRAM)

This piece of memory does not have any hardware protection like the stack and can be writen to and read from at any location. It will have a 16-bit address by 8-bit word size (65,536 bytes) just like the stack.

Its address can be optionally incremented upon reads/writes and can be directly set from the bus (GPRAM-ADDR-A and GPRAM-ADDR-B). For the instructions where the address is incremented, that will happen after the read/write.

Design software

First, everything was built and tested in a digital circuit simulator Rusty Logic which allowed my to check that all the timing diagrams would be followed.

Once everything was working in Rusty Logic, KiCad was used to layout all of the actual PCBs.

Parts

56
QtyValueFootprintReferences
13Rcustom_footprint_library:0.4_pitch_resistorR1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13
6SW_Pushcustom_footprint_library:2_pin_buttonSW2, SW3, SW4, SW5, SW6, SW7
5CCapacitor_THT:C_Rect_L11.0mm_W4.2mm_P10.00mm_MKTC2, C3, C4, C5, C6
5~Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_VerticalU15, U16, U19, U20, U22
5~Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalU1, U3, U9, U12, U13
4Conn_01x01_PinConnector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_VerticalJ1, J2, J3, J4
4~Connector_PinHeader_2.54mm:PinHeader_1x16_P2.54mm_VerticalU5, U6, U7, U8
3LEDLED_THT:LED_D3.0mmD1, D2, D3
2~Package_DIP:DIP-16_W7.62mmU2, U4
2~custom_footprint_library:crystal_dip_14U10, U11
1CCapacitor_THT:CP_Radial_D5.0mm_P2.50mmC1
1R_Potentiometercustom_footprint_library:panel_mount_potRV1
1SW_PushButton_Switch_THT:SW_PUSH_6mmSW1
1~Connector_PinHeader_2.54mm:PinHeader_1x10_P2.54mm_HorizontalU21
1~Package_DIP:DIP-14_W7.62mmU14
1~custom_footprint_library:manual_clock_switch_sideU17
1~Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalU18

Questions

How big is the Control panel PCB?

It measures 126.5 × 84 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Control panel use?

56 parts. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Control panel KiCad files?

From the emperor-hadrian/stack_machine repository on GitHub, at the commit this page was made from: the board is kicad/boards_version_1/control_panel/control_panel.kicad_pcb. PCBKit opens the board in the browser, with nothing to install.

Can I use the Control panel design in my own project?

Its repository states no licence, so its author keeps all rights: ask emperor-hadrian before reusing the design.

More from emperor-hadrian/stack_machine

12
  • 2 layers296 × 139 mmALU, the printed circuit board in 3D

    ALU

    emperor-hadrian/stack_machine

    Design for a DIY computer

    59 parts
  • 2 layers201 × 169 mmGpram, the printed circuit board in 3D

    Gpram

    emperor-hadrian/stack_machine

    Design for a DIY computer

    55 parts
  • 2 layers208 × 159 mmStack controller, the printed circuit board in 3D

    Stack controller

    emperor-hadrian/stack_machine

    Design for a DIY computer

    53 parts
  • 2 layers268 × 99.1 mmLed matrix controller, the printed circuit board in 3D

    Led matrix controller

    emperor-hadrian/stack_machine

    Design for a DIY computer

    52 parts
  • 2 layers165 × 118 mmControl unit, the printed circuit board in 3D

    Control unit

    emperor-hadrian/stack_machine

    Design for a DIY computer

    50 parts
  • 2 layers190 × 125 mmBus, the printed circuit board in 3D

    Bus

    emperor-hadrian/stack_machine

    Design for a DIY computer

    48 parts
  • 2 layers220 × 172 mmLed matrix, the printed circuit board in 3D

    Led matrix

    emperor-hadrian/stack_machine

    Design for a DIY computer

    45 parts
  • 2 layers157.5 × 127.5 mmProg mem, the printed circuit board in 3D

    Prog mem

    emperor-hadrian/stack_machine

    Design for a DIY computer

    39 parts
  • 2 layers100 × 100 mmClock, the printed circuit board in 3D

    Clock

    emperor-hadrian/stack_machine

    Design for a DIY computer

    34 parts
  • 2 layers140.5 × 100 mmCall stack, the printed circuit board in 3D

    Call stack

    emperor-hadrian/stack_machine

    Design for a DIY computer

    27 parts

Similar boards

  • 2 layers90 × 38 mmLCD OLinuXino-5TS Rev.B, the printed circuit board in 3D

    LCD OLinuXino-5TS Rev.B

    OLIMEX/OLINUXINO

    OLINUXINO is Open Source / Open Hardware, low cost from EUR 24 Linux Industrial grade Single Board Computer capable to operate -25+85C

    56 parts1.5k
  • 2 layers50.4 × 48.4 mmDistortion, the printed circuit board in 3D

    Distortion

    hackclub/OnBoard

    💡 Join 1,000 teenagers and make your first PCB with a $100 grant!

    56 parts915
  • 2 layers27 × 24.7 mmKawaiiSD, the printed circuit board in 3D

    KawaiiSD

    mackieks/Kawaii

    Tiny, beautiful metal Wii keychain

    56 parts374
  • 2 layers123.9 × 94.4 mmRoba L, the printed circuit board in 3D

    Roba L

    kumamuk-git/roBa

    56 parts363GPL-3.0
  • 2 layers120.6 × 85.5 mmKLOTZ, the printed circuit board in 3D

    KLOTZ

    GEIGEIGEIST/KLOTZ

    KLOTZ is 34 keys column-staggered split keyboard. It uses an encoder and three status LEDs on each side.

    56 parts287GPL-3.0
  • 2 layers136 × 91.7 mmOne, the printed circuit board in 3D

    One

    ergonautkb/one

    Ergonaut One is an open-source ergonomic wireless split mechanical keyboard designed by Ergonaut Keyboards.

    56 parts210CERN-OHL-P-2.0
  • 2 layers78.5 × 69 mmKicad cpu board, the printed circuit board in 3D

    Kicad cpu board

    matthewcieplak/super-sixteen

    Code and schematics for the Super Sixteen Eurorack sequencer

    56 parts171
  • 2 layers45 × 45 mmAeroq Hardware v3, the printed circuit board in 3D

    Aeroq Hardware v3

    EnriqueNeyra/Aeroq

    An Indoor Air Quality Monitor Powered by ESP32, SCD40, and SEN54

    56 parts130