Commit Graph

6 Commits

Author SHA1 Message Date
188444f987 feat(mmc5): implement MMC5 mapper with accurate scanline IRQ and CHR banking
Some checks failed
CI / rust (push) Has been cancelled
- Add ExRAM (modes 0-1) and fill-mode nametable routing via
  read_nametable_byte / write_nametable_byte mapper hooks
- Separate sprite and BG CHR bank sets ($5120-$5127 vs $5128-$512B);
  BG banks are only active in 8x16 sprite mode
- Use mapper.ppu_read_sprite() for sprite tile loads so they always
  use the sprite bank set regardless of PPU fetch phase
- Replace CPU-cycle IRQ stub with scanline-based counter matching
  Mesen2 hardware behaviour: fire when counter == irq_scanline at
  dot 2 (start of scanline), irq_scanline=0 never fires
- Add Mapper::notify_frame_start() called unconditionally at the PPU
  frame boundary; MMC5 uses it to hard-reset the scanline counter even
  when rendering is disabled (e.g. during room transitions), preventing
  stale counter values from shifting the CHR split by 8+ scanlines
- Fix CHR bank calculation for modes 0-2: use << 3/2/1 shifts instead
  of & !7/3/1 masking to correctly convert bank numbers to 1KB indices
- Correct $5204 read: bit 7 = IRQ pending (cleared on read), bit 6 =
  in-frame flag; IRQ line stays asserted until $5204 is read
- Dispatch $4020-$5FFF CPU reads/writes to mapper cpu_read_low /
  cpu_write_low so MMC5 internal registers are accessible
2026-03-15 17:10:50 +03:00
d9666c23b4 feat: Hermite resampling, sprite shift registers, controller open bus
Some checks failed
CI / rust (push) Has been cancelled
#3 audio.rs: replace linear interpolation with Catmull-Rom Hermite cubic.
  Stores prev_sample as p0 control point; m1=(p2-p0)/2, m2=(p2-p1)/2
  tangents give continuous first derivative across batch boundaries.

#4 ppu: add per-slot sprite shift registers (spr_shift_lo/hi, spr_x_counter,
  spr_attr_latch). load_sprite_shifters fetches pattern bytes with h-flip at
  dot 1 of each visible scanline. sprite_pixel_from_shifters replaces the
  per-pixel OAM scan; sprite-0 hit detection integrated into the shifter path.

#5 joypad.rs: format_controller_read now preserves bits 1-5,7 as open bus
  (!0x41 mask) instead of zeroing bits 1-4, matching NES hardware behaviour.
2026-03-15 11:30:14 +03:00
d8f41bc2c9 fix(apu): correct frame counter timing, add LP filter, mute aliased triangle
- Fix frame counter running at 2× speed: clock_frame_counter now skips
  odd CPU cycles (APU cycle = CPU/2), so envelope, sweep, and length
  counters tick at the correct rate. Fixes sweep-driven whistle in Megaman II.

- Switch audio sampling to per-CPU-cycle granularity in
  run_until_frame_complete_with_audio to eliminate square-wave harmonic
  aliasing caused by sampling only once per instruction.

- Add IIR one-pole low-pass filter (~14 kHz) to AudioMixer to smooth
  abrupt level transitions (crackling) introduced by correct envelope timing.

- Mute triangle channel when timer_period < 2 (≥27 kHz), which aliases
  into the audible range at 48 kHz. Real NES RC circuit removes these
  ultrasonics; emulator must suppress them explicitly.

- Update all APU bus tests to use correct (doubled) CPU cycle counts.
2026-03-15 10:44:43 +03:00
d2be893cfe fix: stabilize desktop audio playback
Some checks failed
CI / rust (push) Has been cancelled
2026-03-13 19:20:33 +03:00
cd0a99a813 feat(apu): add timer/sequencer/LFSR fields for channel output tracking 2026-03-13 16:06:37 +03:00
bdf23de8db Initial commit: NES emulator with GTK4 desktop frontend
Some checks failed
CI / rust (push) Has been cancelled
Full NES emulation: CPU, PPU, APU, 47 mappers, iNES/NES 2.0 parsing.
GTK4 desktop client with HeaderBar, pixel-perfect Cairo rendering,
drag-and-drop ROM loading, and keyboard shortcuts.
187 tests covering core emulation, mappers, and runtime.
2026-03-13 11:48:45 +03:00