
Board 722039m
fabio-d/minitel-native
Software and hardware tools to run native programs on the Minitel

8-bit Virtual Machine written in C
UVM is an open-source printed circuit board by sam159, from the sam159/uVM repository on GitHub, published under the Apache-2.0 licence. It is a 2-layer board of 245 × 126 mm with 205 parts on 359 nets, routed with 2,415 tracks and 43 vias.
It is built around the ATMEGA328P-PU, A13 and 74HC595, with the 74HC165D, 23LCV512-E/P and L7805 among its other parts. Its parts include 122 diodes, 23 ICs, 22 switches, 7 capacitors and 5 resistors. It belongs with the retro computing and games boards and the AVR (ATmega, ATtiny) boards of this library.
This is an 8-bit virtual machine with 16-bit addressing. It is RISC-style with no direct operations on memory, instead operations are done on one of 16 8-bit registers with 6 16-bit registers mapped over them.
An ASM language is defined and implemented for this VM.
CMake and a C build toolchain are required to build. On a debian-based system install build-essential and cmake packages.
# setup makefiles (run once)
$ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -S . -B ./cmake-build-release
# build project
$ cmake --build ./cmake-build-release --target uVMUsage is printed with no options given.
$ ./cmake-build-release/uVM
Usage:
uVM program.bin # load at 0x0000
uVM -a 0x100 file1.bin -a 0x200 file2.bin # multiple files at absolute addresses
uVM -p 0x100 program.bin # set PC to 0x100
uVM -c file.asm [-o output.bin] # assemble into binary formatCompiling and running asm files can be achieved with the following.
$ ./cmake-build-release/uVM -c programs/basic.asm -o programs/basic.bin
Assembling 'programs/basic.asm' -> 'programs/basic.bin'
$ /cmake-build-release/uVM programs/basic.bin
Loaded 'programs/basic.bin' at 0x0000 (272 bytes)
VM Halted with code 0
PC: 0110 carry: 0 halted: 1 haltcode: 0000 (0)
R0: 00 (000) R4: 02 (002) R8: 00 (000) RC: 00 (000)
R1: 01 (001) R5: 00 (000) R9: 00 (000) RD: 00 (000)
R2: 64 (100) R6: 00 (000) RA: 00 (000) RE: 00 (000)
R3: 00 (000) R7: 00 (000) RB: 00 (000) RF: 00 (000)
RXA: 200 (00512) RXB: 00 (00000) RXE: 00 (00000)
RXC: 00 (00000) RXF: 00 (00000) RXD: 00 (00000)R0–RF), 8-bit each.RX0-RXF) mapped over the 8-bit registers.
RX0-RX9 mirroring R0-RF extended to 16-bitsRXA-RXF mapped to pairs of 8-bit registersSome instructions can use two 8-bit registers as one 16-bit register for addressing.
The upper 12 registers form six extended 16-bit address registers (big-endian, high byte : low byte):
| Alias | Registers |
|---|---|
| RXA | R4 : R5 |
| RXB | R6 : R7 |
| RXC | R8 : R9 |
| RXD | RA : RB |
| RXE | RC : RD |
| RXF | RE : RF |
vm_get_rx() returns the 16-bit value of a register: 0x0-0x9 return the 8-bit variant, with 0xA-0xF returning the above registers.
readAddr and writeAddr on the VM struct.All instructions are two bytes (big-endian). The upper four bits are the opcode. Three operand formats share the lower 12 bits:
| Format | Layout (16 bits) | Description |
|---|---|---|
| Q | [op:4][rd:4][imm8:8] | Destination register + 8-bit immediate |
| S | [op:4][rd:4][rx:4][ry:4] | Destination + two source registers |
| T | [op:4][rd:4][rx:4][imm4:4] | Destination + source register + 4-bit immediate |
| V | [op:4][imm12:12] | 12-bit immediate |
Operand terms
exitcode - sets the vm exitcoderd/rx/ry - 8-bit registerrdx - rd with extended register supportimm4 - immediate value 4-bitimm4_s - immediate value 4-bitimm4_s_x2 - immediate value 4-bit multiplied by twotest - a conditional jump typeimm8 - immediate value 8-bitimm8_s - signed immediate value 8-bitimm8_s_x2 - signed immediate value 8-bit multiplied by twoimm12 - immediate value 12-bitimm12_s - signed immediate value 12-bitimm12_s_x2 - signed immediate value 12-bit multiplied by twocarry - carry flagAll jumps are in words/instructions.
| Op | Mnemonic | Format | Operation | Description |
|---|---|---|---|---|
0 | HLT | Q | exitcode ← rd + imm8 | Halt the VM. Sets halted = true, and the exit code to rd + imm8 |
1 | LDA | T | rd ← [rdx + imm4] | Load byte from memory at 16-bit address rdx + imm4 into rd |
2 | STA | T | [rdx + imm4] ← rx | Store rx to memory at 16-bit address rdx + imm4 |
3 | LDI | Q | rd ← imm8 | Load imm8 into rd |
4 | ADD | S | rd ← rx + ry | 8-bit add. Sets carry on overflow |
5 | ADC | S | rd ← rx + ry + carry | 8-bit add with carry. Sets carry on overflow |
6 | SUB | S | rd ← rx - ry | 8-bit subtract. Clears carry |
7 | SBC | S | rd ← rx - ry - carry | 8-bit subtract with borrow. Propagates borrow bit-by-bit into carry |
8 | NOT | T | rd ← ~rx | Bitwise NOT of rx |
9 | BIT | T | rd ← rd OP rx | Bitwise operation on rd using rx. OP: 0=AND, 1=OR, 2=XOR, 4=MOD |
A | SHL | T | rd ← rx << imm4 | Logical left shift by imm bits |
B | SHR | T | rd ← rx >> imm4 | Logical right shift by imm bits |
C | JMP | V | PC ← PC + imm12_s_x2 | Relative jump. Update PC with imm12_s_x2 |
D | JPF | Q | PC ← rdx + imm8_s_x2 | Far jump. Set PC to the value in rdx with imm8_s_x2 value |
E | JNZ | Q | PC ← PC + imm8_s_x2 if rd != 0 | Conditional jump. Add imm8_s_x2 to PC if rd is not zero |
F | JPC | T | PC ← PC + 2 if !test(rd,rx) | Conditional jump. Skips the next instruction if test passes for values in rd and rx |
Test types, used for comparing values in rd and rx.
Tests are mapped into a 4-bit value and can be in any combination
3 2 1 0
| | | |
| | | +-- Equality
| | +------ Less Than
| +---------- Greater Than
+-------------- Negate ResultSetting bits 0–3 will pass for any value, negating it will not pass for any value, similarly not setting any bits will not pass for any value.
| Mnemonic | Number | Binary | Test |
|---|---|---|---|
| EQ | 1 | 0001 | Equals |
| ~EQ | 9 | 1001 | Not equals |
| LT | 2 | 0010 | Less than |
| ~LT | 10 | 1010 | Not less than |
| LTE | 3 | 0011 | Less than or equal |
| ~LTE | 11 | 1011 | Not less than or equal |
| GT | 4 | 0100 | Greater than |
| ~GT | 12 | 1100 | Not greater than |
| GTE | 5 | 0101 | Greater than or equal |
| ~GTE | 13 | 1101 | Not greater than or equal |
Errors are reported via the error hook and halt the VM:
| Code | Constant | Condition |
|---|---|---|
| 1 | VM_ERR_MISALIGN | PC is not word-aligned on instruction fetch. |
| 2 | VM_ERR_UNKNOWN_OP | Opcode is not recognized (0–F). Redundant, exists for completeness. |
| 3 | VM_ERR_OUT_OF_BOUNDS | Memory access address >= 0x10000. |
| 4 | VM_ERR_JUMP_SELF | An jump instruction jumped to itself |
| 5 | VM_ERR_INVALID_BIT_OP | BIT instruction has invalid operation code (not 0, 1, 2, or 4). |
vm_step() fetches one 2-byte instruction from readAddr(PC).rd via vm_put_r().vm_step() repeatedly until vm->halted is true.ASM
:h/:lVM
| Qty | Value | Footprint | References |
|---|---|---|---|
| 122 | LED | LED_THT:LED_D5.0mm | D1, D10, D11, D100, D101, D102, D103, D104, D105, D109, D110, D111, D112, D113, D114, D115 +106 |
| 16 | 74HC595 | Package_DIP:DIP-16_W7.62mm | U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19 |
| 15 | 330 | Resistor_THT:R_Array_SIP9 | RN1, RN2, RN3, RN4, RN5, RN6, RN7, RN8, RN9, RN10, RN11, RN12, RN13, RN14, RN16 |
| 5 | 10K | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal | R1, R2, R3, R4, R5 |
| 3 | 100nF | Capacitor_THT:C_Disc_D6.0mm_W2.5mm_P5.00mm | C1, C4, C7 |
| 3 | 10K | Resistor_THT:R_Array_SIP9 | RN17, RN18, RN19 |
| 3 | 74HC165 | Package_DIP:DIP-16_W7.62mm | U20, U21, U22 |
| 2 | 6pF | Capacitor_THT:C_Disc_D6.0mm_W2.5mm_P5.00mm | C5, C6 |
| 1 | 1000uF | Capacitor_THT:CP_Radial_D8.0mm_P3.80mm | C2 |
| 1 | 10K | Potentiometer_THT:Potentiometer_Alps_RK09K_Single_Vertical | RV1 |
| 1 | 16MHz | Crystal:Crystal_HC18-U_Vertical | Y1 |
| 1 | 220nF | Capacitor_THT:C_Disc_D4.7mm_W2.5mm_P5.00mm | C3 |
| 1 | 23LCV512 | Package_DIP:DIP-8_W7.62mm_Socket | U2 |
| 1 | 3V CR2032 | Battery:BatteryHolder_Keystone_105_1x2430 | BT1 |
| 1 | A0 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW20 |
| 1 | A1 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW19 |
| 1 | A10 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW10 |
| 1 | A11 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW9 |
| 1 | A12 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW7 |
| 1 | A13 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW5 |
| 1 | A14 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW3 |
| 1 | A15 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW1 |
| 1 | A2 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW18 |
| 1 | A3 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW17 |
| 1 | A4 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW16 |
| 1 | A5 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW15 |
| 1 | A6 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW14 |
| 1 | A7 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW13 |
| 1 | A8 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW12 |
| 1 | A9 | uvm:TOGGLE_SPDT_ON_ON_2MS | SW11 |
| 1 | ATmega328P-PU | Package_DIP:DIP-28_W7.62mm_Socket | U1 |
| 1 | Barrel_Jack | Connector_BarrelJack:BarrelJack_Horizontal | J1 |
| 1 | Deposit / Next | uvm:TOGGLE_SPDT_ON_ON_2MS | SW8 |
| 1 | Examine / Next | uvm:TOGGLE_SPDT_ON_ON_2MS | SW6 |
| 1 | FDTI Serial | Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_Vertical | J3 |
| 1 | ICSP | Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Vertical | J2 |
| 1 | L7805 | Package_TO_SOT_THT:TO-220-3_Horizontal_TabDown | U3 |
| 1 | MCP23017_SP | Package_DIP:DIP-28_W7.62mm | U23 |
| 1 | PortAB | Connector_PinSocket_2.54mm:PinSocket_2x08_P2.54mm_Vertical | J5 |
| 1 | Power | Connector_PinSocket_2.54mm:PinSocket_2x02_P2.54mm_Vertical | J4 |
| 1 | REG Select | uvm:TOGGLE_SPDT_ON_ON_2MS | SW22 |
| 1 | RESET | Button_Switch_THT:SW_PUSH_6mm_H5mm | SW21 |
| 1 | Reset / Clear | uvm:TOGGLE_SPDT_ON_ON_2MS | SW4 |
| 1 | Run / Step | uvm:TOGGLE_SPDT_ON_ON_2MS | SW2 |
It measures 245 × 126 mm and has 2 copper layers, 1.6 mm thick.
205 parts, built around the ATMEGA328P-PU, A13, 74HC595 and 74HC165D. 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.
From the sam159/uVM repository on GitHub, at the commit this page was made from: the board is pcb/uvm.kicad_pcb. PCBKit opens the board in the browser, with nothing to install.
Its repository publishes it under the Apache-2.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

fabio-d/minitel-native
Software and hardware tools to run native programs on the Minitel





stonedDiscord/Automatenplatinen
Reverse engineerte Hardware aus deutschen Spielautomaten.


comakingspace/FlipDotDisplay
They were bought at the Makerfaire Hannover 2016.