ewm one now runs windowed:
- ewm-core/src/chr.rs: the bitmap half of chr.c — the 2716 character
ROM (3410036.bin, embedded) decodes to 7x8 glyphs indexed by Apple ][
screen code, with the same table layout as ewm_chr_init (normal
$A0-$DF, inverse $00-$3F, flashing-as-inverse $40-$7F). Unit
tests pin the 'A' glyph, inverse glyphs, and unmapped slots.
- ewm/src/tty.rs: tty.c — 24x40 screen buffer, scrolling, blinking
cursor, rendered into a 280x192 pixel buffer.
- ewm/src/sdl.rs: sdl.c — pixel-format pick and green phosphor color.
- ewm/src/one.rs: the SDL loop of one.c — 40 fps cycle bursts
(1023000/40), the same key mapping (including one.c's TAB
fallthrough that also sends DEL, and ctrl-a mapping to 0x00),
Cmd-Esc reset, Cmd-Return fullscreen, and --model/--memory/
--trace/--strict flags. Extra --memory regions are supported by
new One::add_ram/add_rom (dispatched LIFO like the C mem list).
- ewm/src/main.rs: subcommand dispatch; two/boo report not ported.
The sdl2 crate now uses the use-pkgconfig feature: linking the real
SDL symbols needs the Homebrew/pkg-config library path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Phase 3: headless Apple 1 / Replica 1
Ports the machine layer for the One:
- pia.rs: the 6820 PIA from pia.c. The C output callback becomes a
return value — Pia::write yields (ddr, byte) when an output register
is written — and reads keep the IRQA1-clear side effect.
- one.rs: One implements Bus with the C memory map (Apple 1: 8K RAM +
Woz monitor ROM at $FF00 on a 6502; Replica 1: 32K RAM + Krusader
ROM at $E000 on a 65C02; PIA at $D010). ROMs are embedded with
include_bytes! so nothing needs to run from src/. Display bytes are
collected in a drainable buffer, with the Apple 1's 7-bit masking
applied exactly where ewm_one_pia_callback did. One::key latches
key | 0x80 into the PIA and raises IRQA1, per ewm_one_keydown.
- tests/one_boot.rs: both machines boot to the Woz monitor prompt;
FF00.FF0F (Apple 1) and E000.E00F (Replica 1) dumps are verified
against the actual ROM bytes; typed characters echo back.
utl.c is not ported: ewm_utl_endswith is str::ends_with, and the
clock_gettime shim is obsolete.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add an interactive console example for the headless One
cargo run -p ewm-core --example one -- [apple1|replica1] gives a
line-based Woz monitor console, so the machine can be tried by hand
before the SDL frontend lands in Phase 4.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Make the example's demo program print HI!
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Completes the CPU core port:
- ins.rs: the 65C02 override handlers ((zp) modes, BRA, STZ, PHX/PHY/
PLX/PLY, TRB/TSB, RMB/SMB, BBR/BBS, INC/DEC A, BIT imm/zpgx/absx,
JMP (abs,X)) and the override table transcribed verbatim from
instructions_65C02 — including its 1-cycle NOPs and the stray 0x03
opcode fields. The table is overlaid onto the 6502 table once, the
Rust version of cpu_initialize()'s back-fill. C's arity-cast NOPs
become explicit nop_byte/nop_word wrappers.
- fmt.rs: cpu_format_state, cpu_format_stack, and the disassembler
from fmt.c, bugs preserved (0x9c prints JMP; BBR/BBS targets are
computed from pc+2).
- tests/dormann.rs: dormann_65c02 passes at $24a8 after 65,094,140
cycles — exactly the C emulator's count.
- Golden-trace harness: scripts/gen-golden-trace.{c,sh} builds a
capture program against the unmodified C sources and records the
first 100k instructions of the functional test as normalized
'PC A X Y SP P' lines; checked in gzipped. trace_compare.rs replays
it on the Rust core and reports the first divergent instruction
(currently: zero divergence). flate2 is a dev-dependency only.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Ports cpu.c, mem.c, and the 6502 half of ins.c to rust/ewm-core:
- bus.rs: the Bus trait (replacing the mem_t linked list) and a flat
64K TestBus for the CPU test harness
- cpu.rs: registers, separate raw-valued flag fields packed/unpacked
only in status()/set_status(), stack ops with u8 sp wraparound,
reset/irq/nmi (keeping the pc+1 interrupt push quirk the Dormann
tests depend on), strict-mode stack overflow checks, and step()
with pc advanced before handler dispatch
- ins.rs: the 3-variant Handler arity enum, addressing-mode and RMW
helpers ported expression-for-expression from mem.c (including the
indx zero-page wrap and the indy non-wrap), ~200 handlers in ins.c
source order, and the 256-entry table transcribed verbatim
- tests/dormann.rs: the cpu_test.c harness (success PC $3399,
branch-to-self deadlock detection) plus unit tests for status
round-trip, stack wraparound, and the indexed-indirect quirks
The Rust core executes 88,957,316 cycles for the functional test —
exactly the C emulator's count.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Phase 0: Rust workspace scaffolding + CI
Adds the parallel Rust workspace under rust/ per REWRITE.md:
- ewm-core (headless lib, zero dependencies) and ewm (binary,
declares sdl2 now so CI installs SDL2 headers from day one;
prints the same usage line as the C binary)
- rust-toolchain.toml pinning 1.91.1 with rustfmt + clippy
- GitHub Actions CI: C build job (ubuntu + libsdl2-dev) and Rust
job (fmt --check, clippy -D warnings, test)
- Anchor the 'ewm' gitignore pattern to src/ so rust/ewm is tracked;
ignore rust/target/
- README note pointing at REWRITE.md
The C tree in src/ is untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* CI: build the C tree on macOS
gcc on ubuntu fails -Werror with -Wimplicit-fallthrough in two.c;
src/ is frozen until Phase 9, so build C where it has always built
(macOS, as Travis did).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* CI: point clang at the Homebrew prefix via CPATH/LIBRARY_PATH
The committed Makefile does not search /opt/homebrew, so SDL2
headers are not found on the arm64 macOS runner. src/ is frozen,
so pass the paths through the environment instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Add sound subsystem that emulates the Apple II speaker by:
- Tracking speaker state toggles when $C030 is accessed
- Generating audio samples based on CPU cycle timing
- Outputting 44.1 kHz audio via SDL
New files: snd.h, snd.c
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Replace the 2-bit pairing approach with per-pixel rendering to eliminate
color artifacts at edges. The new implementation processes each pixel
individually, uses each byte's own high bit for palette selection, and
properly detects adjacent pixels for white rendering.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>