Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8277d19
Implemented render callback so that we can use IMGUI
gunterhager Mar 16, 2025
7898bc5
Added IMGUI dependency
gunterhager Mar 16, 2025
7b45e39
Removed render_cb since it's obsolete
gunterhager Mar 16, 2025
c9a5772
Started to implement debug UI
gunterhager Mar 17, 2025
5a160be
Started to implement Z80 window
gunterhager Mar 18, 2025
420c686
Implemented Z80 debug UI
gunterhager Mar 18, 2025
ad21eb8
Implemented Z80 PIO
gunterhager Mar 18, 2025
c1a938e
Implemented CTC debug UI
gunterhager Mar 18, 2025
faf392d
Merge pull request #1 from gunterhager/feature/debug_ui
gunterhager Mar 19, 2025
b30c9a7
Added "(TODO)" menu item to all items that aren't working yet
gunterhager Mar 22, 2025
d5b1422
Merge branch 'floooh:main' into main
gunterhager Mar 22, 2025
cb5000a
Implemented debug UI for intel8255 PPI
gunterhager Mar 23, 2025
8b6ade7
Fixed build error in init
gunterhager Mar 23, 2025
9ba775b
Update .gitignore
gunterhager Mar 27, 2025
fd5d654
Merge remote-tracking branch 'upstream/main'
gunterhager Mar 27, 2025
302d6f2
Merge remote-tracking branch 'upstream/main'
gunterhager Jun 24, 2025
5480f4b
Started to implement memory map debug view
gunterhager Jun 24, 2025
dc17b89
Merge remote-tracking branch 'upstream/main'
gunterhager Sep 12, 2025
3d24be5
Fixed build issues
gunterhager Sep 12, 2025
1fd248b
Create copilot-instructions.md
gunterhager Dec 2, 2025
1ee4af1
Merge remote-tracking branch 'upstream/main'
gunterhager Dec 2, 2025
2f4e6cb
Update readFileAlloc usage for Zig API changes
gunterhager Dec 2, 2025
35d2bda
Merge remote-tracking branch 'upstream/main'
gunterhager Mar 10, 2026
41acbb9
fix build: use root_module.addIncludePath for Zig 0.14+ API, update deps
gunterhager Mar 10, 2026
879e6c5
Update .gitignore
gunterhager Mar 10, 2026
d1cd01f
add Z80 debugger UI: disassembler, CPU debugger, breakpoints
gunterhager Mar 18, 2026
b2ad767
Update .gitignore
gunterhager Mar 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## Quick orientation for AI coding agents

This repository implements several 8-bit emulator experiments written in Zig. The codebase is organized into emulated "systems" (platforms/arcade machines), reusable "chips" (CPU, sound, IO), a small host layer, and UI helpers.

Key directories and files to inspect first:
- `src/chipz.zig` — top-level module imports and entry points for the emulator.
- `src/systems/` — each system (eg. `namco.zig`, `bombjack.zig`, `kc85.zig`) defines machine composition and wiring of chips and memory.
- `src/chips/` — chip implementations, notably `z80.zig` (cycle-stepped Z80), `ay3891.zig` (audio), Intel 8255, CTC, PIO, etc.
- `src/common/` — shared utilities: `memory.zig` (paged memory model), `audio.zig`, `clock.zig`, and small helpers used broadly.
- `src/host/` — host abstraction (gfx, audio, timing, profiling) that separates platform I/O from machine logic.
- `src/ui/` — realtime debugging and UI panels (Z80 state, memory map, chip helpers).
- `emus/` and `media/` — ROMs and media assets used by systems.
- `tests/` — unit tests for many chips (use these as canonical examples of expected behavior).

Important architecture & conventions
- Systems are composed by wiring together chips and mapping memory explicitly. See `src/systems/*.zig` for examples of how ROMs, RAM and IO are mapped.
- The Z80 implementation is a cycle-stepped emulator that exposes a Type(comptime cfg) API (see `src/chips/z80.zig`). Many chips in this codebase use Zig `comptime`-driven types; prefer adding specialized types via the existing Type(...) patterns rather than duplicating logic.
- Memory uses a paged model (`src/common/memory.zig`) with separate read/write pointers per page. Mapping functions include `mapRAM`, `mapROM`, `mapRW`, and `unmap`. All slices passed to Memory must outlive the Memory object — keep host lifetime in mind when writing tests or wiring memory.
- Host vs machine separation: device logic (chips, memory, systems) is pure emulation code; `src/host` contains platform glue for graphics/audio/timing. Avoid placing platform-specific code into `src/chips` or `src/systems`.

Build / run / test workflows (concrete):
- Run arcade or system targets (examples from `README.md`):
- `zig build --release=fast run-pacman`
- `zig build --release=fast run-pengo`
- `zig build --release=fast run-kc853 -- -slot8 m022` (KC85 example with a slot)
- Unit tests are provided under `tests/`. Run a test file directly with Zig or use the repository build targets:
- `zig test tests/memory.test.zig`
- or `zig build <test-target>` when available in `build.zig` (inspect `build.zig` for provided tasks).
- Build artifacts are placed in `zig-out/bin/` (executables like `pacman`, `z80test`, etc.).

Project-specific patterns to follow
- Prefer small, well-scoped files: chips implement a single device; systems assemble devices.
- Use the provided Memory Type for mapping. Example mapping pattern from systems:
- `mem.mapROM(0x0000, rom.len, rom_slice)`
- `mem.mapRAM(0x4000, ram_size, ram_slice)`
- Chips expose low-level, cycle-accurate interfaces: for the Z80, code inspects and manipulates pin masks and steps the CPU by cycles — avoid attempts at high-level shortcuts that skip pins or the step model.
- Use comptime Type stamps already present (e.g., `Z80.Type(TypeConfig{...})`) when creating specialized chip instances.

Integration & extension notes
- Adding a new system: implement `src/systems/<your>.zig`, wire chips and memory using existing APIs, add a `run-<your>` target to `build.zig` mirroring existing runs.
- Adding a new chip: follow shape in `src/chips/*` — provide a Type(comptime cfg) when relevant, keep device logic free of host I/O, and add focused unit tests under `tests/`.
- ROM and media files live under `emus/` and `media/` — systems load these directly; keep naming and offsets consistent with existing systems.

Examples to reference while coding
- See `src/systems/namco.zig` and `emus/namco/roms/pacman` for an arcade wiring example.
- See `src/chips/z80.zig` for cycle-stepped CPU semantics and `src/common/memory.zig` for mapping behavior.
- See tests like `tests/memory.test.zig` and `tests/intel8255.test.zig` for small, focused test patterns.

When you need clarification from a human
- If a requested change touches host APIs (`src/host/*`) or build targets (`build.zig`), ask for which platforms to target (macOS / Linux) and whether CI needs updating.
- If you must change memory ownership/lifetimes, request guidance — many memory APIs rely on host-owned slices that must outlive the Memory object.

If this snapshot is missing something you expect, tell me what to add (target, device, or workflow) and I'll update this file.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
zig-*/
.zig-*/
.vscode/
.cursor
/.claude
23 changes: 23 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,18 @@ pub fn build(b: *Build) !void {
const dep_sokol = b.dependency("sokol", .{
.target = target,
.optimize = optimize,
.with_sokol_imgui = true,
});
const dep_cimgui = b.dependency("cimgui", .{
.target = target,
.optimize = optimize,
});

// inject the cimgui header search path into the sokol C library compile step
dep_sokol.artifact("sokol_clib").root_module.addIncludePath(dep_cimgui.path("src"));
const dep_shdc = dep_sokol.builder.dependency("shdc", .{});
const mod_sokol = dep_sokol.module("sokol");
const mod_cimgui = dep_cimgui.module("cimgui");

// shader module
const mod_shaders = try sokol.shdc.createModule(b, "shaders", mod_sokol, .{
Expand Down Expand Up @@ -58,10 +67,22 @@ pub fn build(b: *Build) !void {
.optimize = optimize,
.imports = &.{
.{ .name = "sokol", .module = dep_sokol.module("sokol") },
.{ .name = "cimgui", .module = dep_cimgui.module("cimgui") },
.{ .name = "common", .module = mod_common },
.{ .name = "shaders", .module = mod_shaders },
},
});
const mod_ui = b.addModule("ui", .{
.root_source_file = b.path("src/ui/ui.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "sokol", .module = dep_sokol.module("sokol") },
.{ .name = "cimgui", .module = dep_cimgui.module("cimgui") },
.{ .name = "common", .module = mod_common },
.{ .name = "chips", .module = mod_chips },
},
});

// top-level modules
const mod_chipz = b.addModule("chipz", .{
Expand All @@ -73,6 +94,7 @@ pub fn build(b: *Build) !void {
.{ .name = "chips", .module = mod_chips },
.{ .name = "systems", .module = mod_systems },
.{ .name = "host", .module = mod_host },
.{ .name = "ui", .module = mod_ui },
},
});

Expand All @@ -94,5 +116,6 @@ pub fn build(b: *Build) !void {
.optimize = optimize,
.mod_chipz = mod_chipz,
.mod_sokol = mod_sokol,
.mod_cimgui = mod_cimgui,
});
}
8 changes: 6 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
.fingerprint = 0x3ecb34175baf6f81,
.dependencies = .{
.sokol = .{
.url = "git+https://github.com/floooh/sokol-zig.git#9dacdb9ecdbd124b99c828d8891363236f0a56de",
.hash = "sokol-0.1.0-pb1HK6VgNgBI8wSklN7Gk_SV_sgIKAa-p3042rJ6HQH1",
.url = "git+https://github.com/floooh/sokol-zig.git#de5906fb0f81f96e92c1c67a2b8a24dc50872207",
.hash = "sokol-0.1.0-pb1HK9ngNgD_m7L3HpbsyJ-jHRGVzcd672pjJDEPBQWh",
},
.cimgui = .{
.url = "git+https://github.com/floooh/dcimgui.git#4557d7526fdd977f46ca10c2bbdd63532254f8d6",
.hash = "cimgui-0.1.0-44ClkXnYlwBKnil7TfCWL9z1Zo_2YJCJREzrpdFiGvA1",
},
},
.paths = .{
Expand Down
4 changes: 4 additions & 0 deletions emus/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub const Options = struct {
optimize: OptimizeMode,
mod_chipz: *Build.Module,
mod_sokol: *Build.Module,
mod_cimgui: *Build.Module,
};

pub fn build(b: *Build, opts: Options) void {
Expand All @@ -43,6 +44,7 @@ pub fn build(b: *Build, opts: Options) void {
.optimize = opts.optimize,
.mod_chipz = opts.mod_chipz,
.mod_sokol = opts.mod_sokol,
.mod_cimgui = opts.mod_cimgui,
});
}
}
Expand All @@ -55,6 +57,7 @@ const EmuOptions = struct {
optimize: OptimizeMode,
mod_chipz: *Build.Module,
mod_sokol: *Build.Module,
mod_cimgui: *Build.Module,
};

fn addEmulator(b: *Build, opts: EmuOptions) void {
Expand All @@ -65,6 +68,7 @@ fn addEmulator(b: *Build, opts: EmuOptions) void {
.imports = &.{
.{ .name = "chipz", .module = opts.mod_chipz },
.{ .name = "sokol", .module = opts.mod_sokol },
.{ .name = "cimgui", .module = opts.mod_cimgui },
},
});
if (opts.model != .NONE) {
Expand Down
Loading
Loading