This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
RP8086 is a hardware-software complex that uses a Raspberry Pi Pico (RP2350B) as a complete chipset for the Intel 8086 processor. The RP2350B acts as:
- Bus controller (via PIO0 state machine at 504 MHz)
- ROM/RAM emulator (736KB RAM via external PSRAM + 32KB VRAM + 8KB BIOS)
- I/O controller (Intel 8259A, 8253, 8237, 8272A, XTIDE, 16550 UART, i8042 keyboard controller emulation)
- Clock generator (4.75-6 MHz PWM, 33% duty cycle, configurable)
- CGA/PCjr video adapter with hardware VGA output (GPIO 30-37 via PIO1 and R-2R DAC)
- Text mode: 80×25 (16 colors)
- CGA graphics: 320×200×4 colors
- PCjr graphics: 160×200×16 and 320×200×16 colors (IBM PCjr/Tandy 1000 compatible)
- PC Speaker controller (GPIO 46 via PWM, emulates i8253 Channel 2)
- SD Card reader (SPI1 on GPIO 40-43 for loading disk images from FAT filesystem)
- USB Host controller (built-in RP2350B USB controller with TinyUSB stack)
- USB HID keyboard: auto-conversion USB HID → XT Scancodes → i8042 controller
- USB HID mouse: emulation of Microsoft Serial Mouse protocol via COM1 (ports 0x3F8-0x3FF)
- USB hub support: up to 4 HID devices simultaneously
- Plug & Play: automatic device detection on Type-C port connection
The system successfully boots DR-DOS 7 and other DOS operating systems from SD card floppy/HDD images and runs at stable 4.75-6 MHz.
# Build from cmake-build-rp2350b directory
cd cmake-build-rp2350b
cmake --build .
# Output files (in bin/ directory):
# - RP8086-<branch>-<build_number>.uf2 - Flashable to RP2350B via USB bootloader
# - RP8086-<branch>-<build_number>.elf - Debug symbols
# - RP8086-<branch>-<build_number>.hex - Intel HEX format
# - RP8086-<branch>-<build_number>.bin - Raw binaryBuild modes:
- DEBUG:
cmake -DDEBUG=1 ..- USB serial stdio, no USB HID, verbose logging - RELEASE (default): USB HID enabled, optimized binary, no debug output
Flash to device:
# 1. Hold BOOTSEL button while connecting RP2350B to USB
# 2. Drag & drop .uf2 file to mounted drive (RPI-RP2)
# 3. Device automatically reboots and starts firmwareBuild Requirements:
- Pico SDK (set
PICO_SDK_PATHenvironment variable) - CMake >= 3.13
- ARM GCC toolchain (arm-none-eabi-gcc)
- C23 standard support
Hardware Requirements:
- WeAct Studio RP2350B Core Board (WEACT_STUDIO_RP2350B_CORE)
- RP2350B microcontroller (ARM Cortex-M33 dual-core @ 500 MHz max)
- 16MB QSPI Flash (W25Q128)
- 8MB QSPI PSRAM (APS6404L-3SQR)
- USB Type-C connector (USB 1.1 Host/Device)
- 3.3V LDO regulator (supports up to 500mA)
- BOOTSEL button for firmware flashing
- Onboard LED (GPIO 25 or board-specific)
- Intel 8086 CPU (or 8086 compatible: NEC V40)
- External components: VGA R-2R DAC, level shifters (optional), SD card module
Build Configuration:
- Target Board:
WEACT_STUDIO_RP2350B_CORE(WeAct Studio RP2350B development board) - Platform:
rp2350-arm-s(ARM Secure mode, enables TrustZone features)- Why ARM Secure? Provides access to full 512KB RAM (vs 264KB in Non-Secure mode)
- Enables unrestricted peripheral access (required for PIO, DMA, USB Host)
- TrustZone features not actively used, but Secure mode is necessary for performance
- Flash Size: 16MB (PICO_FLASH_SIZE_BYTES = 16777216)
- Optimization:
-Ofastwith LTO enabled (-flto -fwhole-program) - Binary mode:
copy_to_ram(executes from RAM for maximum performance) - Linker script: Custom
memmap.ldfor optimized memory layout- Internal RAM: 512KB at 0x20000000 (used for code execution via copy_to_ram)
- External PSRAM: 8MB at 0x11000000 (736KB used for i8086 RAM emulation)
- SCRATCH_X/Y: 4KB each at 0x20080000/0x20081000 (fast scratchpad memory)
- Size optimizations:
--wrap=atexit,--wrap=abort,--strip-all,--gc-sections - Standards: C23 and C++23
- System clock: 504 MHz (overclocked with voltage boost to 1.65V)
- i8086 clock: 4.75-6 MHz (configurable via
I8086_CLOCK_SPEEDin common.h)
Conditional compilation:
- DEBUG mode: USB Host disabled, USB serial stdio enabled for debugging
- RELEASE mode: USB Host enabled (TinyUSB + usbhid), stdio via serial terminal
Memory Layout (memmap.ld):
FLASH (16MB) : Code, constants, read-only data
RAM (512KB) : copy_to_ram execution, stack, heap
PSRAM (8MB @ QMI) : i8086 RAM/ROM/VRAM emulation (736KB used, 7.26MB available)
SCRATCH_X (4KB) : Core0 fast scratchpad
SCRATCH_Y (4KB) : Core1 fast scratchpad
Performance implications:
- All critical code runs from internal 512KB RAM (zero wait states)
- PSRAM accessed via QMI (Quad SPI Memory Interface) with ~6 cycle latency
- SCRATCH_X/Y can be used for ultra-fast temporary storage in IRQ handlers
Layer 1: PIO (Hardware - i8086_bus.pio)
- Runs independently on RP2350B's Programmable I/O state machine at 504 MHz (clkdiv = 1.0, no frequency divider)
- Handles all timing-critical bus operations in hardware
- Manages i8086 bus signals: ALE, RD, WR, M/IO, BHE, INTA, READY
- Controls bidirectional data bus (GPIO 0-15)
- Generates interrupts (IRQ0 for writes, IRQ1 for reads, IRQ3 for INTA)
- 32-bit protocol: ARM returns
[data:16][pindirs_mask:16]for ISA-compatibility - PIO clock runs at full system frequency (504 MHz) without divider for maximum timing precision
Layer 2: ARM Cortex-M33 (Software - cpu_bus.c)
- Services interrupts from PIO via FIFO
- Implements memory/IO emulation logic
- All handlers use
__time_critical_funcmacro to run from RAM - Interrupts run at
PICO_HIGHEST_IRQ_PRIORITY
Core0 (Main) - User Interface & I/O:
- System initialization (overclock to 504 MHz, USB Host init, PSRAM init, SD card mount, VGA init)
- Launches Core1 via
multicore_launch_core1(bus_handler_core) - Main loop responsibilities:
- USB HID processing (TinyUSB stack):
- USB keyboard: Converts USB HID reports → XT Scancodes → i8042 controller (via
handleScancode()) - USB mouse: Converts HID reports → Microsoft Serial Mouse protocol → COM1 (ports 0x3F8-0x3FF)
- Supports up to 4 HID devices via USB hubs (CFG_TUH_HID = 4)
- Plug & Play device detection via
tuh_hid_mount_cb()/tuh_hid_umount_cb()
- USB keyboard: Converts USB HID reports → XT Scancodes → i8042 controller (via
- CGA/PCjr hardware video output: Renders VIDEORAM to VGA port (GPIO 30-37) at 60 FPS via PIO1 + DMA
- Supports multiple video modes: text 80×25, CGA 320×200×4, PCjr 160×200×16 and 320×200×16
- Debug commands: R (reset), B (bootloader), M (memory dump), V (video dump), C (CTTY mode), P (CGA registers)
- CTTY mode: Direct serial terminal mode via COM1/USB
- PC Speaker: PWM output on GPIO 46 controlled by i8253 Channel 2 emulation (port 0x61)
- SD Card: Loads .img disk images (floppy and HDD) from FAT filesystem for FDC and XTIDE emulation
- USB HID processing (TinyUSB stack):
Core1 (bus_handler_core) - Bus & IRQ Management:
- Hardware initialization sequence (critical order):
start_cpu_clock()- PWM clock generation (4.75-6 MHz)pic_init()- INTR pin setupcpu_bus_init()- PIO program + IRQ handlersreset_cpu()- Release i8086 from reset (MUST be last)
- Main loop:
- Timer IRQ generation via hardware
repeating_timer(18.2 Hz, IBM PC compatible) - INTR signal management: Sets INTR=HIGH when pending interrupts exist
- Uses
__wfe()for power efficiency when idle
- Timer IRQ generation via hardware
INTA Protocol:
- INTA handled in PIO state machine via IRQ 3
- Process: PIO detects INTA=LOW → generates IRQ 3 → ARM calls
i8259_nextirq()→ returns interrupt vector - Next read cycle returns vector in format
0xFF00 | vector
Critical bus signals (hardcoded in PIO):
- GPIO 0-15: AD0-AD15 (multiplexed Address/Data bus, bidirectional)
- GPIO 16-19: A16-A19 (Address bus upper 4 bits)
- GPIO 20: ALE (Address Latch Enable)
- GPIO 21: RD (Read strobe, active LOW)
- GPIO 22: WR (Write strobe, active LOW)
- GPIO 23: INTA (Interrupt acknowledge, active LOW)
- GPIO 24: M/IO (Memory/IO select: 1=memory, 0=I/O)
- GPIO 25: BHE (Bus High Enable)
- GPIO 26: INTR (Interrupt request output, active HIGH)
- GPIO 27: READY (Wait state control, managed by PIO sideset)
- GPIO 28: RESET (Reset output, active HIGH)
- GPIO 29: CLK (Clock output, PWM)
Hardware peripherals:
- GPIO 30-37: VGA_DATA[0:7] (8-bit hardware CGA video output, controlled by PIO1)
- GPIO 40: SD_MISO (SPI1 - SD Card Master In Slave Out)
- GPIO 41: SD_CS (SPI1 - SD Card Chip Select)
- GPIO 42: SD_SCK (SPI1 - SD Card Clock)
- GPIO 43: SD_MOSI (SPI1 - SD Card Master Out Slave In)
- GPIO 45: ISA_PIN (ISA bus active indicator, directly controlled by memory/port handlers)
- GPIO 46: BEEPER (PC Speaker PWM output, emulates i8253 PIT Channel 2)
- GPIO 47: PSRAM_CS (Chip Select for external PSRAM, 736KB RAM via QMI)
Important:
- Pin assignments in
i8086_bus.piomust match hardware wiring - RP2350B is 5V tolerant on inputs, allowing direct connection to i8086 (5V logic) without level shifters
- VGA video driver uses PIO1 with R-2R DAC for analog signal generation
- SD Card uses SPI1 bus for loading floppy disk images and file systems
- Total GPIO usage: 45 pins (0-15: AD bus, 16-19: A bus, 20-29: control signals, 30-37: VGA, 40-43: SD, 45: ISA, 46: speaker, 47: PSRAM)
RP2350B has 2 PIO blocks (PIO0, PIO1), each with 4 state machines and 32 instructions memory. Current usage:
PIO0 (Bus Controller):
- State Machine 0: i8086 bus protocol handler (i8086_bus.pio)
- Instruction memory: 29/32 instructions used (3 reserved for future)
- IRQ usage: IRQ0 (writes), IRQ1 (reads), IRQ3 (INTA cycles)
- Runs at 504 MHz (clkdiv = 1.0) for maximum timing precision
- Sideset: READY signal for wait state control
PIO1 (Video Controller):
- State Machine: VGA timing and signal generation (vga-nextgen driver)
- Generates hsync/vsync timing for CGA-compatible modes
- DMA-driven VIDEORAM → VGA_DATA transfer at 60 FPS
- Outputs 8-bit RGBI signal (GPIO 30-37) with R-2R DAC conversion
- Runs at VGA pixel clock frequency (25.175 MHz for standard VGA)
Available Resources:
- PIO0: State machines 1-3 available for future expansion (ISA bus, additional peripherals)
- PIO1: State machines 1-3 available for future features (audio, additional video modes)
Build System (CMakeLists.txt):
- Main executable: Compiled from
src/main.c,src/cpu.c,src/cpu_bus.c,src/common.c - PIO generation:
i8086_bus.pioauto-compiled to header viapico_generate_pio_header() - Drivers linked:
drivers/graphics- Graphics utilitiesdrivers/vga-nextgen- VGA video output driver (PIO1 based)drivers/sdcard- SD Card SPI driverdrivers/fatfs- FAT filesystem supportdrivers/usbhid- USB HID driver (TinyUSB, RELEASE mode only)
- Pico SDK libraries:
pico_runtime,pico_stdlib,pico_stdio- Core SDKpico_multicore- Dual-core supporthardware_pio,hardware_pwm- Hardware peripheralstinyusb_host,tinyusb_board- USB Host stack (RELEASE only)
- Build artifacts:
bin/directory with auto-incremented build numbers - Version control: Git branch and commit hash embedded in binary via compile definitions
Compile-time definitions:
VGA- Enables VGA video driverVGA_BASE_PIN=30- VGA data output starts at GPIO 30SDCARD_PIN_SPI0_MISO=40,CS=41,SCK=42,MOSI=43- SD Card SPI pinsPICO_BUILD_NAME,PICO_GIT_BRANCH,PICO_GIT_COMMIT- Version information
main.c - Entry point and Core0 main loop:
- System initialization (USB Host via TinyUSB, PSRAM, VGA video, SD card mounting)
- USB HID integration:
- Calls
tuh_task()in main loop for TinyUSB processing - Receives scancodes from USB keyboard via
handleScancode()callback - USB mouse data automatically sent to COM1 by USB HID driver
- Calls
- CGA video rendering at 60 FPS with multiple mode support:
- Text mode: 80×25 characters
- CGA graphics: 320×200×4 colors
- PCjr graphics: 160×200×16 colors, 320×200×16 colors (Tandy 1000 compatible)
- Keyboard input processing:
- USB keyboard: USB HID → XT Scancodes → i8042 (via USB HID driver)
- Serial terminal: ASCII → Scancode conversion (for debug)
- Debug commands (uppercase): R, B, M, V, C, P
- CTTY mode support (direct COM1/USB terminal mode)
- SD card management: loads floppy and HDD disk images (.img) from FAT filesystem
cpu.c - i8086 CPU control (functions declared in common.h):
start_cpu_clock(): PWM generation for i8086 clock (33% duty cycle)reset_cpu(): RESET sequence
cpu_bus.c/h - Bus controller and memory emulation:
cpu_bus_init(): Loads PIO program, sets up IRQ handlersbus_read_handler(): Services read requests (IRQ1) and INTA cycles (IRQ3)bus_write_handler(): Services write requests (IRQ0)i8086_read()/i8086_write(): Highly optimized 16-bit memory/IO operations
common.h - Common definitions and structures:
- System configuration (clocks, pins, PIO settings)
- Device structures:
i8259_s,i8253_s,dma_channel_s,i8272_s,ide_s,uart_16550_s,mc6845_s,cga_s - Helper functions:
write_to()for BHE support
common.c - Binary file imports and global data structures:
- IMPORT_BIN macro: Imports binary files directly into FLASH memory at compile time
- Syntax:
IMPORT_BIN("path/to/file.bin", symbol_name) - Creates read-only array
uint8_t symbol_name[]in.flashdatasection - CRITICAL: Imported data is READ-ONLY (stored in FLASH, not RAM)
- Cannot be modified at runtime - any "patching" must be done via conditional logic in memory_read()
- Example:
IMPORT_BIN("./binary/GLABIOS.ROM", BIOS)createsextern uint8_t BIOS[]
- Syntax:
- Current binary imports:
BIOS[]- Turbo XT BIOS v3.1 (8KB, read-only)IDE[]- XTIDE ROM (read-only)FLOPPY[]- Floppy disk image (read-only)
- Tandy mode patching example: Since BIOS is read-only, patching is done in
memory_read():// In memory.h - dynamic "patch" via conditional return if (address == 0xFFFFE && settings.tandy_enabled) { return 0xFF; // Return patched value instead of BIOS[8190] }
- Global device structures:
i8259,i8253,i8272,dma_channels[],uart,mc6845,cga,ide - RAM arrays:
RAM[],UMB[],VIDEORAM[](these ARE writable, in PSRAM/SRAM)
memory.h - Memory emulation:
memory_read()/memory_write(): Handles RAM/ROM/VIDEORAM/UMB access- 4-byte aligned arrays for optimal performance
- PSRAM support for 736KB conventional RAM
ports.h - I/O ports routing:
port_read()/port_write(): 16-bit operations with BHE support- Direct routing to device emulation functions (no port array)
hardware/i8259.h - Intel 8259A PIC:
- Full ICW1-ICW4 and OCW1-OCW3 support
- Fully Nested Mode with automatic priorities
- Non-specific EOI uses
__builtin_ctz()to find highest priority ISR bit - Specific EOI clears only ISR without touching IRR
- Functions:
i8259_read(),i8259_write(),i8259_interrupt(),i8259_nextirq()
hardware/i8253.h - Intel 8253 PIT:
- 3 independent channels with reload values
- Access modes: LOBYTE, HIBYTE, TOGGLE, LATCHCOUNT
- Channel 0 (System Timer): One-shot interrupt on terminal count via hardware
repeating_timer, usesirq0_timer_callback()for dynamic timer control - Channel 1 (Memory Refresh): Emulated for compatibility (not actively used)
- Channel 2 (PC Speaker): Controls PWM output on GPIO 46 via port 0x61 bits 0-1, frequency = 1193182 / reload_value
- Dynamic timer_interval calculation based on reload value
- PC Speaker hardware controlled by
pwm_set_gpio_level()when enabled via port 0x61
hardware/i8237.h - Intel 8237 DMA Controller:
- 4 channels with auto-initialization support
- Memory-to-memory transfer mode
- Page registers for 20-bit addressing
- Functions:
i8237_read(),i8237_write(),i8237_readpage(),i8237_writepage()
hardware/i8272.h - Intel 8272A Floppy Controller:
- Full command emulation (read/write sectors, seek, recalibrate)
- DMA integration via channel 2
- IRQ6 generation on operation completion
- Supports multiple disk formats (160KB-1.44MB)
hardware/ide.h - XTIDE/ATA Hard Disk Controller:
- Full XTIDE controller emulation at ports 0x300-0x308
- LBA28 and CHS addressing modes support
- Implemented commands: IDENTIFY DEVICE (0xEC), READ SECTOR(S) (0x20), WRITE SECTOR(S) (0x30), READ VERIFY (0x40/0x41)
- Works with HDD image file (hdd.img) on SD card via FatFS
- 512-byte sector buffer for efficient I/O operations
- Status register with BUSY, DRDY, DSC, DRQ, ERR flags
- Multi-sector transfers with automatic LBA increment
- Geometry: 16 heads, 63 sectors per track (standard CHS)
- Functions:
ide_read(),ide_write(),ide_identify(),read_sector(),write_sector()
hardware/uart.h - 16550 UART emulation:
- Full COM1 emulation at ports 0x3F8-0x3FF
- FIFO support for buffered serial I/O
- Used for CTTY mode (direct terminal access)
hardware/mc6845.h - Motorola 6845 CRTC:
- Video timing control for CGA adapter
- Cursor position and display parameters
- Register-based configuration via ports 0x3D4/0x3D5
i8086_bus.pio - PIO state machine:
- Captures 20-bit address + control signals
- Optimized polling for RD/WR/INTA detection
- Sideset delays for timing optimization
- 32-bit protocol for ISA-compatibility
bios.h - BIOS ROM images:
- Turbo XT BIOS v3.1 (default, 8KB)
- Landmark Diagnostic ROM (for testing)
- Ruud's Diagnostic ROM v5.4 (for validation)
drivers/vga-nextgen/ - Hardware VGA video driver:
- Uses PIO1 to generate VGA timing signals (hsync, vsync)
- Outputs 8-bit RGBI signal on GPIO 30-37 (VGA_BASE_PIN)
- Supported video modes:
- CGA Text: 80×25 characters (16 colors)
- CGA Graphics: 320×200×4 colors (standard IBM CGA)
- PCjr Low-Res: 160×200×16 colors (IBM PCjr/Tandy 1000)
- PCjr High-Res: 320×200×16 colors (IBM PCjr/Tandy 1000)
- R-2R DAC resistor ladder converts digital to analog VGA signal
- DMA-based refresh from VIDEORAM at 60 FPS
- Mode switching via MC6845 CRTC registers (ports 0x3D4/0x3D5)
drivers/sdcard/ - SD Card SPI driver:
- Uses SPI1 bus (GPIO 40-43: MISO, CS, SCK, MOSI)
- Mounts FAT12/FAT16/FAT32 filesystem from SD card at boot
- Loads floppy disk images (.img files) for i8272A FDC emulation
- Loads hard disk images (hdd.img) for XTIDE controller emulation
- Supported disk image formats:
- 160KB (SS/SD, 8 sectors/track)
- 180KB (SS/SD, 9 sectors/track)
- 320KB (DS/SD, 8 sectors/track)
- 360KB (DS/DD, 9 sectors/track, standard 5.25")
- 720KB (DS/DD, 9 sectors/track, 3.5")
- 1.2MB (DS/HD, 15 sectors/track, 5.25")
- 1.44MB (DS/HD, 18 sectors/track, 3.5")
- Auto-detection of disk geometry from image file size
- Configurable pin assignments via CMakeLists.txt compile definitions
- Integrated with FAT filesystem driver for DOS compatibility
- Primary use: boot DR-DOS 7 and other DOS-based operating systems from floppy/HDD images stored on SD card
- HDD images support: LBA28 addressing with up to 8GB capacity (limited by FatFS file size)
drivers/usbhid/ - USB HID driver (TinyUSB stack):
- tusb_config.h: TinyUSB configuration
- CFG_TUH_ENABLED = 1 (USB Host mode enabled)
- CFG_TUH_HID = 4 (supports up to 4 HID interfaces - keyboard + mouse)
- CFG_TUH_HUB = 1 (USB hub support, up to 4 devices)
- CFG_TUH_DEVICE_MAX = 4 (maximum 4 devices simultaneously)
- usb_to_xt_scancodes.h: USB HID → XT Scancode conversion table
- Full keyboard mapping (104-key layout)
- Supports all keys: F1-F12, NumPad, arrows, modifiers (Shift, Ctrl, Alt)
- Extended scancodes for special keys (Insert, Delete, Home, End, etc.)
- hid_app.c: USB HID application layer
tuh_hid_mount_cb(): Detects keyboard/mouse on connectiontuh_hid_report_received_cb(): Processes HID reportstuh_hid_umount_cb(): Handles device disconnection- Keyboard: Converts USB HID → XT Scancodes → calls
handleScancode()in main app - Mouse: Converts HID → Microsoft Serial Mouse protocol (3 bytes) → COM1 UART
- Auto-detection: When DOS driver sets DTR/RTS on COM1, sends identifier "M"
- Works with DOS mouse drivers: CTMOUSE, MOUSE.COM (Microsoft Serial Mouse compatible)
setup.h / setup.c - Configuration menu system:
- settings_s structure: Project configuration (versioned for compatibility)
version- Settings file version (uint16_t, current = SETTINGS_VERSION)cpu_freq_index- CPU frequency selector (0=1MHz, 1=4.75MHz, 2=6MHz)tandy_enabled- IBM PCjr/Tandy 1000 compatibility modefda,fdb,hdd- Disk image paths (256 chars each)
- Settings versioning: File format validation prevents loading incompatible configs
- Increment
SETTINGS_VERSIONwhen changingsettings_sstructure load_settings()checks version and file size - rejects mismatches- Rejected configs → use default settings (prevents crashes from old/corrupt files)
- Increment
- File browser: SD card file selection with directory navigation
- Menu system: Arrow key navigation, ENTER/ESC controls
- Persistence: Saves to
/XT/config.syson SD card (binary format) - Called before Core1 launch: Settings loaded → SETUP menu → Core1 starts with selected config
i8086 Address Space (1MB):
0x00000 - 0xB7FFF : RAM (736KB) - 4-byte aligned, external PSRAM via QMI
0xB8000 - 0xBBFFF : Video RAM CGA (16KB) - 4-byte aligned
0xBC000 - 0xFDFFF : Unmapped (returns 0xFFFF)
0xFE000 - 0xFFFFF : ROM Turbo XT BIOS v3.1 (8KB) - 4-byte aligned
Reset vector at 0xFFFF0 points into ROM.
Special Memory Addresses (Tandy/PCjr compatibility):
- 0xFC000: Tandy signature detection
- Returns
0x21whensettings.tandy_enabled == 1 - Returns
0xFFFF(unmapped) when Tandy mode disabled - Used by software to detect IBM PCjr/Tandy 1000 hardware
- Returns
- 0xFFFFE: BIOS compatibility byte (dynamic patching)
- Returns
0xFFwhensettings.tandy_enabled == 1 - Returns original BIOS value when Tandy mode disabled
- BIOS is read-only in FLASH - patching done via conditional logic in
memory_read() - See
common.csection above for why IMPORT_BIN arrays cannot be modified at runtime
- Returns
RP2350B Physical Memory (memmap.ld):
0x10000000 - 0x10FFFFFF : FLASH (16MB) - Code and constants
0x20000000 - 0x2007FFFF : RAM (512KB) - Execution, stack, heap (copy_to_ram)
0x20080000 - 0x20080FFF : SCRATCH_X (4KB) - Core0 fast scratchpad
0x20081000 - 0x20081FFF : SCRATCH_Y (4KB) - Core1 fast scratchpad
0x11000000 - 0x117FFFFF : PSRAM (8MB) - i8086 memory emulation
Currently used: 736KB RAM + 16KB VRAM + 8KB ROM = 760KB
Available for expansion: 7.26MB (can support extended/expanded memory)
Potential expansions:
- EMS (Expanded Memory Specification): Up to 7MB of page-switched memory
- XMS (Extended Memory Specification): High memory area (HMA) emulation
- RAM disk: Fast storage in unused PSRAM
- Additional video buffers: For page flipping or multiple video modes
Current emulated ports:
- 0x00-0x0F: Intel 8237 DMA Controller (4 channels, auto-init, memory-to-memory)
- 0x20-0x21: Intel 8259A PIC (IRQ0-IRQ7 management, ICW/OCW support)
- 0x40-0x43: Intel 8253 PIT (3 channels: timer, memory refresh, PC speaker)
- 0x60: Keyboard Data Port (i8042 emulation, scancode read/write)
- 0x61: System Control Port B (keyboard reset, speaker enable via bit 0-1, timer gate)
- 0x64: Keyboard Status Port (i8042 emulation, output buffer status)
- 0x81/82/83/87: DMA Page Registers (20-bit addressing for DMA channels)
- 0x300-0x308: XTIDE/ATA Hard Disk Controller (LBA28/CHS, sector I/O, status/command)
- 0x3D0-0x3DF: CGA/MC6845 CRTC registers (video timing, cursor position)
- 0x3F0-0x3F7: Intel 8272A FDC (floppy disk controller, DMA channel 2)
- 0x3F8-0x3FF: 16550 UART (COM1, used for CTTY mode and DOS serial I/O)
Edit port_read8() and port_write8() in ports.h. Add switch cases for the port range and call the appropriate device emulation function.
System Clocks:
- RP2350B: 500 MHz (overclocked with voltage boost to 1.60V)
- PIO: 500 MHz (clkdiv = 1.0, no frequency divider)
- i8086: 4.75-6 MHz (configurable, currently stable at these frequencies)
Available Ticks & Core 1 Load Analysis:
- Total Ticks: The RP2350B provides 500,000,000 ticks per second for Core 1.
- Ticks per i8086 Cycle: Approximately 83-105 RP2350B ticks per i8086 clock cycle (500 MHz / 6 MHz = ~83 ticks).
- PIO Processing Time: PIO state machine handles bus protocol in hardware with deterministic timing (2.0 ns per instruction at 500 MHz).
- Bus Handling: Core 1's primary critical task is servicing PIO interrupts for i8086 bus cycles.
- Worst-Case Load: Even at 6 MHz with continuous bus access, Core 1 load remains below 45%, leaving ample headroom for device emulation.
Critical optimizations:
- All bus handlers run from RAM (
__time_critical_func) - 4-byte aligned memory arrays for fast access (RAM, VIDEORAM, BIOS)
- Direct 16-bit memory access via pointer casting
- Inline functions (
__force_inline) for hot paths likely()/unlikely()hints for branch prediction- Minimal volatile variable usage (local copies in hot paths)
- PIO instruction count: 29/32 used (bus controller)
- Hardware repeating_timer for IRQ0 instead of polling loop
__wfe()on Core1 for power efficiency when idle- DMA-driven VGA refresh (zero CPU overhead on Core0)
- PSRAM accessed via QMI for high-speed 736KB RAM
- SD Card I/O performed during initialization only (zero runtime overhead)
- PC Speaker uses hardware PWM (no CPU polling required)
Core utilization:
- Core0: ~15-20% (VGA handled by DMA, USB HID via TinyUSB, keyboard/mouse input sporadic)
- Core1: ~45% worst case (bus handling at 6 MHz, device emulation)
- Total system headroom: ~35-40% available for future features
USB HID performance:
- TinyUSB processes HID reports at ~1ms intervals (1000 Hz polling)
- Keyboard latency: <2ms (USB poll + XT conversion + i8042 injection)
- Mouse latency: <2ms (USB poll + Serial Mouse conversion + COM1 UART)
- Zero impact on i8086 bus performance (all processing on Core0)
Wrong order = i8086 starts before PIO is ready = bus conflicts!
Core1 (bus_handler_core) initialization sequence:
start_cpu_clock(); // 1. Start clock first
pic_init(); // 2. Initialize INTR pin
cpu_bus_init(); // 3. Load PIO program, setup IRQ handlers
reset_cpu(); // 4. Release i8086 from reset (MUST be last!)Never call reset_cpu() before cpu_bus_init().
- Follow KISS principle (Keep It Simple, Stupid)
- Self-documenting code preferred over excessive comments
- Functions only created when code is reused
- Comments in Russian for this project
- No emojis unless explicitly requested
Edit i8086_bus.pio carefully - timing-sensitive:
- All comments in Russian
- Test thoroughly - incorrect timing can hang i8086
- RD checked before WR in polling loop (80% of operations are reads)
- PIO program auto-recompiled via
pico_generate_pio_header()during build - Output:
src/i8086_bus.pio.h(auto-generated, do not edit manually)
Important CMakeLists.txt features:
- Auto-versioning: Git branch and commit hash embedded in binary
- Accessible via
PICO_BUILD_NAME,PICO_GIT_BRANCH,PICO_GIT_COMMITdefines - Displayed in boot messages and debug output
- Accessible via
- Build numbering: Post-build script auto-increments
.build_numberfile- Output format:
RP8086-<branch>-<build_number>.uf2 - Useful for tracking firmware versions
- Output format:
- Conditional USB: USB HID only compiled in RELEASE mode
- DEBUG mode:
stdio_usbenabled for debugging via USB serial - RELEASE mode:
tinyusb_host+usbhidenabled for USB keyboard/mouse
- DEBUG mode:
- Memory usage reporting: Linker prints memory usage summary after build
- Shows FLASH, RAM, PSRAM usage
- Helps track size optimizations
Compile-time configuration:
- Pin assignments are compile-time constants (cannot be changed at runtime)
- Change pin mappings in
CMakeLists.txt→ rebuild required - PIO programs depend on specific pin locations → test thoroughly after changes
Pico SDK libraries used:
pico_runtime- Core runtime initialization (clocks, PLLs, voltage control)pico_stdlib- Standard library (GPIO, time, interrupts)pico_stdio- Standard I/O (USB serial for debugging)pico_multicore- Dual-core support (Core0/Core1 synchronization)hardware_pio- PIO state machine API (i8086 bus controller, VGA timing)hardware_pwm- PWM API (i8086 clock generator, PC Speaker)tinyusb_host- USB Host stack (keyboard/mouse support, RELEASE mode only)tinyusb_board- Board-specific USB configuration (RELEASE mode only)
Special commands (uppercase, not sent to i8086):
- 'M': Memory dump (interactive - prompts for address in hex)
- 'V': Video RAM dump (contents of VRAM at 0xB8000)
- 'R': Reset CPU
- 'B': Reboot RP2350B to bootloader mode
- 'C': Toggle CTTY mode (direct COM1/USB terminal, disables video)
- 'P': Dump CGA/CRTC register values
Regular input:
- All other characters converted to scancodes and sent to i8042
- Generates IRQ1 (keyboard interrupt) automatically
IRQ priorities (Fully Nested Mode):
- IRQ0 (timer) > IRQ1 (keyboard) > IRQ6 (floppy) > ...
IRQ0 (Timer) - Core1:
// Hardware repeating_timer callback
static bool irq0_timer_callback(struct repeating_timer *t) {
i8259_interrupt(0); // Sets bit in IRR[0]
return channel->operating_mode != 0; // Stop timer for mode 0
}IRQ1 (Keyboard) - Core0:
push_scancode(scancode); // Calls i8259_interrupt(1)IRQ6 (Floppy) - FDC emulation:
i8272_irq(); // Calls i8259_interrupt(6) if enabledINTR Management:
gpio_put(INTR_PIN, i8259_get_pending_irqs()); // Checks IRR & ~IMREOI (End of Interrupt):
- Non-specific EOI (0x20): Clears highest priority ISR bit via
__builtin_ctz() - Specific EOI (0x60 + IRQ): Clears only specified ISR bit
- BIOS sends 0x20 to port 0x20 after interrupt handling
Port 0x61 (System Control Port B):
- Bit 6 (0x40): Keyboard reset trigger
- Rising edge on bit 6 generates scancode 0xAA (self-test passed) and IRQ1
- Used by diagnostic ROMs to test keyboard controller
Port 0x60 (Keyboard Data Port):
- Read: Returns current scancode (0 if none available)
- Write: Sets scancode to 0xAA for self-test response
- Scancodes can come from two sources:
- USB keyboard: USB HID driver converts to XT scancodes and calls
handleScancode() - Serial terminal: ASCII input converted to scancodes for debugging
- USB keyboard: USB HID driver converts to XT scancodes and calls
Architecture:
- USB Host stack runs on Core0 via
tuh_task()in main loop - HID reports processed in interrupt context by TinyUSB
- Callbacks in
drivers/usbhid/hid_app.c:tuh_hid_mount_cb(): Called when USB HID device connectedtuh_hid_report_received_cb(): Called on each HID report (keyboard keys, mouse movement/buttons)tuh_hid_umount_cb(): Called when USB HID device disconnected
Keyboard flow:
USB Device → TinyUSB Host Stack → tuh_hid_report_received_cb() →
USB HID Scancode → usb_to_xt_scancodes[] lookup → XT Scancode →
handleScancode() → i8042 controller → Port 0x60
Mouse flow:
USB Device → TinyUSB Host Stack → tuh_hid_report_received_cb() →
HID Mouse Report (X, Y, buttons) → Microsoft Serial Mouse packet (3 bytes) →
uart_write_byte() → COM1 (ports 0x3F8-0x3FF) → DOS mouse driver
Mouse auto-detection:
- USB mouse plugged in →
tuh_hid_mount_cb()sets flagusb_mouse_connected = true - DOS driver (CTMOUSE, MOUSE.COM) starts and sets DTR/RTS on COM1
uart16550.hdetects DTR/RTS change, checksis_usb_mouse_connected()- If mouse connected → sends Microsoft Serial Mouse identifier "M" to DOS driver
- DOS driver recognizes mouse and starts reading movement/button data from COM1
Supported USB HID devices:
- Standard USB keyboards (104-key layout, full scancode support)
- Standard USB mice (3-button + scroll wheel)
- USB hubs (up to 4 ports, CFG_TUH_DEVICE_MAX = 4)
- Combined keyboard+mouse devices (e.g., laptops with touchpad)
IMPORTANT:
- Всегда спрашивать разрешение перед коммитом
- Никогда не коммитить изменения без согласия пользователя
- Никогда не собирать проект автоматически (пользователь собирает сам)
- Никогда не добавлять намеки про наличие AI в коммиты
When user requests commit:
- Run
git statusandgit diff - Draft concise commit message in Russian
- Ask for approval before executing commit
- Never use
--no-verifyor skip hooks
Diagnostic ROMs:
- Landmark Diagnostic ROM: Tests all hardware components (IRQ, PIT, keyboard, memory)
- Ruud's Diagnostic ROM v5.4: Comprehensive PC/XT hardware validation
- CheckIt: System board and peripheral testing
Test Results (after recent interrupt fixes):
- ✅ Landmark Diagnostic ROM: All tests pass without errors
- ✅ Ruud's Diagnostic ROM v5.4: Complete hardware check passes
- ✅ Boulder Dash: Runs correctly with keyboard input
- ✅ CheckIt: System board and keyboard tests pass
- ✅ DR-DOS 7: Successfully boots from floppy image
Common issues fixed:
- Intel 8253 Mode 0: Now correctly generates one-shot interrupts
- Intel 8259A EOI: Non-specific EOI clears only highest priority ISR bit
- Keyboard reset: Port 0x61 bit 6 rising edge triggers self-test response
Machine-readable specifications are available in docs/specs/ directory in TOON format (Token-Oriented Object Notation) for efficient token usage:
intel_8086_specs.toon: CPU architecture, registers, interruptsintel_8259a_specs.toon: PIC configuration and operationintel_8253_specs.toon: PIT modes and channel configurationintel_8237a_specs.toon: DMA controller channels and modesintel_8272a_specs.toon: FDC commands and disk formatsi8086_architecture_reference.toon: Complete system architectureport_addresses.toon: I/O port map for IBM PC/XT
PDF datasheets from manufacturers are in docs/datasheets/ for detailed reference.