Overview
Virtual devices are defined indevices.zig and use port-based communication:
- Keyboard: Input device for sending character data to the CPU
- Monitor: Output device for displaying characters from the CPU
Keyboard
The Keyboard device simulates character input by writing to I/O ports that the CPU can read. Defined indevices.zig:4-21.
Port structure
- char_port_low
- char_port_high
- char_ready_port
Type:
*u4Pointer to a 4-bit port storing the lower nibble of the input character. The Keyboard writes the lower 4 bits of each character here.Methods
send_char(char: u8)
send_char(char: u8)
Sends a single 8-bit character to the CPU. Defined in
devices.zig:15-20.Behavior:- Waits while
char_ready_portbit 0 is set (CPU hasn’t read previous character) - Splits the character into high and low nibbles
- Writes low nibble to
char_port_low - Writes high nibble to
char_port_high - Sets bit 0 of
char_ready_portto signal data is ready
The method blocks until the previous character is read by the CPU, implementing flow control through the ready flag.
send_string(str: []u8)
send_string(str: []u8)
Sends multiple characters by calling
send_char() for each byte. Defined in devices.zig:9-12.Monitor
The Monitor device reads characters from I/O ports and displays them to stdout, simulating a display terminal. Defined indevices.zig:23-45.
Port structure
- char_port_low
- char_port_high
- char_ready_port
Type:
*u4Pointer to a 4-bit port where the CPU writes the lower nibble of output characters.Methods
turn_on()
turn_on()
Starts the monitor’s main loop, continuously reading and displaying characters. Defined in
devices.zig:28-44.Behavior:- Opens stdout for writing
- Enters an infinite loop:
- Waits while
char_ready_portbit 0 is clear (no character ready) - Reads low nibble from
char_port_low - Reads high nibble from
char_port_high - Combines nibbles into an 8-bit character
- If character is DEL (0x7F), outputs backspace sequence to erase
- Outputs the character to stdout
- Clears bit 0 of
char_ready_portto signal character was read
- Waits while
The DEL character (ASCII 0x7F) receives special handling: it outputs a backspace-space-backspace sequence to visually erase the previous character, simulating a backspace key.
Port-based I/O protocol
Both devices follow a shared communication protocol:Character transmission
- Split 8-bit character into two 4-bit nibbles (high and low)
- Write nibbles to separate high/low ports
- Set ready flag (bit 0 of ready port) to indicate data availability
- Wait for acknowledgment by polling the ready flag
- Clear ready flag after the other party reads the data
This protocol enables bidirectional flow control without interrupts, matching the polling-based I/O model of the original Intel 4004.
Port initialization
Device ports must be initialized with pointers to specific I/O ports in the CPU’s Data RAM or ROM port arrays. The CPU program is responsible for:- Allocating port numbers for each device
- Creating device instances with pointers to those ports
- Ensuring sender and receiver use the same port addresses
Device threading
In typical usage, the Monitor runs in a separate thread calling
turn_on() in an infinite loop, while the main thread controls the CPU and Keyboard. This allows simultaneous input and output operations.