Skip to the content
PCBKitNew board
2 layers428 × 293 mmVector digital controller, the printed circuit board in 3D

Vector digital controller

emperor-hadrian/stack_machine

Design for a DIY computer

Size
428 × 293 mm
Copper layers
2
Thickness
1.6 mm
Parts
156
Nets
598
Pads
2,005
Tracks, vias
7,641, 783
Pours
2
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
11 Mar 2024
Updated
26 Sep 2026

Overview

Vector digital controller 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 428 × 293 mm with 156 parts on 598 nets, routed with 7,641 tracks and 783 vias.

Its parts include 137 ICs and 19 resistors.

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

156
QtyValueFootprintReferences
48~Package_DIP:DIP-14_W7.62mmU100, U101, U102, U103, U104, U105, U106, U107, U112, U113, U114, U115, U116, U117, U120, U123 +32
29~Package_DIP:DIP-20_W7.62mmU1, U10, U11, U16, U19, U20, U21, U33, U35, U37, U39, U40, U41, U139, U140, U141 +13
28~custom_footprint_library:jumperU54, U62, U70, U71, U75, U76, U77, U78, U79, U80, U108, U109, U110, U111, U118, U122 +12
20~Package_DIP:DIP-16_W7.62mmU4, U14, U17, U22, U23, U34, U48, U49, U53, U55, U56, U57, U66, U67, U121, U421 +4
19Rcustom_footprint_library:0.4_pitch_resistorR1, R2, R3, R4, R5, R6, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19 +3
4~Package_DIP:DIP-24_W7.62mmU32, U44, U51, U52
3~Package_DIP:DIP-28_W15.24mmU3, U12, U36
1~Connector_PinHeader_2.54mm:PinHeader_1x23_P2.54mm_VerticalU2
1~custom_footprint_library:crystal_dip_14U72
1~Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalU96
1~Connector_PinHeader_2.54mm:PinHeader_1x12_P2.54mm_VerticalU18
1~Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_VerticalU119

Questions

How big is the Vector digital controller PCB?

It measures 428 × 293 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Vector digital controller use?

156 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 Vector digital controller KiCad files?

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

Can I use the Vector digital controller 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 layers126.5 × 84 mmControl panel, the printed circuit board in 3D

    Control panel

    emperor-hadrian/stack_machine

    Design for a DIY computer

    56 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 layers65 × 100 mmJOVE, the printed circuit board in 3D

    JOVE

    minisystem/JOVE

    Eurorack multimode filter inspired by the Roland Jupiter-6

    156 parts109
  • 2 layers85 × 56.5 mmAIOR, the printed circuit board in 3D

    AIOR

    GBert/misc

    miscellaneous stuff / unsorted

    156 parts99
  • 2 layers109 × 71 mmGamma split, the printed circuit board in 3D

    Gamma split

    ahtn/keyboard_pcb

    156 parts96
  • 2 layers313.3 × 131.6 mmKBIC65, the printed circuit board in 3D

    KBIC65

    b-karl/KBIC65

    65% keyboard PCB with ProMicro footprint. Through-hole kit design with focus on wireless.

    156 parts67MIT
  • 2 layers191.2 × 129.5 mmJonkey v2, the printed circuit board in 3D

    Jonkey v2

    AtomicJon/jonkey

    The JONKEY is a columnar split keyboard created using ergogen.

    156 parts33
  • 2 layers361 × 120.7 mmTrifecta, the printed circuit board in 3D

    Trifecta

    swiftrax/Trifecta

    Open source Alice like mechanical keyboard with arrow keys and support of up to 3 rotary encoders

    156 parts32GPL-2.0
  • 2 layers90 × 38 mmKampela, the printed circuit board in 3D

    Kampela

    Alzymologist/Kampela

    Hardware signer and key storage for Substrate ecosystem

    156 parts21GPL-3.0