From 0cd2dc2062063f342acb16b9deac964e8c6f8f88 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Fri, 5 Jun 2026 10:23:57 -0300 Subject: [PATCH] test(chipbus): Phase 3 core - Z80 + ROM + RAM + address decode over the bus The architectural heart of the retro computer, proven on real chips. A Z80, a 32K ROM, a 64K RAM and an inverter (address-decode glue) are wired chip-to-chip over a shared address + data bus, no board: ROM at 0x0000-0x7FFF rom.CE = A15 RAM at 0x8000-0xFFFF ram.CE = NOT A15 (the inverter chip) RD -> both OE ; WR -> RAM WE The ROM program writes 0x5A to RAM at 0x8000, clears A, reads it back, and HALTs only if the byte survived. HALT going low proves the full core works: the Z80 runs from ROM, the inverter decodes A15 to select RAM (the settle kernel drives the combinational glue across hops), and the RAM latches a write and returns it on a read over the shared tri-state bus, all within synchronous bus cycles. Adds z80-ram-rom.c (boot image) + ram-64k/inverter fixtures. 37 chipbus tests across 7 files pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../__tests__/chipbus-z80-ram-decode.test.ts | 134 ++++++++++++++++++ .../__tests__/fixtures/chipbus/inverter.wasm | Bin 0 -> 63291 bytes .../__tests__/fixtures/chipbus/ram-64k.wasm | Bin 0 -> 65727 bytes .../fixtures/chipbus/z80-ram-rom.wasm | Bin 0 -> 54415 bytes .../sdk/examples/z80-ram-rom.c | 113 +++++++++++++++ .../sdk/examples/z80-ram-rom.chip.json | 9 ++ 6 files changed, 256 insertions(+) create mode 100644 frontend/src/__tests__/chipbus-z80-ram-decode.test.ts create mode 100644 frontend/src/__tests__/fixtures/chipbus/inverter.wasm create mode 100644 frontend/src/__tests__/fixtures/chipbus/ram-64k.wasm create mode 100644 frontend/src/__tests__/fixtures/chipbus/z80-ram-rom.wasm create mode 100644 test/test_custom_chips/sdk/examples/z80-ram-rom.c create mode 100644 test/test_custom_chips/sdk/examples/z80-ram-rom.chip.json diff --git a/frontend/src/__tests__/chipbus-z80-ram-decode.test.ts b/frontend/src/__tests__/chipbus-z80-ram-decode.test.ts new file mode 100644 index 00000000..6528428e --- /dev/null +++ b/frontend/src/__tests__/chipbus-z80-ram-decode.test.ts @@ -0,0 +1,134 @@ +/** + * Phase 3 computer-core LIVE proof (project/multichip-bus/): a real Z80 with + * ROM + RAM + address-decode glue, all chip-to-chip over a shared bus, no board. + * + * Memory map via real glue logic: + * ROM (32K) at 0x0000-0x7FFF -> rom.CE = A15 (selected when A15=0) + * RAM (64K) at 0x8000-0xFFFF -> ram.CE = NOT A15 (an inverter chip) + * both data outputs gated by RD (OE); RAM write gated by WR (WE). + * + * The ROM program writes 0x5A to RAM at 0x8000, clears A, reads it back, and + * HALTs only if the byte survived (else it spins). HALT going low proves: the + * Z80 ran from ROM, the inverter decoded A15 to select RAM (Phase 2 settle + * drives the combinational glue), the RAM latched a write and returned it on a + * read over the shared bus (Phase 1 tri-state), all within synchronous bus + * cycles (Phase 2 settle-before-read). + * + * Fixtures compiled with wasi-sdk; skips if absent. ram-64k.wasm / inverter.wasm + * are built from the committed examples; z80-ram-rom.c is the boot image. + */ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { readFileSync, existsSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { PinManager } from '../simulation/PinManager'; +import { ChipInstance } from '../simulation/customChips/ChipRuntime'; +import { + resolveChipNetKey, + setChipBusEnabledForTest, + resetChipNetIndexForTest, + type ChipNetState, +} from '../simulation/customChips/chipNets'; +import { syntheticChipPin } from '../simulation/customChips/syntheticPins'; +import { resetBusNets } from '../simulation/customChips/busNets'; + +const f = (n: string) => fileURLToPath(new URL(`./fixtures/chipbus/${n}`, import.meta.url)); +const paths = { + z80: f('z80.wasm'), + rom: f('z80-ram-rom.wasm'), + ram: f('ram-64k.wasm'), + inv: f('inverter.wasm'), +}; +const haveFixtures = Object.values(paths).every(existsSync); + +const range = (n: number) => Array.from({ length: n }, (_, i) => i); + +const Z80_PINS = [ + ...range(16).map((i) => `A${i}`), + ...range(8).map((i) => `D${i}`), + 'M1', 'MREQ', 'IORQ', 'RD', 'WR', 'RFSH', 'HALT', 'WAIT', + 'INT', 'NMI', 'RESET', 'BUSREQ', 'BUSACK', 'CLK', 'VCC', 'GND', +]; +const ROM_PINS = [...range(15).map((i) => `A${i}`), ...range(8).map((i) => `D${i}`), 'CE', 'OE', 'VCC', 'GND']; +const RAM_PINS = [...range(16).map((i) => `A${i}`), ...range(8).map((i) => `D${i}`), 'CE', 'OE', 'WE', 'VCC', 'GND']; +const INV_PINS = ['IN', 'OUT']; + +const W: ChipNetState['wires'] = []; +const wire = (a: string, ap: string, b: string, bp: string) => + (W as { start: { componentId: string; pinName: string }; end: { componentId: string; pinName: string } }[]).push( + { start: { componentId: a, pinName: ap }, end: { componentId: b, pinName: bp } }, + ); +// Address bus A0..A14 shared by Z80, ROM and RAM. +for (const i of range(15)) { + wire('z80', `A${i}`, 'rom', `A${i}`); + wire('z80', `A${i}`, 'ram', `A${i}`); +} +// A15: top RAM address bit, ROM chip-select, and the inverter input (decode). +wire('z80', 'A15', 'ram', 'A15'); +wire('z80', 'A15', 'rom', 'CE'); +wire('z80', 'A15', 'inv', 'IN'); +// Data bus shared by all three memory-side chips. +for (const i of range(8)) { + wire('z80', `D${i}`, 'rom', `D${i}`); + wire('z80', `D${i}`, 'ram', `D${i}`); +} +// Control: RD -> both output-enables; WR -> RAM write-enable; !A15 -> RAM CE. +wire('z80', 'RD', 'rom', 'OE'); +wire('z80', 'RD', 'ram', 'OE'); +wire('z80', 'WR', 'ram', 'WE'); +wire('inv', 'OUT', 'ram', 'CE'); + +const STATE: ChipNetState = { + wires: W, + components: [ + { id: 'z80', metadataId: 'custom-chip' }, + { id: 'rom', metadataId: 'custom-chip' }, + { id: 'ram', metadataId: 'custom-chip' }, + { id: 'inv', metadataId: 'custom-chip' }, + ], + boards: [], +}; + +const pinKey = (chipId: string, pin: string): number => + resolveChipNetKey(STATE, chipId, pin) ?? syntheticChipPin(chipId, pin); +const wiresFor = (chipId: string, pins: string[]): Map => + new Map(pins.map((p) => [p, pinKey(chipId, p)] as [string, number])); + +describe.skipIf(!haveFixtures)('chipbus Phase 3 core — Z80 + ROM + RAM + address decode', () => { + beforeEach(() => { + setChipBusEnabledForTest(true); + resetChipNetIndexForTest(); + resetBusNets(); + }); + afterEach(() => { + setChipBusEnabledForTest(null); + resetChipNetIndexForTest(); + resetBusNets(); + }); + + it('runs from ROM, round-trips RAM via the inverter-decoded bus, and HALTs', async () => { + const pm = new PinManager(); + const z80 = await ChipInstance.create({ wasm: new Uint8Array(readFileSync(paths.z80)), componentId: 'z80', pinManager: pm, wires: wiresFor('z80', Z80_PINS) }); + z80.start(); + const rom = await ChipInstance.create({ wasm: new Uint8Array(readFileSync(paths.rom)), componentId: 'rom', pinManager: pm, wires: wiresFor('rom', ROM_PINS) }); + rom.start(); + const ram = await ChipInstance.create({ wasm: new Uint8Array(readFileSync(paths.ram)), componentId: 'ram', pinManager: pm, wires: wiresFor('ram', RAM_PINS) }); + ram.start(); + const inv = await ChipInstance.create({ wasm: new Uint8Array(readFileSync(paths.inv)), componentId: 'inv', pinManager: pm, wires: wiresFor('inv', INV_PINS) }); + inv.start(); + + const halt = pinKey('z80', 'HALT'); + expect(pm.getPinState(halt)).toBe(true); // running at power-on + + pm.triggerPinChange(pinKey('z80', 'BUSREQ'), true); + pm.triggerPinChange(pinKey('z80', 'WAIT'), true); + pm.triggerPinChange(pinKey('z80', 'RESET'), true); + + z80.tickTimers(100_000n); // ~400 clocks; the program halts after ~7 instructions + + // HALT low: the RAM write+read round-trip survived -> the whole computer core + // (CPU + ROM + RAM + inverter decode) works over the shared chip-to-chip bus. + expect(pm.getPinState(halt)).toBe(false); + + z80.dispose(); rom.dispose(); ram.dispose(); inv.dispose(); + }); +}); diff --git a/frontend/src/__tests__/fixtures/chipbus/inverter.wasm b/frontend/src/__tests__/fixtures/chipbus/inverter.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1e36b76653413a36507312d873eb1400f9af1108 GIT binary patch literal 63291 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 YV%?S}%ax&WDTs(y%ukJuR7%kMAEsG5dH?_b literal 0 HcmV?d00001 diff --git a/frontend/src/__tests__/fixtures/chipbus/ram-64k.wasm b/frontend/src/__tests__/fixtures/chipbus/ram-64k.wasm new file mode 100644 index 0000000000000000000000000000000000000000..d957887c30225cd36e2a10fa83c25c2e9dc8075b GIT binary patch literal 65727 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 IwLm}ugH#E>bftE#(8x~s}s8gT0t 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 PKhKRV$6q-#lHLCWlgTSH literal 0 HcmV?d00001 diff --git a/test/test_custom_chips/sdk/examples/z80-ram-rom.c b/test/test_custom_chips/sdk/examples/z80-ram-rom.c new file mode 100644 index 00000000..e899adca --- /dev/null +++ b/test/test_custom_chips/sdk/examples/z80-ram-rom.c @@ -0,0 +1,113 @@ +/* + * z80-ram-rom — a rom-32k variant whose image is a Z80 RAM round-trip test, + * for the Phase 3 computer-core proof (project/multichip-bus/). Honours the + * full image (no 0xFF clamp) so the program can exceed 16 bytes. + * + * 0000: 3E 5A LD A, 0x5A + * 0002: 32 00 80 LD (0x8000), A ; write 0x5A to RAM at 0x8000 + * 0005: AF XOR A ; A = 0 + * 0006: 3A 00 80 LD A, (0x8000) ; read it back from RAM + * 0009: FE 5A CP 0x5A + * 000B: C2 10 00 JP NZ, 0x0010 ; mismatch -> fail loop (no HALT) + * 000E: 76 HALT ; success: RAM round-trip worked + * 0010: C3 10 00 JP 0x0010 ; fail: spin forever + * + * HALT only fires if the Z80 fetched the program from ROM (0x0000-0x7FFF), + * wrote+read RAM (0x8000-0xFFFF), and the byte survived — i.e. address decoding + * + RAM read/write over the shared bus all work. + */ +#include "velxio-chip.h" +#include +#include + +#define ROM_SIZE 0x8000 /* 32 KB */ + +static const uint8_t rom_image[ROM_SIZE] = { + [0x0000] = 0x3E, [0x0001] = 0x5A, + [0x0002] = 0x32, [0x0003] = 0x00, [0x0004] = 0x80, + [0x0005] = 0xAF, + [0x0006] = 0x3A, [0x0007] = 0x00, [0x0008] = 0x80, + [0x0009] = 0xFE, [0x000A] = 0x5A, + [0x000B] = 0xC2, [0x000C] = 0x10, [0x000D] = 0x00, + [0x000E] = 0x76, + [0x0010] = 0xC3, [0x0011] = 0x10, [0x0012] = 0x00, +}; + +typedef struct { + vx_pin a[15]; + vx_pin d[8]; + vx_pin ce; + vx_pin oe; + vx_pin vcc; + vx_pin gnd; + bool driving; +} chip_t; + +static chip_t G; + +static uint16_t read_addr(void) { + uint16_t v = 0; + for (int i = 0; i < 15; i++) if (vx_pin_read(G.a[i])) v |= (1u << i); + return v; +} + +static uint8_t image_byte(uint16_t addr) { + if (addr >= ROM_SIZE) return 0xFF; + return rom_image[addr]; /* honour the whole image; unset = 0x00 (NOP) */ +} + +static void drive_data(uint8_t v) { + for (int i = 0; i < 8; i++) { + vx_pin_set_mode(G.d[i], VX_OUTPUT); + vx_pin_write(G.d[i], (v >> i) & 1); + } + G.driving = true; +} + +static void release_data(void) { + if (!G.driving) return; + for (int i = 0; i < 8; i++) vx_pin_set_mode(G.d[i], VX_INPUT); + G.driving = false; +} + +static void update_outputs(void) { + int ce_low = (vx_pin_read(G.ce) == 0); + int oe_low = (vx_pin_read(G.oe) == 0); + if (ce_low && oe_low) { + drive_data(image_byte(read_addr())); + } else { + release_data(); + } +} + +static void on_pin_change(void* user_data, vx_pin pin, int value) { + (void)user_data; (void)pin; (void)value; + update_outputs(); +} + +void chip_setup(void) { + char name[4]; + for (int i = 0; i < 15; i++) { + name[0]='A'; + if (i<10) { name[1]='0'+i; name[2]=0; } + else { name[1]='1'; name[2]='0'+(i-10); name[3]=0; } + G.a[i] = vx_pin_register(name, VX_INPUT); + } + for (int i = 0; i < 8; i++) { + name[0]='D'; name[1]='0'+i; name[2]=0; + G.d[i] = vx_pin_register(name, VX_INPUT); + } + G.ce = vx_pin_register("CE", VX_INPUT); + G.oe = vx_pin_register("OE", VX_INPUT); + G.vcc = vx_pin_register("VCC", VX_INPUT); + G.gnd = vx_pin_register("GND", VX_INPUT); + G.driving = false; + + for (int i = 0; i < 15; i++) { + vx_pin_watch(G.a[i], VX_EDGE_BOTH, on_pin_change, 0); + } + vx_pin_watch(G.ce, VX_EDGE_BOTH, on_pin_change, 0); + vx_pin_watch(G.oe, VX_EDGE_BOTH, on_pin_change, 0); + + update_outputs(); +} diff --git a/test/test_custom_chips/sdk/examples/z80-ram-rom.chip.json b/test/test_custom_chips/sdk/examples/z80-ram-rom.chip.json new file mode 100644 index 00000000..2f26ed79 --- /dev/null +++ b/test/test_custom_chips/sdk/examples/z80-ram-rom.chip.json @@ -0,0 +1,9 @@ +{ + "schema": "velxio-chip/v1", + "name": "Z80 RAM-test ROM", + "author": "Velxio", + "license": "MIT", + "description": "A rom-32k variant holding a Z80 RAM round-trip program (write 0x5A to 0x8000, read back, HALT on match). Fixture for the Phase 3 computer-core proof (Z80 + ROM + RAM + address decode).", + "pins": ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "CE", "OE", "VCC", "GND"], + "attributes": [] +}