Skip to content

Feature: System Emulation Framework (C64, generic modes) #6

@barryw

Description

@barryw

Summary

Transform sim6502 from a processor emulator to a system emulation framework. Instead of processor(6502|6510|65c02), users will declare system(c64) or system(generic_6502) to get accurate memory maps, ROM overlays, and banking behavior.

This addresses #5 where C64 code writing to $A000-$DFFF (under BASIC/KERNAL ROM) corrupts code because the simulator uses flat 64KB RAM instead of the C64's layered memory architecture.

Motivation

Real 6502-based systems have complex memory architectures:

  • C64: RAM "underneath" ROM, banking controlled by $01 processor port
  • Apple II: Soft switches for bank selection
  • Commander X16: VERA, banked RAM/ROM

The current flat 64KB model can't accurately test code that relies on these behaviors.

Proposed Design

1. New DSL Syntax

; New system declaration (processor auto-determined)
system(c64)              ; 6510 + C64 memory map + banking
system(generic_6502)     ; Plain 6502, flat 64KB (current behavior)
system(generic_6510)     ; 6510 with $00/$01 I/O, flat memory
system(generic_65c02)    ; 65C02, flat 64KB

; ROM loading (new)
rom("kernal", "kernal.901227-03.bin")
rom("basic", "basic.901226-01.bin")

; Program loading (existing, unchanged)
load("my-program.prg")

2. Backward Compatibility

processor() syntax continues to work but emits deprecation warning:

processor(6502)  →  Warning: processor() is deprecated, use system(generic_6502)

3. Memory Architecture

public interface IMemoryMap
{
    byte Read(int address);
    void Write(int address, byte value);
    void LoadRom(string name, byte[] data);
    void RegisterIOHandler(int startAddr, int endAddr, IIOHandler handler);
}

public interface IIOHandler
{
    byte Read(int address);
    void Write(int address, byte value);
}

Each system implements IMemoryMap:

  • GenericMemoryMap - flat 64KB (current behavior)
  • C64MemoryMap - RAM + ROM layers + $01 banking

4. C64 Memory Banking (Initial)

Banking controlled by $01 processor port bits 0-2:

$01 Value LORAM HIRAM CHAREN Result
$37 1 1 1 BASIC + KERNAL + I/O (default)
$36 0 1 1 KERNAL + I/O
$35 1 0 1 All RAM visible
$34 0 0 0 All RAM, no I/O
... (8 combinations)

EXROM/GAME cartridge lines deferred to future release.

5. I/O Handling

I/O region ($D000-$DFFF) uses callback hooks:

  • Default stubs return sensible values
  • VIC-II: return last written or defaults
  • SID: writes ignored (no audio emulation)
  • CIA: basic stubs, can be extended later

6. ROM Configuration

Layered lookup (highest priority first):

  1. DSL override: rom("kernal", "custom.bin")
  2. Config file: ~/.sim6502/systems.json
  3. Environment: SIM6502_ROM_PATH=/roms
  4. Default paths: ./roms/{system}/ or ~/.sim6502/roms/{system}/

Users must supply their own legally-owned ROM images.

7. Initial System Support

System Processor Memory Model
c64 6510 Full C64 banking
generic_6502 6502 Flat 64KB
generic_6510 6510 Flat 64KB + $00/$01
generic_65c02 65C02 Flat 64KB

Future: C128, VIC-20, Apple II, Commander X16, NES

Implementation Tasks

  1. Define IMemoryMap and IIOHandler interfaces
  2. Create GenericMemoryMap (extract current behavior)
  3. Create C64MemoryMap with banking logic
  4. Add system() grammar rule and visitor
  5. Add rom() grammar rule and visitor
  6. Deprecate processor() with warning
  7. Implement ROM configuration loading
  8. Create C64-specific tests
  9. Update documentation

Related Issues

Questions for Reviewers

@barryw - Please review this spec

  • Does this cover your chess engine's needs?
  • Any C64 banking edge cases I missed?
  • Priority of future systems (X16, Apple II, etc.)?

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions