@neovand/zilion 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ Zilion runs **thousands of independent Z80 CPUs at once** as a single WebGPU com
26
26
 
27
27
  ## Why?
28
28
 
29
- CPU emulators run one machine at a time. But a whole class of problems needs to run *many* small Z80 programs independently and cheaply:
29
+ CPU emulators run one machine at a time. But a whole class of problems needs to run _many_ small Z80 programs independently and cheaply:
30
30
 
31
31
  - 🧎 **Artificial life & open-ended evolution** — soups of self-modifying machine code (à la [BFF / Computational Life](https://arxiv.org/abs/2406.19108)).
32
32
  - 🧠 **Genetic programming** — evaluate an entire population of evolved Z80 programs each generation.
@@ -40,6 +40,7 @@ Zilion turns "run N Z80s" into one GPU dispatch instead of N CPU loops.
40
40
  - ⚡ **Massively parallel** — one Z80 per GPU invocation, thousands at a time.
41
41
  - ðŸŽŊ **Correct** — the full documented instruction set plus **IX/IY**, **CB/ED/DDCB/FDCB** prefixes, shadow registers, and undocumented flag behavior. Continuously [differential-tested](#correctness) against a real-Z80 reference emulator.
42
42
  - ðŸ§Đ **Simple API** — `create` once, `run` batches, read back memory + registers.
43
+ - 🔎 **Instruction ablation** — remove any instruction from the ISA (including prefixed ones like `LDIR`) with a one-line hook; built for instruction-set experiments.
43
44
  - ðŸŠķ **Zero dependencies**, TypeScript-native, ships as ESM.
44
45
  - 🔌 **Bring your own `GPUDevice`** or let Zilion request one.
45
46
 
@@ -54,7 +55,7 @@ Requires an environment with [WebGPU](https://caniuse.com/webgpu) (Chrome/Edge 1
54
55
  ## Quick start
55
56
 
56
57
  ```ts
57
- import { Zilion } from '@neovand/zilion';
58
+ import { Zilion } from "@neovand/zilion";
58
59
 
59
60
  const z80 = await Zilion.create({ memBytes: 256 });
60
61
 
@@ -76,7 +77,7 @@ Every entry in the array is an independent Z80 with its own memory:
76
77
  ```ts
77
78
  // 10,000 random 32-byte programs, 128 instructions each — one dispatch.
78
79
  const programs = Array.from({ length: 10_000 }, () =>
79
- Uint8Array.from({ length: 32 }, () => (Math.random() * 256) | 0)
80
+ Uint8Array.from({ length: 32 }, () => (Math.random() * 256) | 0),
80
81
  );
81
82
 
82
83
  const { registers, memory, memoryOf } = await z80.run(programs, { steps: 128 });
@@ -88,7 +89,7 @@ const { registers, memory, memoryOf } = await z80.run(programs, { steps: 128 });
88
89
  ```ts
89
90
  await z80.run([program], {
90
91
  steps: 64,
91
- init: [{ af: 0x4100, bc: 0x0008, sp: 0xfff0 }] // A=0x41, BC=8, SP=0xFFF0
92
+ init: [{ af: 0x4100, bc: 0x0008, sp: 0xfff0 }], // A=0x41, BC=8, SP=0xFFF0
92
93
  });
93
94
  ```
94
95
 
@@ -109,15 +110,15 @@ The Z80's 16-bit address space **wraps** onto `memBytes` (so a program can't esc
109
110
 
110
111
  ```ts
111
112
  interface RunOptions {
112
- steps: number; // instructions per program (stops early on HALT)
113
+ steps: number; // instructions per program (stops early on HALT)
113
114
  init?: Z80RegisterInit[]; // optional per-program starting registers
114
115
  }
115
116
 
116
117
  interface RunResult {
117
118
  count: number;
118
119
  memBytes: number;
119
- memory: Uint8Array; // flat: count * memBytes
120
- registers: Z80Registers[]; // af, bc, de, hl, ix, iy, sp, pc, + shadows
120
+ memory: Uint8Array; // flat: count * memBytes
121
+ registers: Z80Registers[]; // af, bc, de, hl, ix, iy, sp, pc, + shadows
121
122
  memoryOf(i: number): Uint8Array; // program i's final memory
122
123
  }
123
124
  ```
@@ -128,6 +129,51 @@ Each program is copied into its instance's memory (zero-padded or truncated to `
128
129
 
129
130
  Releases GPU resources (and the device if Zilion created it).
130
131
 
132
+ ### Instruction ablation (`fetchHook`)
133
+
134
+ Zilion can remove instructions from the ISA. Pass a WGSL boolean expression over
135
+ `prefix` and `op`; every instruction for which it is true is skipped as a NOP:
136
+
137
+ ```ts
138
+ // No block copies (LDIR/LDDR/LDI/LDD) and no PUSH:
139
+ const z80 = await Zilion.create({
140
+ memBytes: 256,
141
+ fetchHook:
142
+ "(prefix == 0xedu && (op & 0xf7u) == 0xa0u) || (prefix == 0u && (op & 0xcfu) == 0xc5u)",
143
+ });
144
+ ```
145
+
146
+ The hook fires once per executed instruction, **after prefix resolution**:
147
+
148
+ | `prefix` | page | `op` |
149
+ | ------------------- | ----------------------------- | -------------------------------- |
150
+ | `0` | base | the opcode byte |
151
+ | `0xDD` / `0xFD` | IX / IY form of a base opcode | the opcode byte after the prefix |
152
+ | `0xCB` | CB (rotates, bits) | the byte after `CB` |
153
+ | `0xED` | ED (block ops, 16-bit loads) | the byte after `ED` |
154
+ | `0xDDCB` / `0xFDCB` | indexed bit ops | the byte after the displacement |
155
+
156
+ Prefix bytes are never reported as `op`. A skipped base-page opcode is a 1-byte
157
+ NOP: its operand bytes are _not_ skipped and run as the next instruction, exactly
158
+ as if the opcode had been removed from the CPU. Skipped CB/ED-page opcodes are
159
+ 2-byte NOPs (like undefined `ED` opcodes on real hardware); skipped DDCB/FDCB
160
+ opcodes are 4-byte NOPs. `R` increments as for a real fetch.
161
+
162
+ ### Embedding the core in your own shader
163
+
164
+ `Z80_CORE_WGSL` is the bare core. A host shader declares the memory model and the
165
+ hook before splicing it in:
166
+
167
+ ```wgsl
168
+ fn mem_read(addr: u32) -> u32 { ... }
169
+ fn mem_write(addr: u32, val: u32) { ... }
170
+ fn on_fetch_opcode(prefix: u32, op: u32) -> bool { ... }
171
+ // ${Z80_CORE_WGSL}
172
+ ```
173
+
174
+ then calls `z80_step()` in a loop after initialising the `cpu_*` registers. See
175
+ `buildComputeShader` in `src/shader.ts` for a complete host.
176
+
131
177
  ## How it works
132
178
 
133
179
  Zilion generates a WGSL compute shader containing a complete Z80 core. Each shader invocation:
@@ -145,7 +191,7 @@ Emulator bugs hide in undocumented corners, so Zilion's Z80 core is developed ag
145
191
 
146
192
  The core implements the full documented instruction set, the **CB**, **ED**, **DD/FD (IX/IY)**, and **DDCB/FDCB** prefix pages (including the undocumented DDCB register-copy side effect and the CPI/CPD undocumented-flag quirk), shadow registers, and `EXX`/`EX AF,AF'`.
147
193
 
148
- > **Scope & honesty:** Zilion is a batch execution core, not a cycle-accurate machine emulator. There are no interrupts and no I/O ports (`IN` reads 0, `OUT` is a no-op), and time is counted in instructions, not T-states — every instruction advances the step counter by one. The `R` refresh register increments per M1 (opcode/prefix) fetch and `HALT` idles correctly (re-executing itself until the step budget runs out, matching a real Z80's PC/R behavior). If you need cycle-accurate single-machine emulation, use a dedicated emulator; if you need to run a zillion Z80s fast, use Zilion.
194
+ > **Scope & honesty:** Zilion is a batch execution core, not a cycle-accurate machine emulator. There are no interrupts and no I/O ports (`IN` reads 0, `OUT` is a no-op), and time is counted in instructions, not T-states — every instruction advances the step counter by one. The `R` refresh register increments per M1 (opcode/prefix) fetch and `HALT` idles correctly (re-executing itself until the step budget runs out, matching a real Z80's PC/R behavior). The one documented simplification: the internal `WZ`/`memptr` register isn't modeled, so the _undocumented_ F3/F5 flag bits of `BIT n,(HL)` come from the operand rather than the memory address (this never affects control flow). Everything else — the full documented instruction set across the base, CB, ED, and DD/FD/DDCB/FDCB pages — is differential-tested against a real-Z80 reference to zero divergence in documented behavior. If you need cycle-accurate single-machine emulation, use a dedicated emulator; if you need to run a zillion Z80s fast, use Zilion.
149
195
 
150
196
  ## Performance
151
197
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { Zilion } from './zilion.js';
2
- export type { ZilionOptions, RunOptions, RunResult, Z80Registers, Z80RegisterInit } from './zilion.js';
3
- export { buildComputeShader, REG_FIELDS, REGS_PER_PROGRAM } from './shader.js';
4
- export { Z80_CORE_WGSL } from './z80-core.wgsl.js';
1
+ export { Zilion } from "./zilion.js";
2
+ export type { ZilionOptions, RunOptions, RunResult, Z80Registers, Z80RegisterInit, } from "./zilion.js";
3
+ export { buildComputeShader, REG_FIELDS, REGS_PER_PROGRAM } from "./shader.js";
4
+ export type { ShaderOptions } from "./shader.js";
5
+ export { Z80_CORE_WGSL } from "./z80-core.wgsl.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EACX,aAAa,EACb,UAAU,EACV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EACV,aAAa,EACb,UAAU,EACV,SAAS,EACT,YAAY,EACZ,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Zilion } from './zilion.js';
2
- export { buildComputeShader, REG_FIELDS, REGS_PER_PROGRAM } from './shader.js';
3
- export { Z80_CORE_WGSL } from './z80-core.wgsl.js';
1
+ export { Zilion } from "./zilion.js";
2
+ export { buildComputeShader, REG_FIELDS, REGS_PER_PROGRAM } from "./shader.js";
3
+ export { Z80_CORE_WGSL } from "./z80-core.wgsl.js";
4
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/shader.d.ts CHANGED
@@ -11,5 +11,16 @@ export declare const REGS_PER_PROGRAM: 12;
11
11
  * 2: storage regs — flat u32 array, REGS_PER_PROGRAM per program (out)
12
12
  * 3: storage init — flat u32 array, REGS_PER_PROGRAM per program (in)
13
13
  */
14
- export declare function buildComputeShader(memBytes: number): string;
14
+ export interface ShaderOptions {
15
+ /**
16
+ * WGSL expression evaluated once per executed instruction, after prefix
17
+ * resolution, with `prefix: u32` and `op: u32` in scope (see the host
18
+ * contract in z80-core.wgsl.ts for the prefix encoding). Return `true` to
19
+ * skip the instruction (treat it as a NOP). Default: `false` (nothing is
20
+ * suppressed). Example — ablate LDIR and every PUSH:
21
+ * `(prefix == 0xedu && op == 0xb0u) || (prefix == 0u && (op & 0xcfu) == 0xc5u)`
22
+ */
23
+ fetchHook?: string;
24
+ }
25
+ export declare function buildComputeShader(memBytes: number, opts?: ShaderOptions): string;
15
26
  //# sourceMappingURL=shader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shader.d.ts","sourceRoot":"","sources":["../src/shader.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,uGAab,CAAC;AACX,eAAO,MAAM,gBAAgB,IAAoB,CAAC;AAElD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA4F3D"}
1
+ {"version":3,"file":"shader.d.ts","sourceRoot":"","sources":["../src/shader.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,uGAab,CAAC;AACX,eAAO,MAAM,gBAAgB,IAAoB,CAAC;AAElD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,aAAkB,GACvB,MAAM,CA6FR"}
package/dist/shader.js CHANGED
@@ -1,36 +1,26 @@
1
- import { Z80_CORE_WGSL } from './z80-core.wgsl.js';
1
+ import { Z80_CORE_WGSL } from "./z80-core.wgsl.js";
2
2
  // Registers written back per program (16-bit values), in this fixed order.
3
3
  export const REG_FIELDS = [
4
- 'af',
5
- 'bc',
6
- 'de',
7
- 'hl',
8
- 'ix',
9
- 'iy',
10
- 'sp',
11
- 'pc',
12
- 'afPrime',
13
- 'bcPrime',
14
- 'dePrime',
15
- 'hlPrime'
4
+ "af",
5
+ "bc",
6
+ "de",
7
+ "hl",
8
+ "ix",
9
+ "iy",
10
+ "sp",
11
+ "pc",
12
+ "afPrime",
13
+ "bcPrime",
14
+ "dePrime",
15
+ "hlPrime",
16
16
  ];
17
17
  export const REGS_PER_PROGRAM = REG_FIELDS.length; // 12 u32 per program
18
- /**
19
- * Build the full WebGPU compute shader for a batch of Z80 programs, each with
20
- * `memBytes` bytes of private memory (must be a power of two). One workgroup
21
- * invocation runs one program for `params.steps` instructions.
22
- *
23
- * Bindings:
24
- * 0: uniform Params { count, mem_bytes, steps, sp_init }
25
- * 1: storage mem — flat u32 array, memBytes/4 words per program (in+out)
26
- * 2: storage regs — flat u32 array, REGS_PER_PROGRAM per program (out)
27
- * 3: storage init — flat u32 array, REGS_PER_PROGRAM per program (in)
28
- */
29
- export function buildComputeShader(memBytes) {
18
+ export function buildComputeShader(memBytes, opts = {}) {
30
19
  if (memBytes < 4 || (memBytes & (memBytes - 1)) !== 0) {
31
20
  throw new Error(`memBytes must be a power of two >= 4 (got ${memBytes})`);
32
21
  }
33
22
  const mask = memBytes - 1;
23
+ const hook = opts.fetchHook?.trim() || "false";
34
24
  return /* wgsl */ `
35
25
  struct Params {
36
26
  count: u32,
@@ -49,7 +39,7 @@ struct Params {
49
39
  var<private> mem: array<u32, ${memBytes}u>;
50
40
  fn mem_read(addr: u32) -> u32 { return mem[addr & ${mask}u]; }
51
41
  fn mem_write(addr: u32, val: u32) { mem[addr & ${mask}u] = val & 0xffu; }
52
- fn on_fetch_opcode(op: u32) -> bool { return false; } // no suppression by default
42
+ fn on_fetch_opcode(prefix: u32, op: u32) -> bool { return ${hook}; }
53
43
 
54
44
  ${Z80_CORE_WGSL}
55
45
 
@@ -1 +1 @@
1
- {"version":3,"file":"shader.js","sourceRoot":"","sources":["../src/shader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,UAAU,GAAG;IACzB,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACA,CAAC;AACX,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,qBAAqB;AAExE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAClD,IAAI,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,6CAA6C,QAAQ,GAAG,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC;IAE1B,OAAO,UAAU,CAAC;;;;;;;;;;;;;;;+BAeY,QAAQ;oDACa,IAAI;iDACP,IAAI;;;EAGnD,aAAa;;;;;;;;;;;;;;;;;;;;;;iBAsBE,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ChC,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"shader.js","sourceRoot":"","sources":["../src/shader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACD,CAAC;AACX,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,qBAAqB;AAyBxE,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,OAAsB,EAAE;IAExB,IAAI,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,QAAQ,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC;IAE/C,OAAO,UAAU,CAAC;;;;;;;;;;;;;;;+BAeW,QAAQ;oDACa,IAAI;iDACP,IAAI;4DACO,IAAI;;EAE9D,aAAa;;;;;;;;;;;;;;;;;;;;;;iBAsBE,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ChC,CAAC;AACF,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const Z80_CORE_WGSL = "\n// === Z80 CPU State (per invocation) ===\nvar<private> cpu_a: u32;\nvar<private> cpu_f: u32;\nvar<private> cpu_b: u32;\nvar<private> cpu_c: u32;\nvar<private> cpu_d: u32;\nvar<private> cpu_e: u32;\nvar<private> cpu_h: u32;\nvar<private> cpu_l: u32;\nvar<private> cpu_sp: u32;\nvar<private> cpu_pc: u32;\nvar<private> cpu_a2: u32;\nvar<private> cpu_f2: u32;\nvar<private> cpu_b2: u32;\nvar<private> cpu_c2: u32;\nvar<private> cpu_d2: u32;\nvar<private> cpu_e2: u32;\nvar<private> cpu_h2: u32;\nvar<private> cpu_l2: u32;\nvar<private> cpu_halted: u32;\nvar<private> cpu_iff1: u32;\nvar<private> cpu_iff2: u32;\nvar<private> cpu_ix: u32;\nvar<private> cpu_iy: u32;\nvar<private> cpu_i: u32; // interrupt vector register (I)\nvar<private> cpu_r: u32; // memory refresh register (R); bits 0-6 count M1 cycles, bit 7 preserved\n\n// Increment R once per M1 (opcode/prefix) fetch: 7-bit counter, bit 7 preserved.\nfn r_inc() { cpu_r = (cpu_r & 0x80u) | ((cpu_r + 1u) & 0x7fu); }\n// Index-prefix state for the instruction currently executing:\n// idx_mode: 0 = HL, 1 = IX, 2 = IY\n// idx_disp: sign-extended displacement for (IX+d)/(IY+d)\n// idx_uses_mem: 1 when this instruction dereferences (IX+d)/(IY+d), which\n// means H/L operands are NOT substituted by IXH/IXL (real Z80 rule).\nvar<private> idx_mode: u32;\nvar<private> idx_disp: u32;\nvar<private> idx_uses_mem: u32;\n\n// HOST CONTRACT: the host shader must declare the following BEFORE this core:\n// fn mem_read(addr: u32) -> u32 // read one byte from memory\n// fn mem_write(addr: u32, val: u32) // write one byte to memory\n// fn on_fetch_opcode(op: u32) -> bool // return true to skip (NOP) an\n// // opcode after prefix resolution\n// This lets the host choose the memory model (mask, modulo, storage buffer, \u2026)\n// and hook opcode execution (e.g. instruction suppression). See buildComputeShader.\n\n// Z80 flag bits\nconst CF: u32 = 0x01u;\nconst NF: u32 = 0x02u;\nconst PF: u32 = 0x04u;\nconst F3: u32 = 0x08u;\nconst HF: u32 = 0x10u;\nconst F5: u32 = 0x20u;\nconst ZF: u32 = 0x40u;\nconst SFl: u32 = 0x80u;\n\n\nfn z80_fetch() -> u32 {\n let val = mem_read(cpu_pc);\n cpu_pc = (cpu_pc + 1u) & 0xffffu;\n return val;\n}\n\nfn z80_fetch_word() -> u32 {\n let lo = z80_fetch();\n let hi = z80_fetch();\n return (hi << 8u) | lo;\n}\n\nfn z80_push16(val: u32) {\n cpu_sp = (cpu_sp - 1u) & 0xffffu;\n mem_write(cpu_sp, (val >> 8u) & 0xffu);\n cpu_sp = (cpu_sp - 1u) & 0xffffu;\n mem_write(cpu_sp, val & 0xffu);\n}\n\nfn z80_pop16() -> u32 {\n let lo = mem_read(cpu_sp);\n cpu_sp = (cpu_sp + 1u) & 0xffffu;\n let hi = mem_read(cpu_sp);\n cpu_sp = (cpu_sp + 1u) & 0xffffu;\n return (hi << 8u) | lo;\n}\n\nfn signed_byte(b: u32) -> i32 {\n let sb = i32(b);\n if (sb > 127) { return sb - 256; }\n return sb;\n}\n\n// === Register Access ===\nfn get_bc() -> u32 { return (cpu_b << 8u) | cpu_c; }\nfn get_de() -> u32 { return (cpu_d << 8u) | cpu_e; }\nfn get_hl() -> u32 { return (cpu_h << 8u) | cpu_l; }\nfn get_af() -> u32 { return (cpu_a << 8u) | cpu_f; }\n\nfn set_bc(v: u32) { cpu_b = (v >> 8u) & 0xffu; cpu_c = v & 0xffu; }\nfn set_de(v: u32) { cpu_d = (v >> 8u) & 0xffu; cpu_e = v & 0xffu; }\nfn set_hl(v: u32) { cpu_h = (v >> 8u) & 0xffu; cpu_l = v & 0xffu; }\nfn set_af(v: u32) { cpu_a = (v >> 8u) & 0xffu; cpu_f = v & 0xffu; }\n\nfn get_reg(idx: u32) -> u32 {\n switch(idx) {\n case 0u: { return cpu_b; }\n case 1u: { return cpu_c; }\n case 2u: { return cpu_d; }\n case 3u: { return cpu_e; }\n case 4u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { return (idx_reg16() >> 8u) & 0xffu; } // IXH/IYH\n return cpu_h;\n }\n case 5u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { return idx_reg16() & 0xffu; } // IXL/IYL\n return cpu_l;\n }\n case 6u: { return mem_read(idx_addr()); }\n case 7u: { return cpu_a; }\n default: { return 0u; }\n }\n}\n\nfn set_reg(idx: u32, val: u32) {\n let v = val & 0xffu;\n switch(idx) {\n case 0u: { cpu_b = v; }\n case 1u: { cpu_c = v; }\n case 2u: { cpu_d = v; }\n case 3u: { cpu_e = v; }\n case 4u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { set_idx_reg16((idx_reg16() & 0x00ffu) | (v << 8u)); }\n else { cpu_h = v; }\n }\n case 5u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { set_idx_reg16((idx_reg16() & 0xff00u) | v); }\n else { cpu_l = v; }\n }\n case 6u: { mem_write(idx_addr(), v); }\n case 7u: { cpu_a = v; }\n default: {}\n }\n}\n\nfn get_reg16(idx: u32) -> u32 {\n switch(idx) {\n case 0u: { return get_bc(); }\n case 1u: { return get_de(); }\n case 2u: { return idx_reg16(); } // HL / IX / IY\n case 3u: { return cpu_sp; }\n default: { return 0u; }\n }\n}\n\nfn set_reg16(idx: u32, val: u32) {\n let v = val & 0xffffu;\n switch(idx) {\n case 0u: { set_bc(v); }\n case 1u: { set_de(v); }\n case 2u: { set_idx_reg16(v); } // HL / IX / IY\n case 3u: { cpu_sp = v; }\n default: {}\n }\n}\n\nfn get_reg16_af(idx: u32) -> u32 {\n if (idx == 3u) { return get_af(); }\n return get_reg16(idx);\n}\n\nfn set_reg16_af(idx: u32, val: u32) {\n if (idx == 3u) { set_af(val); } else { set_reg16(idx, val); }\n}\n\n// === Index register (IX/IY) helpers ===\n// The 16-bit register the current prefix maps HL to (HL itself when no prefix).\nfn idx_reg16() -> u32 {\n if (idx_mode == 1u) { return cpu_ix; }\n if (idx_mode == 2u) { return cpu_iy; }\n return get_hl();\n}\nfn set_idx_reg16(v: u32) {\n if (idx_mode == 1u) { cpu_ix = v & 0xffffu; }\n else if (idx_mode == 2u) { cpu_iy = v & 0xffffu; }\n else { set_hl(v); }\n}\n// Address used for (HL) / (IX+d) / (IY+d).\nfn idx_addr() -> u32 {\n if (idx_mode != 0u) { return (idx_reg16() + idx_disp) & 0xffffu; }\n return get_hl();\n}\n// Sign-extend a displacement byte to 16 bits (two's complement).\nfn signext(b: u32) -> u32 {\n if (b >= 0x80u) { return b | 0xff00u; }\n return b;\n}\n// Does this main opcode dereference (HL)? (Determines displacement fetch and\n// whether H/L operands are IXH/IXL or real H/L under a DD/FD prefix.)\nfn op_uses_hl_mem(op: u32) -> bool {\n let x = (op >> 6u) & 3u;\n let y = (op >> 3u) & 7u;\n let z = op & 7u;\n if (x == 1u) { return (y == 6u || z == 6u) && !(y == 6u && z == 6u); } // LD r,(HL)/(HL),r (not HALT)\n if (x == 2u) { return z == 6u; } // ALU A,(HL)\n if (x == 0u) {\n if (z == 4u || z == 5u || z == 6u) { return y == 6u; } // INC/DEC (HL), LD (HL),n\n return false;\n }\n return false;\n}\n// Write a REAL 8-bit register (no IX/IY substitution) \u2014 used by the\n// undocumented DDCB/FDCB register-copy side effect.\nfn set_reg_raw(idx: u32, val: u32) {\n let v = val & 0xffu;\n switch(idx) {\n case 0u: { cpu_b = v; }\n case 1u: { cpu_c = v; }\n case 2u: { cpu_d = v; }\n case 3u: { cpu_e = v; }\n case 4u: { cpu_h = v; }\n case 5u: { cpu_l = v; }\n case 7u: { cpu_a = v; }\n default: {}\n }\n}\n\n// === Flag Helpers ===\nfn sz_flags(val: u32) -> u32 {\n var f = val & SFl;\n if (val == 0u) { f |= ZF; }\n f |= val & (F3 | F5);\n return f;\n}\n\nfn parity(val: u32) -> bool {\n var p = val;\n p ^= p >> 4u;\n p ^= p >> 2u;\n p ^= p >> 1u;\n return (p & 1u) == 0u;\n}\n\nfn check_cc(cc: u32) -> bool {\n switch(cc) {\n case 0u: { return (cpu_f & ZF) == 0u; }\n case 1u: { return (cpu_f & ZF) != 0u; }\n case 2u: { return (cpu_f & CF) == 0u; }\n case 3u: { return (cpu_f & CF) != 0u; }\n case 4u: { return (cpu_f & PF) == 0u; }\n case 5u: { return (cpu_f & PF) != 0u; }\n case 6u: { return (cpu_f & SFl) == 0u; }\n case 7u: { return (cpu_f & SFl) != 0u; }\n default: { return false; }\n }\n}\n\n// === ALU ===\nfn z80_alu(op: u32, val: u32) {\n let a = cpu_a;\n let c = cpu_f & CF;\n switch(op) {\n case 0u: { // ADD\n let r = a + val;\n cpu_f = sz_flags(r & 0xffu) | select(0u, CF, r > 0xffu) |\n ((a ^ val ^ r) & HF) |\n select(0u, PF, ((~(a ^ val)) & (a ^ r) & 0x80u) != 0u);\n cpu_a = r & 0xffu;\n }\n case 1u: { // ADC\n let r = a + val + c;\n cpu_f = sz_flags(r & 0xffu) | select(0u, CF, r > 0xffu) |\n ((a ^ val ^ r) & HF) |\n select(0u, PF, ((~(a ^ val)) & (a ^ r) & 0x80u) != 0u);\n cpu_a = r & 0xffu;\n }\n case 2u: { // SUB\n let r = i32(a) - i32(val);\n let ru = u32(r) & 0xffu;\n cpu_f = sz_flags(ru) | NF | select(0u, CF, r < 0) |\n ((a ^ val ^ u32(r)) & HF) |\n select(0u, PF, (((a ^ val) & (a ^ u32(r))) & 0x80u) != 0u);\n cpu_a = ru;\n }\n case 3u: { // SBC\n let r = i32(a) - i32(val) - i32(c);\n let ru = u32(r) & 0xffu;\n cpu_f = sz_flags(ru) | NF | select(0u, CF, r < 0) |\n ((a ^ val ^ u32(r)) & HF) |\n select(0u, PF, (((a ^ val) & (a ^ u32(r))) & 0x80u) != 0u);\n cpu_a = ru;\n }\n case 4u: { // AND\n cpu_a = a & val;\n cpu_f = sz_flags(cpu_a) | HF | select(0u, PF, parity(cpu_a));\n }\n case 5u: { // XOR\n cpu_a = a ^ val;\n cpu_f = sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n case 6u: { // OR\n cpu_a = a | val;\n cpu_f = sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n case 7u: { // CP\n let r = i32(a) - i32(val);\n let ru = u32(r) & 0xffu;\n cpu_f = (ru & SFl) | select(0u, ZF, ru == 0u) | (val & (F3 | F5)) | NF |\n select(0u, CF, r < 0) | ((a ^ val ^ u32(r)) & HF) |\n select(0u, PF, (((a ^ val) & (a ^ u32(r))) & 0x80u) != 0u);\n }\n default: {}\n }\n}\n\nfn z80_inc8(val: u32) -> u32 {\n let r = (val + 1u) & 0xffu;\n cpu_f = (cpu_f & CF) | sz_flags(r) |\n select(0u, PF, val == 0x7fu) |\n select(0u, HF, (r & 0x0fu) == 0u);\n return r;\n}\n\nfn z80_dec8(val: u32) -> u32 {\n let r = (val - 1u) & 0xffu;\n cpu_f = (cpu_f & CF) | sz_flags(r) | NF |\n select(0u, PF, val == 0x80u) |\n select(0u, HF, (val & 0x0fu) == 0u);\n return r;\n}\n\nfn z80_add_hl(val: u32) {\n let hl = idx_reg16(); // ADD HL,rp / ADD IX,rp / ADD IY,rp\n let r = hl + val;\n cpu_f = (cpu_f & (SFl | ZF | PF)) |\n select(0u, CF, r > 0xffffu) |\n select(0u, HF, ((hl ^ val ^ r) & 0x1000u) != 0u) |\n ((r >> 8u) & (F3 | F5));\n set_idx_reg16(r & 0xffffu);\n}\n\n// === Rotate/Shift for accumulator ===\nfn z80_rot_accum(y: u32) {\n let a = cpu_a;\n let c = cpu_f & CF;\n let keep = cpu_f & (SFl | ZF | PF);\n switch(y) {\n case 0u: { // RLCA\n cpu_a = ((a << 1u) | (a >> 7u)) & 0xffu;\n cpu_f = keep | (a >> 7u) | (cpu_a & (F3 | F5));\n }\n case 1u: { // RRCA\n cpu_a = ((a >> 1u) | (a << 7u)) & 0xffu;\n cpu_f = keep | (a & 1u) | (cpu_a & (F3 | F5));\n }\n case 2u: { // RLA\n cpu_a = ((a << 1u) | c) & 0xffu;\n cpu_f = keep | (a >> 7u) | (cpu_a & (F3 | F5));\n }\n case 3u: { // RRA\n cpu_a = ((a >> 1u) | (c << 7u)) & 0xffu;\n cpu_f = keep | (a & 1u) | (cpu_a & (F3 | F5));\n }\n case 4u: { // DAA\n var correction = 0u;\n var carry = c;\n if ((cpu_f & HF) != 0u || (a & 0x0fu) > 9u) { correction |= 0x06u; }\n if (c != 0u || a > 0x99u) { correction |= 0x60u; carry = 1u; }\n if ((cpu_f & NF) != 0u) { cpu_a = (a - correction) & 0xffu; }\n else { cpu_a = (a + correction) & 0xffu; }\n cpu_f = (cpu_f & NF) | sz_flags(cpu_a) | carry |\n ((a ^ cpu_a) & HF) | select(0u, PF, parity(cpu_a));\n }\n case 5u: { // CPL\n cpu_a = (~a) & 0xffu;\n cpu_f = (cpu_f & (SFl | ZF | PF | CF)) | HF | NF | (cpu_a & (F3 | F5));\n }\n case 6u: { // SCF\n cpu_f = (cpu_f & (SFl | ZF | PF)) | CF | (cpu_a & (F3 | F5));\n }\n case 7u: { // CCF\n cpu_f = (cpu_f & (SFl | ZF | PF)) |\n select(0u, HF, c != 0u) |\n select(CF, 0u, c != 0u) |\n (cpu_a & (F3 | F5));\n }\n default: {}\n }\n}\n\n// === CB Prefix (bit ops, rotates, shifts) ===\nfn z80_cb_rot(op: u32, val: u32) -> u32 {\n let c = cpu_f & CF;\n var r = 0u;\n switch(op) {\n case 0u: { r = ((val << 1u) | (val >> 7u)) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 1u: { r = ((val >> 1u) | (val << 7u)) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n case 2u: { r = ((val << 1u) | c) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 3u: { r = ((val >> 1u) | (c << 7u)) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n case 4u: { r = (val << 1u) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 5u: { r = ((val >> 1u) | (val & 0x80u)) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n case 6u: { r = ((val << 1u) | 1u) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 7u: { r = (val >> 1u) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n default: { r = val; }\n }\n return r;\n}\n\nfn z80_exec_cb() {\n let op = z80_fetch();\n r_inc(); // M1: CB-page opcode fetch\n let x = (op >> 6u) & 3u;\n let y = (op >> 3u) & 7u;\n let z = op & 7u;\n let val = get_reg(z);\n switch(x) {\n case 0u: { set_reg(z, z80_cb_rot(y, val)); }\n case 1u: { // BIT\n cpu_f = (cpu_f & CF) | HF |\n select(0u, ZF | PF, (val & (1u << y)) == 0u) |\n select(0u, SFl, y == 7u && (val & 0x80u) != 0u) |\n (val & (F3 | F5));\n }\n case 2u: { set_reg(z, val & ~(1u << y)); }\n case 3u: { set_reg(z, val | (1u << y)); }\n default: {}\n }\n}\n\n// DDCB / FDCB: operates on (IX+d)/(IY+d). The displacement (idx_disp) has\n// already been fetched. For rot/shift/RES/SET the result is written to memory\n// AND (undocumented) copied to the real register in the low 3 bits unless it is\n// 6. For BIT, the undocumented F3/F5 come from the high byte of the address.\nfn z80_exec_idxcb(cbop: u32) {\n let addr = (idx_reg16() + idx_disp) & 0xffffu;\n let cx = (cbop >> 6u) & 3u;\n let cy = (cbop >> 3u) & 7u;\n let cz = cbop & 7u;\n let val = mem_read(addr);\n switch(cx) {\n case 0u: {\n let r = z80_cb_rot(cy, val);\n mem_write(addr, r);\n if (cz != 6u) { set_reg_raw(cz, r); }\n }\n case 1u: { // BIT n,(IX+d)\n cpu_f = (cpu_f & CF) | HF |\n select(0u, ZF | PF, (val & (1u << cy)) == 0u) |\n select(0u, SFl, cy == 7u && (val & 0x80u) != 0u) |\n ((addr >> 8u) & (F3 | F5));\n }\n case 2u: {\n let r = val & ~(1u << cy);\n mem_write(addr, r);\n if (cz != 6u) { set_reg_raw(cz, r); }\n }\n case 3u: {\n let r = val | (1u << cy);\n mem_write(addr, r);\n if (cz != 6u) { set_reg_raw(cz, r); }\n }\n default: {}\n }\n}\n\n// === Block Transfer (ED prefix) ===\nfn z80_ldi() {\n let val = mem_read(get_hl());\n mem_write(get_de(), val);\n set_hl((get_hl() + 1u) & 0xffffu);\n set_de((get_de() + 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n let n = (val + cpu_a) & 0xffu;\n cpu_f = (cpu_f & (SFl | ZF | CF)) |\n select(0u, PF, get_bc() != 0u) |\n (n & F3) | select(0u, F5, (n & 0x02u) != 0u);\n}\n\nfn z80_ldd() {\n let val = mem_read(get_hl());\n mem_write(get_de(), val);\n set_hl((get_hl() - 1u) & 0xffffu);\n set_de((get_de() - 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n let n = (val + cpu_a) & 0xffu;\n cpu_f = (cpu_f & (SFl | ZF | CF)) |\n select(0u, PF, get_bc() != 0u) |\n (n & F3) | select(0u, F5, (n & 0x02u) != 0u);\n}\n\nfn z80_cpi() {\n let val = mem_read(get_hl());\n let r = (cpu_a - val) & 0xffu;\n let hf = (cpu_a ^ val ^ r) & HF;\n // Undocumented F3/F5 come from n = A-(HL)-HF (bit 3 -> F3, bit 1 -> F5).\n let n = (r - select(0u, 1u, hf != 0u)) & 0xffu;\n set_hl((get_hl() + 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n cpu_f = (cpu_f & CF) | (r & SFl) | select(0u, ZF, r == 0u) | NF |\n hf | select(0u, PF, get_bc() != 0u) |\n (n & F3) | ((n & 0x02u) << 4u);\n}\n\nfn z80_cpd() {\n let val = mem_read(get_hl());\n let r = (cpu_a - val) & 0xffu;\n let hf = (cpu_a ^ val ^ r) & HF;\n let n = (r - select(0u, 1u, hf != 0u)) & 0xffu;\n set_hl((get_hl() - 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n cpu_f = (cpu_f & CF) | (r & SFl) | select(0u, ZF, r == 0u) | NF |\n hf | select(0u, PF, get_bc() != 0u) |\n (n & F3) | ((n & 0x02u) << 4u);\n}\n\n// === ED Prefix ===\nfn z80_exec_ed() {\n let op = z80_fetch();\n r_inc(); // M1: ED-page opcode fetch\n switch(op) {\n case 0xa0u: { z80_ldi(); }\n case 0xa8u: { z80_ldd(); }\n case 0xb0u: { z80_ldi(); if (get_bc() != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } } // LDIR\n case 0xb8u: { z80_ldd(); if (get_bc() != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } } // LDDR\n case 0xa1u: { z80_cpi(); }\n case 0xa9u: { z80_cpd(); }\n case 0xb1u: { z80_cpi(); if (get_bc() != 0u && (cpu_f & ZF) == 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } }\n case 0xb9u: { z80_cpd(); if (get_bc() != 0u && (cpu_f & ZF) == 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } }\n // NEG\n case 0x44u, 0x4cu, 0x54u, 0x5cu, 0x64u, 0x6cu, 0x74u, 0x7cu: {\n let a = cpu_a; cpu_a = 0u; z80_alu(2u, a);\n }\n // RETN/RETI\n case 0x45u, 0x4du, 0x55u, 0x5du, 0x65u, 0x6du, 0x75u, 0x7du: {\n cpu_iff1 = cpu_iff2; cpu_pc = z80_pop16();\n }\n // LD I,A / LD R,A / LD A,I / LD A,R\n case 0x47u: { cpu_i = cpu_a; } // LD I,A\n case 0x4fu: { cpu_r = cpu_a; } // LD R,A\n // LD A,I / LD A,R: load I or R into A. Flags: S/Z (+F3/F5) from the loaded\n // value, PF = IFF2, N/H reset, C preserved.\n case 0x57u: { cpu_a = cpu_i; cpu_f = (cpu_f & CF) | sz_flags(cpu_i) | select(0u, PF, cpu_iff2 != 0u); }\n case 0x5fu: { cpu_a = cpu_r; cpu_f = (cpu_f & CF) | sz_flags(cpu_r) | select(0u, PF, cpu_iff2 != 0u); }\n // LD (nn), rr\n case 0x43u, 0x53u, 0x63u, 0x73u: {\n let nn = z80_fetch_word();\n let rp = (op >> 4u) & 3u;\n let val = get_reg16(rp);\n mem_write(nn, val & 0xffu);\n mem_write((nn + 1u) & 0xffffu, (val >> 8u) & 0xffu);\n }\n // LD rr, (nn)\n case 0x4bu, 0x5bu, 0x6bu, 0x7bu: {\n let nn = z80_fetch_word();\n let rp = (op >> 4u) & 3u;\n let lo = mem_read(nn);\n let hi = mem_read((nn + 1u) & 0xffffu);\n set_reg16(rp, (hi << 8u) | lo);\n }\n // ADC HL, rr\n case 0x4au, 0x5au, 0x6au, 0x7au: {\n let rp = (op >> 4u) & 3u;\n let hl = get_hl();\n let val = get_reg16(rp);\n let c = cpu_f & CF;\n let r = hl + val + c;\n cpu_f = ((r >> 8u) & SFl) | select(0u, ZF, (r & 0xffffu) == 0u) |\n select(0u, HF, ((hl ^ val ^ r) & 0x1000u) != 0u) |\n select(0u, PF, ((~(hl ^ val)) & (hl ^ r) & 0x8000u) != 0u) |\n select(0u, CF, r > 0xffffu) | ((r >> 8u) & (F3 | F5));\n set_hl(r & 0xffffu);\n }\n // SBC HL, rr\n case 0x42u, 0x52u, 0x62u, 0x72u: {\n let rp = (op >> 4u) & 3u;\n let hl = get_hl();\n let val = get_reg16(rp);\n let c = cpu_f & CF;\n let r = i32(hl) - i32(val) - i32(c);\n let ru = u32(r) & 0xffffu;\n cpu_f = ((ru >> 8u) & SFl) | select(0u, ZF, ru == 0u) | NF |\n select(0u, HF, ((hl ^ val ^ u32(r)) & 0x1000u) != 0u) |\n select(0u, PF, (((hl ^ val) & (hl ^ u32(r))) & 0x8000u) != 0u) |\n select(0u, CF, r < 0) | ((ru >> 8u) & (F3 | F5));\n set_hl(ru);\n }\n // RRD\n case 0x67u: {\n let m = mem_read(get_hl());\n mem_write(get_hl(), ((cpu_a << 4u) | (m >> 4u)) & 0xffu);\n cpu_a = (cpu_a & 0xf0u) | (m & 0x0fu);\n cpu_f = (cpu_f & CF) | sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n // RLD\n case 0x6fu: {\n let m = mem_read(get_hl());\n mem_write(get_hl(), ((m << 4u) | (cpu_a & 0x0fu)) & 0xffu);\n cpu_a = (cpu_a & 0xf0u) | (m >> 4u);\n cpu_f = (cpu_f & CF) | sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n // IN r,(C) - simplified, just set to 0\n case 0x40u, 0x48u, 0x50u, 0x58u, 0x60u, 0x68u, 0x70u, 0x78u: {\n set_reg((op >> 3u) & 7u, 0u);\n }\n default: {} // unknown ED ops = NOP\n }\n}\n\n// === Main Opcode Execution ===\nfn z80_exec_x0(y: u32, z: u32, p: u32, q: u32) {\n switch(z) {\n case 0u: {\n switch(y) {\n case 0u: {} // NOP\n case 1u: { // EX AF,AF'\n var t = cpu_a; cpu_a = cpu_a2; cpu_a2 = t;\n t = cpu_f; cpu_f = cpu_f2; cpu_f2 = t;\n }\n case 2u: { // DJNZ\n let d = signed_byte(z80_fetch());\n cpu_b = (cpu_b - 1u) & 0xffu;\n if (cpu_b != 0u) { cpu_pc = u32(i32(cpu_pc) + d) & 0xffffu; }\n }\n case 3u: { // JR\n let d = signed_byte(z80_fetch());\n cpu_pc = u32(i32(cpu_pc) + d) & 0xffffu;\n }\n default: { // JR cc (y-4)\n let d = signed_byte(z80_fetch());\n if (check_cc(y - 4u)) { cpu_pc = u32(i32(cpu_pc) + d) & 0xffffu; }\n }\n }\n }\n case 1u: {\n if (q == 0u) { set_reg16(p, z80_fetch_word()); }\n else { z80_add_hl(get_reg16(p)); }\n }\n case 2u: {\n if (q == 0u) {\n switch(p) {\n case 0u: { mem_write(get_bc(), cpu_a); }\n case 1u: { mem_write(get_de(), cpu_a); }\n case 2u: { let nn = z80_fetch_word(); let hl = idx_reg16(); mem_write(nn, hl & 0xffu); mem_write((nn+1u) & 0xffffu, (hl >> 8u) & 0xffu); }\n case 3u: { mem_write(z80_fetch_word(), cpu_a); }\n default: {}\n }\n } else {\n switch(p) {\n case 0u: { cpu_a = mem_read(get_bc()); }\n case 1u: { cpu_a = mem_read(get_de()); }\n case 2u: { let nn = z80_fetch_word(); let lo = mem_read(nn); let hi = mem_read((nn+1u) & 0xffffu); set_idx_reg16((hi << 8u) | lo); }\n case 3u: { cpu_a = mem_read(z80_fetch_word()); }\n default: {}\n }\n }\n }\n case 3u: {\n if (q == 0u) { set_reg16(p, (get_reg16(p) + 1u) & 0xffffu); }\n else { set_reg16(p, (get_reg16(p) - 1u) & 0xffffu); }\n }\n case 4u: { set_reg(y, z80_inc8(get_reg(y))); }\n case 5u: { set_reg(y, z80_dec8(get_reg(y))); }\n case 6u: { set_reg(y, z80_fetch()); }\n case 7u: { z80_rot_accum(y); }\n default: {}\n }\n}\n\nfn z80_exec_x3(y: u32, z: u32, p: u32, q: u32) {\n switch(z) {\n case 0u: { if (check_cc(y)) { cpu_pc = z80_pop16(); } }\n case 1u: {\n if (q == 0u) { set_reg16_af(p, z80_pop16()); }\n else {\n switch(p) {\n case 0u: { cpu_pc = z80_pop16(); } // RET\n case 1u: { // EXX\n var t = cpu_b; cpu_b = cpu_b2; cpu_b2 = t;\n t = cpu_c; cpu_c = cpu_c2; cpu_c2 = t;\n t = cpu_d; cpu_d = cpu_d2; cpu_d2 = t;\n t = cpu_e; cpu_e = cpu_e2; cpu_e2 = t;\n t = cpu_h; cpu_h = cpu_h2; cpu_h2 = t;\n t = cpu_l; cpu_l = cpu_l2; cpu_l2 = t;\n }\n case 2u: { cpu_pc = idx_reg16(); } // JP (HL)/(IX)/(IY)\n case 3u: { cpu_sp = idx_reg16(); } // LD SP,HL/IX/IY\n default: {}\n }\n }\n }\n case 2u: { let nn = z80_fetch_word(); if (check_cc(y)) { cpu_pc = nn; } }\n case 3u: {\n switch(y) {\n case 0u: { cpu_pc = z80_fetch_word(); } // JP nn\n case 1u: { z80_exec_cb(); }\n case 2u: { z80_fetch(); } // OUT (n),A - no I/O device, discard (matches zff outPort no-op)\n case 3u: { z80_fetch(); cpu_a = 0u; } // IN A,(n) - no I/O device, reads 0 (matches zff inPort\u21920)\n case 4u: { // EX (SP),HL / EX (SP),IX / EX (SP),IY\n let lo = mem_read(cpu_sp);\n let hi = mem_read((cpu_sp + 1u) & 0xffffu);\n let hl = idx_reg16();\n mem_write(cpu_sp, hl & 0xffu);\n mem_write((cpu_sp + 1u) & 0xffffu, (hl >> 8u) & 0xffu);\n set_idx_reg16((hi << 8u) | lo);\n }\n case 5u: { // EX DE,HL\n let td = cpu_d; let te = cpu_e;\n cpu_d = cpu_h; cpu_e = cpu_l;\n cpu_h = td; cpu_l = te;\n }\n case 6u: { cpu_iff1 = 0u; cpu_iff2 = 0u; }\n case 7u: { cpu_iff1 = 1u; cpu_iff2 = 1u; }\n default: {}\n }\n }\n case 4u: { let nn = z80_fetch_word(); if (check_cc(y)) { z80_push16(cpu_pc); cpu_pc = nn; } }\n case 5u: {\n if (q == 0u) { z80_push16(get_reg16_af(p)); }\n else {\n switch(p) {\n case 0u: { let nn = z80_fetch_word(); z80_push16(cpu_pc); cpu_pc = nn; } // CALL nn\n case 1u, 3u: {} // DD/FD prefix handled in z80_step\n case 2u: { z80_exec_ed(); }\n default: {}\n }\n }\n }\n case 6u: { z80_alu(y, z80_fetch()); }\n case 7u: { z80_push16(cpu_pc); cpu_pc = y * 8u; } // RST\n default: {}\n }\n}\n\nfn z80_execute(op: u32) {\n let x = (op >> 6u) & 3u;\n let y = (op >> 3u) & 7u;\n let z = op & 7u;\n let p = (y >> 1u) & 3u;\n let q = y & 1u;\n switch(x) {\n case 0u: { z80_exec_x0(y, z, p, q); }\n case 1u: {\n if (y == 6u && z == 6u) {\n // HALT: mark halted and back PC up onto the HALT opcode so the\n // CPU re-executes it every step until an interrupt.\n cpu_halted = 1u;\n cpu_pc = (cpu_pc - 1u) & 0xffffu;\n }\n else { set_reg(y, get_reg(z)); }\n }\n case 2u: { z80_alu(y, get_reg(z)); }\n case 3u: { z80_exec_x3(y, z, p, q); }\n default: {}\n }\n}\n\nfn z80_step() {\n // While halted, the CPU keeps executing HALT: each step is an M1 fetch of\n // the same opcode (R increments), PC stays put. It resumes only on interrupt.\n if (cpu_halted != 0u) { r_inc(); return; }\n // Reset per-instruction index-prefix state.\n idx_mode = 0u;\n idx_uses_mem = 0u;\n idx_disp = 0u;\n\n var op = z80_fetch();\n r_inc(); // M1: opcode (or prefix) fetch\n // A DD/FD prefix selects IX/IY for the following opcode.\n if (op == 0xddu || op == 0xfdu) {\n idx_mode = select(2u, 1u, op == 0xddu);\n let next = z80_fetch();\n r_inc(); // M1: opcode after the prefix\n // A prefix immediately followed by another prefix or ED is a wasted M1:\n // this step consumes just the prefix; back up so the next step restarts\n // at the following byte (matches real Z80 timing and avoids an\n // unbounded fetch loop on all-prefix programs).\n if (next == 0xddu || next == 0xfdu || next == 0xedu) {\n cpu_pc = (cpu_pc - 1u) & 0xffffu;\n return;\n }\n op = next;\n }\n\n // Host hook: skip execution (treat as NOP) if requested.\n if (on_fetch_opcode(op)) { return; }\n\n if (idx_mode != 0u) {\n if (op == 0xcbu) {\n // DDCB/FDCB: displacement precedes the CB opcode.\n idx_disp = signext(z80_fetch());\n let cbop = z80_fetch();\n z80_exec_idxcb(cbop);\n return;\n }\n if (op_uses_hl_mem(op)) {\n idx_uses_mem = 1u;\n idx_disp = signext(z80_fetch());\n }\n }\n z80_execute(op);\n}\n";
1
+ export declare const Z80_CORE_WGSL = "\n// === Z80 CPU State (per invocation) ===\nvar<private> cpu_a: u32;\nvar<private> cpu_f: u32;\nvar<private> cpu_b: u32;\nvar<private> cpu_c: u32;\nvar<private> cpu_d: u32;\nvar<private> cpu_e: u32;\nvar<private> cpu_h: u32;\nvar<private> cpu_l: u32;\nvar<private> cpu_sp: u32;\nvar<private> cpu_pc: u32;\nvar<private> cpu_a2: u32;\nvar<private> cpu_f2: u32;\nvar<private> cpu_b2: u32;\nvar<private> cpu_c2: u32;\nvar<private> cpu_d2: u32;\nvar<private> cpu_e2: u32;\nvar<private> cpu_h2: u32;\nvar<private> cpu_l2: u32;\nvar<private> cpu_halted: u32;\nvar<private> cpu_iff1: u32;\nvar<private> cpu_iff2: u32;\nvar<private> cpu_ix: u32;\nvar<private> cpu_iy: u32;\nvar<private> cpu_i: u32; // interrupt vector register (I)\nvar<private> cpu_r: u32; // memory refresh register (R); bits 0-6 count M1 cycles, bit 7 preserved\n\n// Increment R once per M1 (opcode/prefix) fetch: 7-bit counter, bit 7 preserved.\nfn r_inc() { cpu_r = (cpu_r & 0x80u) | ((cpu_r + 1u) & 0x7fu); }\n// Index-prefix state for the instruction currently executing:\n// idx_mode: 0 = HL, 1 = IX, 2 = IY\n// idx_disp: sign-extended displacement for (IX+d)/(IY+d)\n// idx_uses_mem: 1 when this instruction dereferences (IX+d)/(IY+d), which\n// means H/L operands are NOT substituted by IXH/IXL (real Z80 rule).\nvar<private> idx_mode: u32;\nvar<private> idx_disp: u32;\nvar<private> idx_uses_mem: u32;\n\n// HOST CONTRACT: the host shader must declare the following BEFORE this core:\n// fn mem_read(addr: u32) -> u32 // read one byte from memory\n// fn mem_write(addr: u32, val: u32) // write one byte to memory\n// fn on_fetch_opcode(prefix: u32, op: u32) -> bool // return true to skip (NOP)\n// // the decoded instruction\n// The hook fires once per executed instruction, after full prefix resolution, with\n// prefix = 0u base page (op = the opcode byte)\n// prefix = 0xddu / 0xfdu IX / IY form of a base-page opcode (op = the opcode byte)\n// prefix = 0xcbu CB page (op = the byte after CB)\n// prefix = 0xedu ED page (op = the byte after ED)\n// prefix = 0xddcbu / 0xfdcbu DDCB / FDCB page (op = the byte after the displacement)\n// Prefix bytes themselves (CB, ED, DD, FD) are never reported as op. When the\n// hook returns true the opcode byte(s) and prefix are consumed and nothing\n// executes: a 1-byte NOP for base-page opcodes (operand bytes are NOT skipped \u2014\n// they run as the next instruction, exactly as if the opcode had been removed\n// from the ISA), a 2-byte NOP for CB/ED-page opcodes (like undefined ED opcodes\n// on a real Z80), and a 4-byte NOP for DDCB/FDCB. R increments as for a real\n// fetch. This lets the host choose the memory model (mask, modulo, storage\n// buffer, \u2026) and ablate instructions precisely. See buildComputeShader.\n\n// Z80 flag bits\nconst CF: u32 = 0x01u;\nconst NF: u32 = 0x02u;\nconst PF: u32 = 0x04u;\nconst F3: u32 = 0x08u;\nconst HF: u32 = 0x10u;\nconst F5: u32 = 0x20u;\nconst ZF: u32 = 0x40u;\nconst SFl: u32 = 0x80u;\n\n\nfn z80_fetch() -> u32 {\n let val = mem_read(cpu_pc);\n cpu_pc = (cpu_pc + 1u) & 0xffffu;\n return val;\n}\n\nfn z80_fetch_word() -> u32 {\n let lo = z80_fetch();\n let hi = z80_fetch();\n return (hi << 8u) | lo;\n}\n\nfn z80_push16(val: u32) {\n cpu_sp = (cpu_sp - 1u) & 0xffffu;\n mem_write(cpu_sp, (val >> 8u) & 0xffu);\n cpu_sp = (cpu_sp - 1u) & 0xffffu;\n mem_write(cpu_sp, val & 0xffu);\n}\n\nfn z80_pop16() -> u32 {\n let lo = mem_read(cpu_sp);\n cpu_sp = (cpu_sp + 1u) & 0xffffu;\n let hi = mem_read(cpu_sp);\n cpu_sp = (cpu_sp + 1u) & 0xffffu;\n return (hi << 8u) | lo;\n}\n\nfn signed_byte(b: u32) -> i32 {\n let sb = i32(b);\n if (sb > 127) { return sb - 256; }\n return sb;\n}\n\n// === Register Access ===\nfn get_bc() -> u32 { return (cpu_b << 8u) | cpu_c; }\nfn get_de() -> u32 { return (cpu_d << 8u) | cpu_e; }\nfn get_hl() -> u32 { return (cpu_h << 8u) | cpu_l; }\nfn get_af() -> u32 { return (cpu_a << 8u) | cpu_f; }\n\nfn set_bc(v: u32) { cpu_b = (v >> 8u) & 0xffu; cpu_c = v & 0xffu; }\nfn set_de(v: u32) { cpu_d = (v >> 8u) & 0xffu; cpu_e = v & 0xffu; }\nfn set_hl(v: u32) { cpu_h = (v >> 8u) & 0xffu; cpu_l = v & 0xffu; }\nfn set_af(v: u32) { cpu_a = (v >> 8u) & 0xffu; cpu_f = v & 0xffu; }\n\nfn get_reg(idx: u32) -> u32 {\n switch(idx) {\n case 0u: { return cpu_b; }\n case 1u: { return cpu_c; }\n case 2u: { return cpu_d; }\n case 3u: { return cpu_e; }\n case 4u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { return (idx_reg16() >> 8u) & 0xffu; } // IXH/IYH\n return cpu_h;\n }\n case 5u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { return idx_reg16() & 0xffu; } // IXL/IYL\n return cpu_l;\n }\n case 6u: { return mem_read(idx_addr()); }\n case 7u: { return cpu_a; }\n default: { return 0u; }\n }\n}\n\nfn set_reg(idx: u32, val: u32) {\n let v = val & 0xffu;\n switch(idx) {\n case 0u: { cpu_b = v; }\n case 1u: { cpu_c = v; }\n case 2u: { cpu_d = v; }\n case 3u: { cpu_e = v; }\n case 4u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { set_idx_reg16((idx_reg16() & 0x00ffu) | (v << 8u)); }\n else { cpu_h = v; }\n }\n case 5u: {\n if (idx_mode != 0u && idx_uses_mem == 0u) { set_idx_reg16((idx_reg16() & 0xff00u) | v); }\n else { cpu_l = v; }\n }\n case 6u: { mem_write(idx_addr(), v); }\n case 7u: { cpu_a = v; }\n default: {}\n }\n}\n\nfn get_reg16(idx: u32) -> u32 {\n switch(idx) {\n case 0u: { return get_bc(); }\n case 1u: { return get_de(); }\n case 2u: { return idx_reg16(); } // HL / IX / IY\n case 3u: { return cpu_sp; }\n default: { return 0u; }\n }\n}\n\nfn set_reg16(idx: u32, val: u32) {\n let v = val & 0xffffu;\n switch(idx) {\n case 0u: { set_bc(v); }\n case 1u: { set_de(v); }\n case 2u: { set_idx_reg16(v); } // HL / IX / IY\n case 3u: { cpu_sp = v; }\n default: {}\n }\n}\n\nfn get_reg16_af(idx: u32) -> u32 {\n if (idx == 3u) { return get_af(); }\n return get_reg16(idx);\n}\n\nfn set_reg16_af(idx: u32, val: u32) {\n if (idx == 3u) { set_af(val); } else { set_reg16(idx, val); }\n}\n\n// === Index register (IX/IY) helpers ===\n// The 16-bit register the current prefix maps HL to (HL itself when no prefix).\nfn idx_reg16() -> u32 {\n if (idx_mode == 1u) { return cpu_ix; }\n if (idx_mode == 2u) { return cpu_iy; }\n return get_hl();\n}\nfn set_idx_reg16(v: u32) {\n if (idx_mode == 1u) { cpu_ix = v & 0xffffu; }\n else if (idx_mode == 2u) { cpu_iy = v & 0xffffu; }\n else { set_hl(v); }\n}\n// Address used for (HL) / (IX+d) / (IY+d).\nfn idx_addr() -> u32 {\n if (idx_mode != 0u) { return (idx_reg16() + idx_disp) & 0xffffu; }\n return get_hl();\n}\n// Sign-extend a displacement byte to 16 bits (two's complement).\nfn signext(b: u32) -> u32 {\n if (b >= 0x80u) { return b | 0xff00u; }\n return b;\n}\n// Does this main opcode dereference (HL)? (Determines displacement fetch and\n// whether H/L operands are IXH/IXL or real H/L under a DD/FD prefix.)\nfn op_uses_hl_mem(op: u32) -> bool {\n let x = (op >> 6u) & 3u;\n let y = (op >> 3u) & 7u;\n let z = op & 7u;\n if (x == 1u) { return (y == 6u || z == 6u) && !(y == 6u && z == 6u); } // LD r,(HL)/(HL),r (not HALT)\n if (x == 2u) { return z == 6u; } // ALU A,(HL)\n if (x == 0u) {\n if (z == 4u || z == 5u || z == 6u) { return y == 6u; } // INC/DEC (HL), LD (HL),n\n return false;\n }\n return false;\n}\n// Write a REAL 8-bit register (no IX/IY substitution) \u2014 used by the\n// undocumented DDCB/FDCB register-copy side effect.\nfn set_reg_raw(idx: u32, val: u32) {\n let v = val & 0xffu;\n switch(idx) {\n case 0u: { cpu_b = v; }\n case 1u: { cpu_c = v; }\n case 2u: { cpu_d = v; }\n case 3u: { cpu_e = v; }\n case 4u: { cpu_h = v; }\n case 5u: { cpu_l = v; }\n case 7u: { cpu_a = v; }\n default: {}\n }\n}\n\n// === Flag Helpers ===\nfn sz_flags(val: u32) -> u32 {\n var f = val & SFl;\n if (val == 0u) { f |= ZF; }\n f |= val & (F3 | F5);\n return f;\n}\n\nfn parity(val: u32) -> bool {\n var p = val;\n p ^= p >> 4u;\n p ^= p >> 2u;\n p ^= p >> 1u;\n return (p & 1u) == 0u;\n}\n\nfn check_cc(cc: u32) -> bool {\n switch(cc) {\n case 0u: { return (cpu_f & ZF) == 0u; }\n case 1u: { return (cpu_f & ZF) != 0u; }\n case 2u: { return (cpu_f & CF) == 0u; }\n case 3u: { return (cpu_f & CF) != 0u; }\n case 4u: { return (cpu_f & PF) == 0u; }\n case 5u: { return (cpu_f & PF) != 0u; }\n case 6u: { return (cpu_f & SFl) == 0u; }\n case 7u: { return (cpu_f & SFl) != 0u; }\n default: { return false; }\n }\n}\n\n// === ALU ===\nfn z80_alu(op: u32, val: u32) {\n let a = cpu_a;\n let c = cpu_f & CF;\n switch(op) {\n case 0u: { // ADD\n let r = a + val;\n cpu_f = sz_flags(r & 0xffu) | select(0u, CF, r > 0xffu) |\n ((a ^ val ^ r) & HF) |\n select(0u, PF, ((~(a ^ val)) & (a ^ r) & 0x80u) != 0u);\n cpu_a = r & 0xffu;\n }\n case 1u: { // ADC\n let r = a + val + c;\n cpu_f = sz_flags(r & 0xffu) | select(0u, CF, r > 0xffu) |\n ((a ^ val ^ r) & HF) |\n select(0u, PF, ((~(a ^ val)) & (a ^ r) & 0x80u) != 0u);\n cpu_a = r & 0xffu;\n }\n case 2u: { // SUB\n let r = i32(a) - i32(val);\n let ru = u32(r) & 0xffu;\n cpu_f = sz_flags(ru) | NF | select(0u, CF, r < 0) |\n ((a ^ val ^ u32(r)) & HF) |\n select(0u, PF, (((a ^ val) & (a ^ u32(r))) & 0x80u) != 0u);\n cpu_a = ru;\n }\n case 3u: { // SBC\n let r = i32(a) - i32(val) - i32(c);\n let ru = u32(r) & 0xffu;\n cpu_f = sz_flags(ru) | NF | select(0u, CF, r < 0) |\n ((a ^ val ^ u32(r)) & HF) |\n select(0u, PF, (((a ^ val) & (a ^ u32(r))) & 0x80u) != 0u);\n cpu_a = ru;\n }\n case 4u: { // AND\n cpu_a = a & val;\n cpu_f = sz_flags(cpu_a) | HF | select(0u, PF, parity(cpu_a));\n }\n case 5u: { // XOR\n cpu_a = a ^ val;\n cpu_f = sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n case 6u: { // OR\n cpu_a = a | val;\n cpu_f = sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n case 7u: { // CP\n let r = i32(a) - i32(val);\n let ru = u32(r) & 0xffu;\n cpu_f = (ru & SFl) | select(0u, ZF, ru == 0u) | (val & (F3 | F5)) | NF |\n select(0u, CF, r < 0) | ((a ^ val ^ u32(r)) & HF) |\n select(0u, PF, (((a ^ val) & (a ^ u32(r))) & 0x80u) != 0u);\n }\n default: {}\n }\n}\n\nfn z80_inc8(val: u32) -> u32 {\n let r = (val + 1u) & 0xffu;\n cpu_f = (cpu_f & CF) | sz_flags(r) |\n select(0u, PF, val == 0x7fu) |\n select(0u, HF, (r & 0x0fu) == 0u);\n return r;\n}\n\nfn z80_dec8(val: u32) -> u32 {\n let r = (val - 1u) & 0xffu;\n cpu_f = (cpu_f & CF) | sz_flags(r) | NF |\n select(0u, PF, val == 0x80u) |\n select(0u, HF, (val & 0x0fu) == 0u);\n return r;\n}\n\nfn z80_add_hl(val: u32) {\n let hl = idx_reg16(); // ADD HL,rp / ADD IX,rp / ADD IY,rp\n let r = hl + val;\n cpu_f = (cpu_f & (SFl | ZF | PF)) |\n select(0u, CF, r > 0xffffu) |\n select(0u, HF, ((hl ^ val ^ r) & 0x1000u) != 0u) |\n ((r >> 8u) & (F3 | F5));\n set_idx_reg16(r & 0xffffu);\n}\n\n// === Rotate/Shift for accumulator ===\nfn z80_rot_accum(y: u32) {\n let a = cpu_a;\n let c = cpu_f & CF;\n let keep = cpu_f & (SFl | ZF | PF);\n switch(y) {\n case 0u: { // RLCA\n cpu_a = ((a << 1u) | (a >> 7u)) & 0xffu;\n cpu_f = keep | (a >> 7u) | (cpu_a & (F3 | F5));\n }\n case 1u: { // RRCA\n cpu_a = ((a >> 1u) | (a << 7u)) & 0xffu;\n cpu_f = keep | (a & 1u) | (cpu_a & (F3 | F5));\n }\n case 2u: { // RLA\n cpu_a = ((a << 1u) | c) & 0xffu;\n cpu_f = keep | (a >> 7u) | (cpu_a & (F3 | F5));\n }\n case 3u: { // RRA\n cpu_a = ((a >> 1u) | (c << 7u)) & 0xffu;\n cpu_f = keep | (a & 1u) | (cpu_a & (F3 | F5));\n }\n case 4u: { // DAA\n var correction = 0u;\n var carry = c;\n if ((cpu_f & HF) != 0u || (a & 0x0fu) > 9u) { correction |= 0x06u; }\n if (c != 0u || a > 0x99u) { correction |= 0x60u; carry = 1u; }\n if ((cpu_f & NF) != 0u) { cpu_a = (a - correction) & 0xffu; }\n else { cpu_a = (a + correction) & 0xffu; }\n cpu_f = (cpu_f & NF) | sz_flags(cpu_a) | carry |\n ((a ^ cpu_a) & HF) | select(0u, PF, parity(cpu_a));\n }\n case 5u: { // CPL\n cpu_a = (~a) & 0xffu;\n cpu_f = (cpu_f & (SFl | ZF | PF | CF)) | HF | NF | (cpu_a & (F3 | F5));\n }\n case 6u: { // SCF\n cpu_f = (cpu_f & (SFl | ZF | PF)) | CF | (cpu_a & (F3 | F5));\n }\n case 7u: { // CCF\n cpu_f = (cpu_f & (SFl | ZF | PF)) |\n select(0u, HF, c != 0u) |\n select(CF, 0u, c != 0u) |\n (cpu_a & (F3 | F5));\n }\n default: {}\n }\n}\n\n// === CB Prefix (bit ops, rotates, shifts) ===\nfn z80_cb_rot(op: u32, val: u32) -> u32 {\n let c = cpu_f & CF;\n var r = 0u;\n switch(op) {\n case 0u: { r = ((val << 1u) | (val >> 7u)) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 1u: { r = ((val >> 1u) | (val << 7u)) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n case 2u: { r = ((val << 1u) | c) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 3u: { r = ((val >> 1u) | (c << 7u)) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n case 4u: { r = (val << 1u) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 5u: { r = ((val >> 1u) | (val & 0x80u)) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n case 6u: { r = ((val << 1u) | 1u) & 0xffu; cpu_f = sz_flags(r) | (val >> 7u) | select(0u, PF, parity(r)); }\n case 7u: { r = (val >> 1u) & 0xffu; cpu_f = sz_flags(r) | (val & 1u) | select(0u, PF, parity(r)); }\n default: { r = val; }\n }\n return r;\n}\n\nfn z80_exec_cb() {\n let op = z80_fetch();\n r_inc(); // M1: CB-page opcode fetch\n if (on_fetch_opcode(0xcbu, op)) { return; } // host hook (2-byte NOP)\n let x = (op >> 6u) & 3u;\n let y = (op >> 3u) & 7u;\n let z = op & 7u;\n let val = get_reg(z);\n switch(x) {\n case 0u: { set_reg(z, z80_cb_rot(y, val)); }\n case 1u: { // BIT\n cpu_f = (cpu_f & CF) | HF |\n select(0u, ZF | PF, (val & (1u << y)) == 0u) |\n select(0u, SFl, y == 7u && (val & 0x80u) != 0u) |\n (val & (F3 | F5));\n }\n case 2u: { set_reg(z, val & ~(1u << y)); }\n case 3u: { set_reg(z, val | (1u << y)); }\n default: {}\n }\n}\n\n// DDCB / FDCB: operates on (IX+d)/(IY+d). The displacement (idx_disp) has\n// already been fetched. For rot/shift/RES/SET the result is written to memory\n// AND (undocumented) copied to the real register in the low 3 bits unless it is\n// 6. For BIT, the undocumented F3/F5 come from the high byte of the address.\nfn z80_exec_idxcb(cbop: u32) {\n let addr = (idx_reg16() + idx_disp) & 0xffffu;\n let cx = (cbop >> 6u) & 3u;\n let cy = (cbop >> 3u) & 7u;\n let cz = cbop & 7u;\n let val = mem_read(addr);\n switch(cx) {\n case 0u: {\n let r = z80_cb_rot(cy, val);\n mem_write(addr, r);\n if (cz != 6u) { set_reg_raw(cz, r); }\n }\n case 1u: { // BIT n,(IX+d)\n cpu_f = (cpu_f & CF) | HF |\n select(0u, ZF | PF, (val & (1u << cy)) == 0u) |\n select(0u, SFl, cy == 7u && (val & 0x80u) != 0u) |\n ((addr >> 8u) & (F3 | F5));\n }\n case 2u: {\n let r = val & ~(1u << cy);\n mem_write(addr, r);\n if (cz != 6u) { set_reg_raw(cz, r); }\n }\n case 3u: {\n let r = val | (1u << cy);\n mem_write(addr, r);\n if (cz != 6u) { set_reg_raw(cz, r); }\n }\n default: {}\n }\n}\n\n// === Block Transfer (ED prefix) ===\nfn z80_ldi() {\n let val = mem_read(get_hl());\n mem_write(get_de(), val);\n set_hl((get_hl() + 1u) & 0xffffu);\n set_de((get_de() + 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n let n = (val + cpu_a) & 0xffu;\n cpu_f = (cpu_f & (SFl | ZF | CF)) |\n select(0u, PF, get_bc() != 0u) |\n (n & F3) | select(0u, F5, (n & 0x02u) != 0u);\n}\n\nfn z80_ldd() {\n let val = mem_read(get_hl());\n mem_write(get_de(), val);\n set_hl((get_hl() - 1u) & 0xffffu);\n set_de((get_de() - 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n let n = (val + cpu_a) & 0xffu;\n cpu_f = (cpu_f & (SFl | ZF | CF)) |\n select(0u, PF, get_bc() != 0u) |\n (n & F3) | select(0u, F5, (n & 0x02u) != 0u);\n}\n\nfn z80_cpi() {\n let val = mem_read(get_hl());\n let r = (cpu_a - val) & 0xffu;\n let hf = (cpu_a ^ val ^ r) & HF;\n // Undocumented F3/F5 come from n = A-(HL)-HF (bit 3 -> F3, bit 1 -> F5).\n let n = (r - select(0u, 1u, hf != 0u)) & 0xffu;\n set_hl((get_hl() + 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n cpu_f = (cpu_f & CF) | (r & SFl) | select(0u, ZF, r == 0u) | NF |\n hf | select(0u, PF, get_bc() != 0u) |\n (n & F3) | ((n & 0x02u) << 4u);\n}\n\nfn z80_cpd() {\n let val = mem_read(get_hl());\n let r = (cpu_a - val) & 0xffu;\n let hf = (cpu_a ^ val ^ r) & HF;\n let n = (r - select(0u, 1u, hf != 0u)) & 0xffu;\n set_hl((get_hl() - 1u) & 0xffffu);\n set_bc((get_bc() - 1u) & 0xffffu);\n cpu_f = (cpu_f & CF) | (r & SFl) | select(0u, ZF, r == 0u) | NF |\n hf | select(0u, PF, get_bc() != 0u) |\n (n & F3) | ((n & 0x02u) << 4u);\n}\n\n// === ED Prefix ===\nfn z80_exec_ed() {\n let op = z80_fetch();\n r_inc(); // M1: ED-page opcode fetch\n if (on_fetch_opcode(0xedu, op)) { return; } // host hook (2-byte NOP)\n switch(op) {\n case 0xa0u: { z80_ldi(); }\n case 0xa8u: { z80_ldd(); }\n case 0xb0u: { z80_ldi(); if (get_bc() != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } } // LDIR\n case 0xb8u: { z80_ldd(); if (get_bc() != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } } // LDDR\n case 0xa1u: { z80_cpi(); }\n case 0xa9u: { z80_cpd(); }\n case 0xb1u: { z80_cpi(); if (get_bc() != 0u && (cpu_f & ZF) == 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } }\n case 0xb9u: { z80_cpd(); if (get_bc() != 0u && (cpu_f & ZF) == 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; } }\n // NEG\n case 0x44u, 0x4cu, 0x54u, 0x5cu, 0x64u, 0x6cu, 0x74u, 0x7cu: {\n let a = cpu_a; cpu_a = 0u; z80_alu(2u, a);\n }\n // RETN/RETI\n case 0x45u, 0x4du, 0x55u, 0x5du, 0x65u, 0x6du, 0x75u, 0x7du: {\n cpu_iff1 = cpu_iff2; cpu_pc = z80_pop16();\n }\n // LD I,A / LD R,A / LD A,I / LD A,R\n case 0x47u: { cpu_i = cpu_a; } // LD I,A\n case 0x4fu: { cpu_r = cpu_a; } // LD R,A\n // LD A,I / LD A,R: load I or R into A. Flags: S/Z (+F3/F5) from the loaded\n // value, PF = IFF2, N/H reset, C preserved.\n case 0x57u: { cpu_a = cpu_i; cpu_f = (cpu_f & CF) | sz_flags(cpu_i) | select(0u, PF, cpu_iff2 != 0u); }\n case 0x5fu: { cpu_a = cpu_r; cpu_f = (cpu_f & CF) | sz_flags(cpu_r) | select(0u, PF, cpu_iff2 != 0u); }\n // LD (nn), rr\n case 0x43u, 0x53u, 0x63u, 0x73u: {\n let nn = z80_fetch_word();\n let rp = (op >> 4u) & 3u;\n let val = get_reg16(rp);\n mem_write(nn, val & 0xffu);\n mem_write((nn + 1u) & 0xffffu, (val >> 8u) & 0xffu);\n }\n // LD rr, (nn)\n case 0x4bu, 0x5bu, 0x6bu, 0x7bu: {\n let nn = z80_fetch_word();\n let rp = (op >> 4u) & 3u;\n let lo = mem_read(nn);\n let hi = mem_read((nn + 1u) & 0xffffu);\n set_reg16(rp, (hi << 8u) | lo);\n }\n // ADC HL, rr\n case 0x4au, 0x5au, 0x6au, 0x7au: {\n let rp = (op >> 4u) & 3u;\n let hl = get_hl();\n let val = get_reg16(rp);\n let c = cpu_f & CF;\n let r = hl + val + c;\n cpu_f = ((r >> 8u) & SFl) | select(0u, ZF, (r & 0xffffu) == 0u) |\n select(0u, HF, ((hl ^ val ^ r) & 0x1000u) != 0u) |\n select(0u, PF, ((~(hl ^ val)) & (hl ^ r) & 0x8000u) != 0u) |\n select(0u, CF, r > 0xffffu) | ((r >> 8u) & (F3 | F5));\n set_hl(r & 0xffffu);\n }\n // SBC HL, rr\n case 0x42u, 0x52u, 0x62u, 0x72u: {\n let rp = (op >> 4u) & 3u;\n let hl = get_hl();\n let val = get_reg16(rp);\n let c = cpu_f & CF;\n let r = i32(hl) - i32(val) - i32(c);\n let ru = u32(r) & 0xffffu;\n cpu_f = ((ru >> 8u) & SFl) | select(0u, ZF, ru == 0u) | NF |\n select(0u, HF, ((hl ^ val ^ u32(r)) & 0x1000u) != 0u) |\n select(0u, PF, (((hl ^ val) & (hl ^ u32(r))) & 0x8000u) != 0u) |\n select(0u, CF, r < 0) | ((ru >> 8u) & (F3 | F5));\n set_hl(ru);\n }\n // RRD\n case 0x67u: {\n let m = mem_read(get_hl());\n mem_write(get_hl(), ((cpu_a << 4u) | (m >> 4u)) & 0xffu);\n cpu_a = (cpu_a & 0xf0u) | (m & 0x0fu);\n cpu_f = (cpu_f & CF) | sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n // RLD\n case 0x6fu: {\n let m = mem_read(get_hl());\n mem_write(get_hl(), ((m << 4u) | (cpu_a & 0x0fu)) & 0xffu);\n cpu_a = (cpu_a & 0xf0u) | (m >> 4u);\n cpu_f = (cpu_f & CF) | sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));\n }\n // IN r,(C): no I/O device, so the port reads 0. Store it (except for the\n // reg-6 form IN (C), which only sets flags) and set S/Z/F3/F5/P flags.\n case 0x40u, 0x48u, 0x50u, 0x58u, 0x60u, 0x68u, 0x70u, 0x78u: {\n let val = 0u;\n let reg = (op >> 3u) & 7u;\n if (reg != 6u) { set_reg(reg, val); }\n cpu_f = (cpu_f & CF) | sz_flags(val) | select(0u, PF, parity(val));\n }\n // Block input: INI (A2) / IND (AA) / INIR (B2) / INDR (BA). No I/O\n // device, so the port reads 0. Writes it to (HL), decrements B, moves HL,\n // sets the block-I/O flags, and repeats (R-forms) while B != 0.\n case 0xa2u, 0xaau, 0xb2u, 0xbau: {\n let val = 0u;\n mem_write(get_hl(), val);\n cpu_b = (cpu_b - 1u) & 0xffu;\n let dec = (op & 0x08u) != 0u;\n let s = (val + cpu_c) & 0xffu;\n let other = select((s + 1u) & 0xffu, (s - 1u) & 0xffu, dec);\n cpu_f = select(0u, NF, (val & 0x80u) != 0u) |\n select(0u, HF | CF, other < val) |\n select(0u, PF, parity((other & 7u) ^ cpu_b)) |\n sz_flags(cpu_b);\n if (dec) { set_hl((get_hl() - 1u) & 0xffffu); } else { set_hl((get_hl() + 1u) & 0xffffu); }\n if ((op & 0x10u) != 0u && cpu_b != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; }\n }\n // Block output: OUTI (A3) / OUTD (AB) / OTIR (B3) / OTDR (BB). Reads (HL),\n // decrements B, moves HL, sends to the (absent) port, sets flags, repeats.\n case 0xa3u, 0xabu, 0xb3u, 0xbbu: {\n let val = mem_read(get_hl());\n cpu_b = (cpu_b - 1u) & 0xffu;\n let dec = (op & 0x08u) != 0u;\n if (dec) { set_hl((get_hl() - 1u) & 0xffffu); } else { set_hl((get_hl() + 1u) & 0xffffu); }\n let other = (val + cpu_l) & 0xffu;\n cpu_f = select(0u, NF, (val & 0x80u) != 0u) |\n select(0u, HF | CF, other < val) |\n select(0u, PF, parity((other & 7u) ^ cpu_b)) |\n sz_flags(cpu_b);\n if ((op & 0x10u) != 0u && cpu_b != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; }\n }\n default: {} // unknown ED ops = NOP\n }\n}\n\n// === Main Opcode Execution ===\nfn z80_exec_x0(y: u32, z: u32, p: u32, q: u32) {\n switch(z) {\n case 0u: {\n switch(y) {\n case 0u: {} // NOP\n case 1u: { // EX AF,AF'\n var t = cpu_a; cpu_a = cpu_a2; cpu_a2 = t;\n t = cpu_f; cpu_f = cpu_f2; cpu_f2 = t;\n }\n case 2u: { // DJNZ\n let d = signed_byte(z80_fetch());\n cpu_b = (cpu_b - 1u) & 0xffu;\n if (cpu_b != 0u) { cpu_pc = u32(i32(cpu_pc) + d) & 0xffffu; }\n }\n case 3u: { // JR\n let d = signed_byte(z80_fetch());\n cpu_pc = u32(i32(cpu_pc) + d) & 0xffffu;\n }\n default: { // JR cc (y-4)\n let d = signed_byte(z80_fetch());\n if (check_cc(y - 4u)) { cpu_pc = u32(i32(cpu_pc) + d) & 0xffffu; }\n }\n }\n }\n case 1u: {\n if (q == 0u) { set_reg16(p, z80_fetch_word()); }\n else { z80_add_hl(get_reg16(p)); }\n }\n case 2u: {\n if (q == 0u) {\n switch(p) {\n case 0u: { mem_write(get_bc(), cpu_a); }\n case 1u: { mem_write(get_de(), cpu_a); }\n case 2u: { let nn = z80_fetch_word(); let hl = idx_reg16(); mem_write(nn, hl & 0xffu); mem_write((nn+1u) & 0xffffu, (hl >> 8u) & 0xffu); }\n case 3u: { mem_write(z80_fetch_word(), cpu_a); }\n default: {}\n }\n } else {\n switch(p) {\n case 0u: { cpu_a = mem_read(get_bc()); }\n case 1u: { cpu_a = mem_read(get_de()); }\n case 2u: { let nn = z80_fetch_word(); let lo = mem_read(nn); let hi = mem_read((nn+1u) & 0xffffu); set_idx_reg16((hi << 8u) | lo); }\n case 3u: { cpu_a = mem_read(z80_fetch_word()); }\n default: {}\n }\n }\n }\n case 3u: {\n if (q == 0u) { set_reg16(p, (get_reg16(p) + 1u) & 0xffffu); }\n else { set_reg16(p, (get_reg16(p) - 1u) & 0xffffu); }\n }\n case 4u: { set_reg(y, z80_inc8(get_reg(y))); }\n case 5u: { set_reg(y, z80_dec8(get_reg(y))); }\n case 6u: { set_reg(y, z80_fetch()); }\n case 7u: { z80_rot_accum(y); }\n default: {}\n }\n}\n\nfn z80_exec_x3(y: u32, z: u32, p: u32, q: u32) {\n switch(z) {\n case 0u: { if (check_cc(y)) { cpu_pc = z80_pop16(); } }\n case 1u: {\n if (q == 0u) { set_reg16_af(p, z80_pop16()); }\n else {\n switch(p) {\n case 0u: { cpu_pc = z80_pop16(); } // RET\n case 1u: { // EXX\n var t = cpu_b; cpu_b = cpu_b2; cpu_b2 = t;\n t = cpu_c; cpu_c = cpu_c2; cpu_c2 = t;\n t = cpu_d; cpu_d = cpu_d2; cpu_d2 = t;\n t = cpu_e; cpu_e = cpu_e2; cpu_e2 = t;\n t = cpu_h; cpu_h = cpu_h2; cpu_h2 = t;\n t = cpu_l; cpu_l = cpu_l2; cpu_l2 = t;\n }\n case 2u: { cpu_pc = idx_reg16(); } // JP (HL)/(IX)/(IY)\n case 3u: { cpu_sp = idx_reg16(); } // LD SP,HL/IX/IY\n default: {}\n }\n }\n }\n case 2u: { let nn = z80_fetch_word(); if (check_cc(y)) { cpu_pc = nn; } }\n case 3u: {\n switch(y) {\n case 0u: { cpu_pc = z80_fetch_word(); } // JP nn\n case 1u: { z80_exec_cb(); }\n case 2u: { z80_fetch(); } // OUT (n),A - no I/O device, discard (matches zff outPort no-op)\n case 3u: { z80_fetch(); cpu_a = 0u; } // IN A,(n) - no I/O device, reads 0 (matches zff inPort\u21920)\n case 4u: { // EX (SP),HL / EX (SP),IX / EX (SP),IY\n let lo = mem_read(cpu_sp);\n let hi = mem_read((cpu_sp + 1u) & 0xffffu);\n let hl = idx_reg16();\n mem_write(cpu_sp, hl & 0xffu);\n mem_write((cpu_sp + 1u) & 0xffffu, (hl >> 8u) & 0xffu);\n set_idx_reg16((hi << 8u) | lo);\n }\n case 5u: { // EX DE,HL\n let td = cpu_d; let te = cpu_e;\n cpu_d = cpu_h; cpu_e = cpu_l;\n cpu_h = td; cpu_l = te;\n }\n case 6u: { cpu_iff1 = 0u; cpu_iff2 = 0u; }\n case 7u: { cpu_iff1 = 1u; cpu_iff2 = 1u; }\n default: {}\n }\n }\n case 4u: { let nn = z80_fetch_word(); if (check_cc(y)) { z80_push16(cpu_pc); cpu_pc = nn; } }\n case 5u: {\n if (q == 0u) { z80_push16(get_reg16_af(p)); }\n else {\n switch(p) {\n case 0u: { let nn = z80_fetch_word(); z80_push16(cpu_pc); cpu_pc = nn; } // CALL nn\n case 1u, 3u: {} // DD/FD prefix handled in z80_step\n case 2u: { z80_exec_ed(); }\n default: {}\n }\n }\n }\n case 6u: { z80_alu(y, z80_fetch()); }\n case 7u: { z80_push16(cpu_pc); cpu_pc = y * 8u; } // RST\n default: {}\n }\n}\n\nfn z80_execute(op: u32) {\n let x = (op >> 6u) & 3u;\n let y = (op >> 3u) & 7u;\n let z = op & 7u;\n let p = (y >> 1u) & 3u;\n let q = y & 1u;\n switch(x) {\n case 0u: { z80_exec_x0(y, z, p, q); }\n case 1u: {\n if (y == 6u && z == 6u) {\n // HALT: mark halted and back PC up onto the HALT opcode so the\n // CPU re-executes it every step until an interrupt.\n cpu_halted = 1u;\n cpu_pc = (cpu_pc - 1u) & 0xffffu;\n }\n else { set_reg(y, get_reg(z)); }\n }\n case 2u: { z80_alu(y, get_reg(z)); }\n case 3u: { z80_exec_x3(y, z, p, q); }\n default: {}\n }\n}\n\nfn z80_step() {\n // While halted, the CPU keeps executing HALT: each step is an M1 fetch of\n // the same opcode (R increments), PC stays put. It resumes only on interrupt.\n if (cpu_halted != 0u) { r_inc(); return; }\n // Reset per-instruction index-prefix state.\n idx_mode = 0u;\n idx_uses_mem = 0u;\n idx_disp = 0u;\n\n var op = z80_fetch();\n r_inc(); // M1: opcode (or prefix) fetch\n // A DD/FD prefix selects IX/IY for the following opcode.\n if (op == 0xddu || op == 0xfdu) {\n idx_mode = select(2u, 1u, op == 0xddu);\n let next = z80_fetch();\n r_inc(); // M1: opcode after the prefix\n // A prefix immediately followed by another prefix or ED is a wasted M1:\n // this step consumes just the prefix; back up so the next step restarts\n // at the following byte (matches real Z80 timing and avoids an\n // unbounded fetch loop on all-prefix programs).\n if (next == 0xddu || next == 0xfdu || next == 0xedu) {\n cpu_pc = (cpu_pc - 1u) & 0xffffu;\n return;\n }\n op = next;\n }\n\n // Host hook for base-page opcodes (and their IX/IY forms). The CB and ED\n // prefix bytes are not reported here; their pages report from their own\n // dispatch with prefix = 0xCB / 0xED / 0xDDCB / 0xFDCB.\n if (op != 0xcbu && op != 0xedu) {\n let pfx = select(select(0xfdu, 0xddu, idx_mode == 1u), 0u, idx_mode == 0u);\n if (on_fetch_opcode(pfx, op)) { return; }\n }\n\n if (idx_mode != 0u) {\n if (op == 0xcbu) {\n // DDCB/FDCB: displacement precedes the CB opcode.\n idx_disp = signext(z80_fetch());\n let cbop = z80_fetch();\n let pfx = select(0xfdcbu, 0xddcbu, idx_mode == 1u);\n if (on_fetch_opcode(pfx, cbop)) { return; } // host hook (4-byte NOP)\n z80_exec_idxcb(cbop);\n return;\n }\n if (op_uses_hl_mem(op)) {\n idx_uses_mem = 1u;\n idx_disp = signext(z80_fetch());\n }\n }\n z80_execute(op);\n}\n";
2
2
  //# sourceMappingURL=z80-core.wgsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"z80-core.wgsl.d.ts","sourceRoot":"","sources":["../src/z80-core.wgsl.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa,gv6BA+xBzB,CAAC"}
1
+ {"version":3,"file":"z80-core.wgsl.d.ts","sourceRoot":"","sources":["../src/z80-core.wgsl.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa,ixhCAu1BzB,CAAC"}
@@ -43,12 +43,24 @@ var<private> idx_disp: u32;
43
43
  var<private> idx_uses_mem: u32;
44
44
 
45
45
  // HOST CONTRACT: the host shader must declare the following BEFORE this core:
46
- // fn mem_read(addr: u32) -> u32 // read one byte from memory
47
- // fn mem_write(addr: u32, val: u32) // write one byte to memory
48
- // fn on_fetch_opcode(op: u32) -> bool // return true to skip (NOP) an
49
- // // opcode after prefix resolution
50
- // This lets the host choose the memory model (mask, modulo, storage buffer, â€Ķ)
51
- // and hook opcode execution (e.g. instruction suppression). See buildComputeShader.
46
+ // fn mem_read(addr: u32) -> u32 // read one byte from memory
47
+ // fn mem_write(addr: u32, val: u32) // write one byte to memory
48
+ // fn on_fetch_opcode(prefix: u32, op: u32) -> bool // return true to skip (NOP)
49
+ // // the decoded instruction
50
+ // The hook fires once per executed instruction, after full prefix resolution, with
51
+ // prefix = 0u base page (op = the opcode byte)
52
+ // prefix = 0xddu / 0xfdu IX / IY form of a base-page opcode (op = the opcode byte)
53
+ // prefix = 0xcbu CB page (op = the byte after CB)
54
+ // prefix = 0xedu ED page (op = the byte after ED)
55
+ // prefix = 0xddcbu / 0xfdcbu DDCB / FDCB page (op = the byte after the displacement)
56
+ // Prefix bytes themselves (CB, ED, DD, FD) are never reported as op. When the
57
+ // hook returns true the opcode byte(s) and prefix are consumed and nothing
58
+ // executes: a 1-byte NOP for base-page opcodes (operand bytes are NOT skipped —
59
+ // they run as the next instruction, exactly as if the opcode had been removed
60
+ // from the ISA), a 2-byte NOP for CB/ED-page opcodes (like undefined ED opcodes
61
+ // on a real Z80), and a 4-byte NOP for DDCB/FDCB. R increments as for a real
62
+ // fetch. This lets the host choose the memory model (mask, modulo, storage
63
+ // buffer, â€Ķ) and ablate instructions precisely. See buildComputeShader.
52
64
 
53
65
  // Z80 flag bits
54
66
  const CF: u32 = 0x01u;
@@ -412,6 +424,7 @@ fn z80_cb_rot(op: u32, val: u32) -> u32 {
412
424
  fn z80_exec_cb() {
413
425
  let op = z80_fetch();
414
426
  r_inc(); // M1: CB-page opcode fetch
427
+ if (on_fetch_opcode(0xcbu, op)) { return; } // host hook (2-byte NOP)
415
428
  let x = (op >> 6u) & 3u;
416
429
  let y = (op >> 3u) & 7u;
417
430
  let z = op & 7u;
@@ -520,6 +533,7 @@ fn z80_cpd() {
520
533
  fn z80_exec_ed() {
521
534
  let op = z80_fetch();
522
535
  r_inc(); // M1: ED-page opcode fetch
536
+ if (on_fetch_opcode(0xedu, op)) { return; } // host hook (2-byte NOP)
523
537
  switch(op) {
524
538
  case 0xa0u: { z80_ldi(); }
525
539
  case 0xa8u: { z80_ldd(); }
@@ -601,9 +615,44 @@ fn z80_exec_ed() {
601
615
  cpu_a = (cpu_a & 0xf0u) | (m >> 4u);
602
616
  cpu_f = (cpu_f & CF) | sz_flags(cpu_a) | select(0u, PF, parity(cpu_a));
603
617
  }
604
- // IN r,(C) - simplified, just set to 0
618
+ // IN r,(C): no I/O device, so the port reads 0. Store it (except for the
619
+ // reg-6 form IN (C), which only sets flags) and set S/Z/F3/F5/P flags.
605
620
  case 0x40u, 0x48u, 0x50u, 0x58u, 0x60u, 0x68u, 0x70u, 0x78u: {
606
- set_reg((op >> 3u) & 7u, 0u);
621
+ let val = 0u;
622
+ let reg = (op >> 3u) & 7u;
623
+ if (reg != 6u) { set_reg(reg, val); }
624
+ cpu_f = (cpu_f & CF) | sz_flags(val) | select(0u, PF, parity(val));
625
+ }
626
+ // Block input: INI (A2) / IND (AA) / INIR (B2) / INDR (BA). No I/O
627
+ // device, so the port reads 0. Writes it to (HL), decrements B, moves HL,
628
+ // sets the block-I/O flags, and repeats (R-forms) while B != 0.
629
+ case 0xa2u, 0xaau, 0xb2u, 0xbau: {
630
+ let val = 0u;
631
+ mem_write(get_hl(), val);
632
+ cpu_b = (cpu_b - 1u) & 0xffu;
633
+ let dec = (op & 0x08u) != 0u;
634
+ let s = (val + cpu_c) & 0xffu;
635
+ let other = select((s + 1u) & 0xffu, (s - 1u) & 0xffu, dec);
636
+ cpu_f = select(0u, NF, (val & 0x80u) != 0u) |
637
+ select(0u, HF | CF, other < val) |
638
+ select(0u, PF, parity((other & 7u) ^ cpu_b)) |
639
+ sz_flags(cpu_b);
640
+ if (dec) { set_hl((get_hl() - 1u) & 0xffffu); } else { set_hl((get_hl() + 1u) & 0xffffu); }
641
+ if ((op & 0x10u) != 0u && cpu_b != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; }
642
+ }
643
+ // Block output: OUTI (A3) / OUTD (AB) / OTIR (B3) / OTDR (BB). Reads (HL),
644
+ // decrements B, moves HL, sends to the (absent) port, sets flags, repeats.
645
+ case 0xa3u, 0xabu, 0xb3u, 0xbbu: {
646
+ let val = mem_read(get_hl());
647
+ cpu_b = (cpu_b - 1u) & 0xffu;
648
+ let dec = (op & 0x08u) != 0u;
649
+ if (dec) { set_hl((get_hl() - 1u) & 0xffffu); } else { set_hl((get_hl() + 1u) & 0xffffu); }
650
+ let other = (val + cpu_l) & 0xffu;
651
+ cpu_f = select(0u, NF, (val & 0x80u) != 0u) |
652
+ select(0u, HF | CF, other < val) |
653
+ select(0u, PF, parity((other & 7u) ^ cpu_b)) |
654
+ sz_flags(cpu_b);
655
+ if ((op & 0x10u) != 0u && cpu_b != 0u) { cpu_pc = (cpu_pc - 2u) & 0xffffu; }
607
656
  }
608
657
  default: {} // unknown ED ops = NOP
609
658
  }
@@ -784,14 +833,21 @@ fn z80_step() {
784
833
  op = next;
785
834
  }
786
835
 
787
- // Host hook: skip execution (treat as NOP) if requested.
788
- if (on_fetch_opcode(op)) { return; }
836
+ // Host hook for base-page opcodes (and their IX/IY forms). The CB and ED
837
+ // prefix bytes are not reported here; their pages report from their own
838
+ // dispatch with prefix = 0xCB / 0xED / 0xDDCB / 0xFDCB.
839
+ if (op != 0xcbu && op != 0xedu) {
840
+ let pfx = select(select(0xfdu, 0xddu, idx_mode == 1u), 0u, idx_mode == 0u);
841
+ if (on_fetch_opcode(pfx, op)) { return; }
842
+ }
789
843
 
790
844
  if (idx_mode != 0u) {
791
845
  if (op == 0xcbu) {
792
846
  // DDCB/FDCB: displacement precedes the CB opcode.
793
847
  idx_disp = signext(z80_fetch());
794
848
  let cbop = z80_fetch();
849
+ let pfx = select(0xfdcbu, 0xddcbu, idx_mode == 1u);
850
+ if (on_fetch_opcode(pfx, cbop)) { return; } // host hook (4-byte NOP)
795
851
  z80_exec_idxcb(cbop);
796
852
  return;
797
853
  }
@@ -1 +1 @@
1
- {"version":3,"file":"z80-core.wgsl.js","sourceRoot":"","sources":["../src/z80-core.wgsl.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,+DAA+D;AAC/D,EAAE;AACF,+EAA+E;AAC/E,kEAAkE;AAElE,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+xBvC,CAAC"}
1
+ {"version":3,"file":"z80-core.wgsl.js","sourceRoot":"","sources":["../src/z80-core.wgsl.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,+DAA+D;AAC/D,EAAE;AACF,+EAA+E;AAC/E,kEAAkE;AAElE,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAu1BvC,CAAC"}
package/dist/zilion.d.ts CHANGED
@@ -41,6 +41,12 @@ export interface ZilionOptions {
41
41
  memBytes?: number;
42
42
  /** Provide your own GPUDevice. If omitted, Zilion requests one. */
43
43
  device?: GPUDevice;
44
+ /**
45
+ * Instruction ablation: a WGSL boolean expression over `prefix` and `op`
46
+ * (see `ShaderOptions.fetchHook`). Instructions for which it is true are
47
+ * skipped as NOPs. Default: none.
48
+ */
49
+ fetchHook?: string;
44
50
  }
45
51
  /**
46
52
  * A batch Z80 executor. Runs many independent Z80 CPUs in parallel on the GPU.
@@ -1 +1 @@
1
- {"version":3,"file":"zilion.d.ts","sourceRoot":"","sources":["../src/zilion.ts"],"names":[],"mappings":"AAEA,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,yGAAyG;AACzG,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAEpD,MAAM,WAAW,UAAU;IAC1B,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,IAAI,CAAC,EAAE,eAAe,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACzB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,MAAM,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AAID;;;GAGG;AACH,qBAAa,MAAM;IAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO;IAeP,sCAAsC;WACzB,MAAM,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB9D;;;;OAIG;IACG,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAqI7F,oEAAoE;IACpE,OAAO,IAAI,IAAI;CAKf"}
1
+ {"version":3,"file":"zilion.d.ts","sourceRoot":"","sources":["../src/zilion.ts"],"names":[],"mappings":"AAEA,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,yGAAyG;AACzG,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,IAAI,CAAC,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,MAAM,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;GAGG;AACH,qBAAa,MAAM;IACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO;IAoBP,sCAAsC;WACzB,MAAM,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB9D;;;;OAIG;IACG,GAAG,CACP,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,EAAE,EAC5C,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,SAAS,CAAC;IA+IrB,oEAAoE;IACpE,OAAO,IAAI,IAAI;CAKhB"}
package/dist/zilion.js CHANGED
@@ -1,4 +1,4 @@
1
- import { buildComputeShader, REG_FIELDS, REGS_PER_PROGRAM } from './shader.js';
1
+ import { buildComputeShader, REG_FIELDS, REGS_PER_PROGRAM } from "./shader.js";
2
2
  const WORKGROUP_SIZE = 64;
3
3
  /**
4
4
  * A batch Z80 executor. Runs many independent Z80 CPUs in parallel on the GPU.
@@ -10,18 +10,18 @@ export class Zilion {
10
10
  pipeline;
11
11
  ownsDevice;
12
12
  destroyed = false;
13
- constructor(device, memBytes, ownsDevice) {
13
+ constructor(device, memBytes, ownsDevice, fetchHook) {
14
14
  this.device = device;
15
15
  this.memBytes = memBytes;
16
16
  this.ownsDevice = ownsDevice;
17
17
  const module = device.createShaderModule({
18
- label: 'zilion-z80',
19
- code: buildComputeShader(memBytes)
18
+ label: "zilion-z80",
19
+ code: buildComputeShader(memBytes, { fetchHook }),
20
20
  });
21
21
  this.pipeline = device.createComputePipeline({
22
- label: 'zilion-z80',
23
- layout: 'auto',
24
- compute: { module, entryPoint: 'main' }
22
+ label: "zilion-z80",
23
+ layout: "auto",
24
+ compute: { module, entryPoint: "main" },
25
25
  });
26
26
  }
27
27
  /** Create a Zilion batch executor. */
@@ -35,14 +35,14 @@ export class Zilion {
35
35
  if (!device) {
36
36
  const gpu = globalThis.navigator?.gpu;
37
37
  if (!gpu)
38
- throw new Error('WebGPU is not available in this environment');
38
+ throw new Error("WebGPU is not available in this environment");
39
39
  const adapter = await gpu.requestAdapter();
40
40
  if (!adapter)
41
- throw new Error('No WebGPU adapter available');
41
+ throw new Error("No WebGPU adapter available");
42
42
  device = await adapter.requestDevice();
43
43
  owns = true;
44
44
  }
45
- return new Zilion(device, memBytes, owns);
45
+ return new Zilion(device, memBytes, owns, opts.fetchHook);
46
46
  }
47
47
  /**
48
48
  * Run a batch of programs. Each program is a byte array copied into that
@@ -51,10 +51,16 @@ export class Zilion {
51
51
  */
52
52
  async run(programs, opts) {
53
53
  if (this.destroyed)
54
- throw new Error('Zilion instance has been destroyed');
54
+ throw new Error("Zilion instance has been destroyed");
55
55
  const count = programs.length;
56
56
  if (count === 0) {
57
- return { count: 0, memBytes: this.memBytes, memory: new Uint8Array(0), registers: [], memoryOf: () => new Uint8Array(0) };
57
+ return {
58
+ count: 0,
59
+ memBytes: this.memBytes,
60
+ memory: new Uint8Array(0),
61
+ registers: [],
62
+ memoryOf: () => new Uint8Array(0),
63
+ };
58
64
  }
59
65
  const device = this.device;
60
66
  const memBytes = this.memBytes;
@@ -87,21 +93,23 @@ export class Zilion {
87
93
  // Buffers.
88
94
  const memBuf = device.createBuffer({
89
95
  size: memData.byteLength,
90
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
96
+ usage: GPUBufferUsage.STORAGE |
97
+ GPUBufferUsage.COPY_SRC |
98
+ GPUBufferUsage.COPY_DST,
91
99
  });
92
100
  device.queue.writeBuffer(memBuf, 0, memData);
93
101
  const regsOutBuf = device.createBuffer({
94
102
  size: regData.byteLength,
95
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
103
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
96
104
  });
97
105
  const regsInBuf = device.createBuffer({
98
106
  size: regData.byteLength,
99
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
107
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
100
108
  });
101
109
  device.queue.writeBuffer(regsInBuf, 0, regData);
102
110
  const paramsBuf = device.createBuffer({
103
111
  size: params.byteLength,
104
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
112
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
105
113
  });
106
114
  device.queue.writeBuffer(paramsBuf, 0, params);
107
115
  const bindGroup = device.createBindGroup({
@@ -110,16 +118,16 @@ export class Zilion {
110
118
  { binding: 0, resource: { buffer: paramsBuf } },
111
119
  { binding: 1, resource: { buffer: memBuf } },
112
120
  { binding: 2, resource: { buffer: regsOutBuf } },
113
- { binding: 3, resource: { buffer: regsInBuf } }
114
- ]
121
+ { binding: 3, resource: { buffer: regsInBuf } },
122
+ ],
115
123
  });
116
124
  const memStage = device.createBuffer({
117
125
  size: memData.byteLength,
118
- usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
126
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
119
127
  });
120
128
  const regsStage = device.createBuffer({
121
129
  size: regData.byteLength,
122
- usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
130
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
123
131
  });
124
132
  const enc = device.createCommandEncoder();
125
133
  const pass = enc.beginComputePass();
@@ -161,7 +169,7 @@ export class Zilion {
161
169
  afPrime: outRegs[b + 8],
162
170
  bcPrime: outRegs[b + 9],
163
171
  dePrime: outRegs[b + 10],
164
- hlPrime: outRegs[b + 11]
172
+ hlPrime: outRegs[b + 11],
165
173
  });
166
174
  }
167
175
  return {
@@ -169,7 +177,7 @@ export class Zilion {
169
177
  memBytes,
170
178
  memory,
171
179
  registers,
172
- memoryOf: (i) => memory.subarray(i * memBytes, (i + 1) * memBytes)
180
+ memoryOf: (i) => memory.subarray(i * memBytes, (i + 1) * memBytes),
173
181
  };
174
182
  }
175
183
  /** Release GPU resources (and the device, if Zilion created it). */
@@ -1 +1 @@
1
- {"version":3,"file":"zilion.js","sourceRoot":"","sources":["../src/zilion.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zilion.js","sourceRoot":"","sources":["../src/zilion.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovand/zilion",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },