Intel4004 struct, which emulates the original 4-bit microprocessor with cycle-accurate timing.
Intel4004 struct
The main CPU struct is defined incpu.zig:6 and contains all processor state:
Registers
The Intel 4004 has several types of registers for different purposes:- Index registers
- Accumulator
- Carry bit
- Test signal
Index registers
Field:index_registers: [16]u4The CPU has 16 index registers, each storing a 4-bit value. These general-purpose registers can be accessed individually or as pairs for 8-bit operations.Register pairs are accessed using the
getRegisterPair() and setRegisterPair() methods, which combine two consecutive 4-bit registers into an 8-bit value.Program counter
Field:program_counter: u12
The 12-bit program counter points to the next instruction to execute in program memory. It can address up to 4096 bytes of program RAM, with automatic wraparound using modulo arithmetic (cpu.zig:67).
Stack
The Intel 4004 has a limited hardware stack for subroutine calls:- stack_registers:
[3]u12- Three 12-bit registers storing return addresses - stack_pointer:
u2- 2-bit pointer (0-2) tracking the current stack position
The stack is circular with only 3 levels. Pushing beyond level 2 wraps back to level 0, overwriting the oldest return address. This matches the original Intel 4004 hardware limitation.
Stack operations
pushToStack(address: u12)
pushToStack(address: u12)
Pushes a 12-bit address onto the stack and increments the stack pointer. Defined in
cpu.zig:19-22.popFromStack() u12
popFromStack() u12
Decrements the stack pointer and returns the address at that position. Defined in
cpu.zig:24-27.Execution model
The CPU executes instructions using a single-step model with cycle-accurate timing:single_step()
Defined incpu.zig:60-87, this method:
- Fetches the instruction byte from program RAM at the current program counter
- Decodes the instruction using the instruction specification
- Fetches a second byte if the instruction is 2 bytes long
- Advances the program counter by the instruction length
- Extracts instruction arguments from the opcode bytes
- Executes the instruction function with the extracted arguments
- Waits to match the expected cycle timing based on a 740 kHz clock speed
The emulator runs at the original Intel 4004 clock speed of 740 kHz, with timing enforcement through busy-waiting to ensure cycle-accurate execution.
Clock timing
- Clock speed: 740,000 Hz (
cpu.zig:57) - Cycle time: ~1,351 nanoseconds per cycle
- Instructions take 1 or 2 cycles depending on their byte length
Helper methods
getRegisterPair(pair: u3) u8
getRegisterPair(pair: u3) u8
Combines two consecutive index registers into an 8-bit value. Defined in
cpu.zig:29-33.The pair index (0-7) is multiplied by 2 to get the first register, and the adjacent register forms the lower 4 bits.setRegisterPair(pair: u3, val: u8)
setRegisterPair(pair: u3, val: u8)
Splits an 8-bit value across two consecutive index registers. Defined in
cpu.zig:35-38.The upper 4 bits go to the even-numbered register, and the lower 4 bits go to the odd-numbered register.reset()
reset()
Resets all CPU state to zero. Defined in
cpu.zig:40-42.