Full system emulation with 6502 CPU, 48KB RAM, text and hi-res graphics video modes, Disk II controller with WOZ image support, keyboard input, and piezo speaker.
1.023 MHz processor
Memory mapping, bank switching
Main memory + aux banks
Text, Lo-Res, Hi-Res modes
$C000 latch + strobe
Stepper motor, WOZ images
$C030 toggle, 1-bit
| Subsystem | Details |
|---|---|
| CPU | MOS 6502 @ 1.023 MHz (NTSC timing) |
| Memory | 48KB main RAM, 12KB ROM (Monitor + Applesoft BASIC) |
| Video: Text | 40x24 characters, normal and inverse |
| Video: Lo-Res | 40x48 blocks, 16 colors |
| Video: Hi-Res | 280x192 pixels, 6 colors (artifact coloring) |
| Storage | Disk II controller, 140KB 5.25" floppies, WOZ format |
| Input | ASCII keyboard with $C000 data latch, $C010 strobe |
| Audio | 1-bit speaker toggle at $C030 |
| I/O slots | 8 expansion slots ($C100-$C7FF ROM, $C080-$C0FF soft switches) |
The system bus connects the CPU to memory and I/O devices through memory-mapped soft switches in the $C000-$C0FF range.
class Apple2 < RHDL::Sim::SequentialComponent
input :clk, :rst
input :key_data, width: 7
input :key_strobe
output :video_out, width: 8
output :spkr_out
subcomponent :cpu, MOS6502
subcomponent :ram, RAM48K
subcomponent :rom, ROM12K
subcomponent :video, VideoGenerator
subcomponent :disk, DiskII
subcomponent :kbd, Keyboard
wire :addr, width: 16
wire :data, width: 8
wire :rw
behavior do
# Memory map
data <= case_select(addr[15..12], {
0x0..0xB => ram.data_out,
0xC => io_read(addr),
0xD..0xF => rom.data_out,
})
end
end
The video generator produces text, lo-res, and hi-res output by scanning the peculiar Apple II memory layout where rows interleave across three 2KB sections.
class VideoGenerator < RHDL::Sim::SequentialComponent
input :clk, :rst
input :mem_data, width: 8
input :mode, width: 2
output :mem_addr, width: 16
output :pixel, width: 4
output :h_sync, :v_sync
sequential clock: :clk,
reset: :rst do
# Apple II screen memory layout
# Row address = base + (row/8)*40
# + (row%8)*0x80
base = mux(page,
0x0400, 0x0800)
row_group = v_count[5..3]
row_third = v_count[2..0]
mem_addr <= base +
(row_group * 40) +
(row_third << 7) +
h_count
end
end