Skip to main content
The debugger is currently not built as a standalone tool. The code exists in debugger.zig but is not included in the build configuration. This page documents the planned debugging functionality.

Overview

The toolkit includes debugger source code (debugger.zig) that provides interactive debugging capabilities via a TCP connection. However, this functionality is not currently exposed as a usable tool in the default build.

Current status

The build.zig file only builds two executables:
  • 4004-assembler - The assembler tool
  • 4004-emulator - The emulator tool
The debugger source exists but is not compiled by default.

Planned debugging architecture

The debugger code implements a TCP-based debugging protocol:

Connection model

The debugger would connect to a modified emulator on TCP port 5005:
pub const TCP_ADDRESS = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 5005);

Planned commands

The debugger source code includes implementations for these commands:
Execute a single instruction and display the next instruction and program counter.
> s
instr: LDM 5
pc: 2
Continue execution until a breakpoint is reached.
> r
reached breakpoint
instr: JUN 100
pc: 100
Set a breakpoint at a specific address.
> b 256
The address parameter is a program memory address (0-4095).
Display all 16 index registers.
> p
0R=5 1R=10 2R=15 3R=0 ...
Read a single nibble from DRAM using three nibble parameters.
> m 0 0 0
15
Parameters are: bank, chip/register, character position.
Display command-line arguments stored in memory by the runtime.
> args
hello world test

Emulator integration

The emulator source includes a start_cpu_with_debugger() function that:
  1. Listens on TCP port 5005
  2. Waits for debugger connection
  3. Executes instructions on command
  4. Responds to debugger queries
However, the main() function calls start_cpu() instead, so this mode is not accessible.

Enabling debugger support

To enable debugging, you would need to:
1

Add debugger executable to build.zig

const debugger_exe = b.addExecutable(.{
    .name = "4004-debugger",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/debugger.zig"),
        .target = target,
        .optimize = optimize
    })
});
b.installArtifact(debugger_exe);
2

Modify emulator to use debugger mode

In emulator.zig, replace the start_cpu() call with start_cpu_with_debugger() or add a command-line flag to enable it.
3

Rebuild the toolkit

zig build
4

Run emulator and debugger

# Terminal 1
./zig-out/bin/4004-emulator program.bin

# Terminal 2
./zig-out/bin/4004-debugger

Alternative debugging approaches

Until the debugger is properly integrated, you can:
  • Add print statements to the emulator source code
  • Use Zig’s built-in debugger (gdb/lldb) to step through emulator execution
  • Examine the emulator’s CPU state by modifying the source
  • Write test programs that output diagnostic information to the monitor

Protocol details

The debugger uses a simple text-based protocol:
  • Commands are single letters followed by optional arguments
  • Responses are newline-terminated
  • Maximum command size is 1024 bytes
  • The debugger tracks command history and supports repeating the last command by pressing Enter
If you’re interested in using or improving the debugger, consider opening a pull request to add it to the build configuration and make it a first-class tool in the toolkit.

Build docs developers (and LLMs) love