added a state dumper for headless checks
This commit is contained in:
@@ -44,6 +44,8 @@
|
||||
- NMI/IRQ servicing done (src/cpu.rs): set_nmi/set_irq setters, shared interrupt() helper (push PC hi/lo, push p with B CLEAR unlike BRK, set I, jump vector, 7 cycles), NMI checked before IRQ at the top of step, IRQ masked by the I flag, cycles accumulated on both interrupt paths. cpu_interrupts.nes currently reports $6000=01 - it runs but needs the APU frame-counter IRQ source ($4017) to pass, which is roadmap Phase 6; verification deferred to the last milestone
|
||||
- PPU 2a done (src/palette.rs + src/render.rs): 64-color 2C02 SYSTEM_PALETTE in index order, index_to_rgb with & 0x3F mask. Renderer trait (the only hardware trait) + PpmRenderer writing numbered frames to renders/ (frame_0000.ppm etc.) + pure ppm_bytes for testability. 4 unit tests pass. 2C02 chosen over composite palettes - we render raw PPU output
|
||||
- PPU 2b done (src/ppu.rs struct + registers + VRAM routing + src/bus.rs open-bus): Ppu has ctrl/mask/status/oam/oamaddr, shared write_latch (W bit for $2005/$2006), vram_addr (14-bit), data_buffer ($2007 read-buffer), vram[0x1000] (4KB for FourScreen), palette[32]. read/write handle $2000-$2007 with open-bus for write-only regs ($2000/$2001/$2003/$2005/$2006), $2002 read = (status & 0xE0) | (open_bus & 0x1F) + clears vblank + resets write latch, $2004 write increments oamaddr, $2007 palette reads bypass the read-buffer. VRAM routing: $0000-$1FFF = CHR via cart, $2000-$3EFF = nametables via cart.mirroring() (H/V/OneScreenLow/High/FourScreen), $3F00-$3FFF = palette with 10/14/18/1C mirror. Bus tracks open_bus (last byte on CPU data bus, updated on every read/write) and passes it into ppu.read; PPU regs routed via disjoint-field borrows; APU/expansion stubs now return open_bus instead of 0. cartridge.rs mirroring honors the four-screen header bit
|
||||
- PPU 2c implementation done (src/ppu.rs full background renderer): scanline/cycle timing (3 PPU dots per CPU cycle, 341 dots/scanline, 262 scanlines/frame, odd-frame 340-dot pre-render line), vblank+NMI at scanline 241 dot 0, clear at 261 dot 0, frame_complete at 261 end. Loopy scroll $2005/$2006 (t/x/w, shared write latch reset on $2002 read). Background fetch pipeline (4-fetch/8-dot: nametable at %8==0, attribute at 2, pattern lo at 4, pattern hi at 6, reload shift regs + increment coarse X at 7), two attribute shift registers (0xFF/0x00 per bit), horizontal copy at dot 255, vertical increment at 256, vertical copy at 280. Fine-X pre-shift at cycle 0 of visible scanlines. Transparent pixel uses palette[0]. Fixed mirroring swap (Horizontal=>a>>11, Vertical=>a>>10). Bus frame-driving methods (tick_ppu/frame_done/take_nmi/framebuffer/begin_frame). main.rs run_cart boots any ROM, renders frames to renders/ with PpmRenderer
|
||||
- CURRENT BUG: SMB renders ALL GREY. The framebuffer is all 0x00 (palette index 0 = dark grey 0x5D5D5D) - every frame renders identical grey boxes (180/3600 frames tested). Diagnosis: either the framebuffer is never written (rendering never enabled / render_bg never true) or every pixel computes transparent. SMB ROM confirmed to write $2000 5x, $2001 3x, poll $2002 6x, reset vector $8000 points at real SEI init code. NMI forwarding fix applied (take_nmi/set_nmi moved inside the frame loop) but did not change the grey output. Next step is machine-state diagnosis
|
||||
- Backup library mapper audit: mappers 0 (NROM) and 1 (MMC1) cover many games; still need mapper 2 (UNROM: Castlevania, Contra, Megaman 1), mapper 4 (MMC3: SMB2, SMB3, Lolo 2), mapper 7 (AOROM: Who Framed Roger Rabbit)
|
||||
- Finding: real commercial games rarely use illegal opcodes; none of the backup library needs them. Official-only CPU is sufficient for the goal of playing these games
|
||||
|
||||
@@ -56,13 +58,12 @@ Phases in order:
|
||||
1. NMI/IRQ servicing - DONE (see Done section). cpu_interrupts.nes verification deferred to the last milestone (needs APU frame-counter IRQ)
|
||||
2. PPU-1 rendering core - PARTIAL: 2a (palette/render) and 2b (registers/VRAM/open-bus) DONE (see Done section). Remaining: full background rendering in ONE merged step - timing + scroll + background pipeline together, no intermediate gating (we do not test until the full PPU exists). Acceptance: SMB title screen renders to PPM via main.rs run_cart. NEXT. Confirmed decisions: full dot-accurate scanline model, loopy v/t/x/w scroll system, Cartridge passed as parameter, open-bus tracking in the bus, hardware-accurate throughout (same philosophy as the CPU). Merged step:
|
||||
|
||||
2c. Full background renderer (merged timing + scroll + pipeline):
|
||||
- Ppu gains: scanline (0-261), cycle (0-340), framebuffer[256*240] palette indices, nmi_pending, frame_complete, loopy registers t (temp addr) + x (fine X) + w (write latch), background pipeline state (bg_pattern_lo/hi u16 shift regs, bg_attr u16, tile_latch, attr_latch)
|
||||
- Timing: tick(cart, cycles) advances cycle by cycles*3; cycle>=341 -> scanline++; odd-frame skip on pre-render line (261 is 340 dots on odd frames); scanline 241 dot 0 sets vblank + nmi_pending; scanline 261 dot 0 clears vblank; frame_complete at 261 end. Rendering on 0-239 and 261 (pre-render fetches, no output); 240 idle
|
||||
- Loopy scroll: $2005 first: t=(t&0x7FE0)|(val>>3), x=val&7, w=true; $2005 second: t=(t&0x0C1F)|((val&0xF8)<<2)|((val&7)<<12), w=false; $2006 first: t=(t&0x00FF)|((val&0x3F)<<8), w=true; $2006 second: t=(t&0x7F00)|val, v=t, w=false; $2002 read resets w
|
||||
- Background fetch pipeline (4 fetch / 8 dot cycle): dot%8==0 nametable byte -> tile_latch, ==2 attribute -> attr_latch, ==4 pattern lo from CHR, ==6 pattern hi, ==7 reload shift regs + increment coarse X (31->0 flips nametable X bit). Each dot outputs pixel combining bg_pattern_lo/hi top bit + attr bit for 2-bit palette select -> background palette -> framebuffer. Vertical increment at scanline end (fine Y 7->0, coarse Y 29->0 flips nametable Y bit)
|
||||
- main.rs: add use crate::render::{PpmRenderer, Renderer}, define frames (e.g. 3) in run_cart, cargo run -- <rom> boots from reset and renders frames to renders/. run_cart already calls the real methods (tick/frame_done/take_nmi/framebuffer/begin_frame)
|
||||
- Acceptance (single gate): cargo run -- roms/backup/SMB.nes -> renders/frame_0000.ppm recognizable SMB title screen
|
||||
2c. Full background renderer - IMPLEMENTED but BROKEN (grey screen, see Done section). Code complete and reviewed: timing, loopy scroll, background pipeline, fine-X, mirroring fix, transparent pixel fix, NMI forwarding fix all in. Acceptance NOT met yet: SMB renders uniform grey (framebuffer all 0x00). Diagnostics pending
|
||||
2d. CURRENT TASK - diagnose the grey screen. The framebuffer is all 0 (dark grey), meaning rendering is either never enabled or every pixel is transparent. Two-step plan:
|
||||
- Step 1 (quick inline probe): temporarily print per-frame state from run_cart - CPU PC (stuck loop?), PPU mask bit 3 (rendering enabled?), status, palette[0..4] (game wrote colors?), framebuffer non-zero pixel count (pipeline producing?). Needs small read accessors on Cpu (pc/a/x/y/sp/p) and Ppu (ctrl/mask/status/scanline/cycle/palette/framebuffer_nonzero) and NesBus (ram/ppu)
|
||||
- Step 2 (full dump module): new src/dump.rs writing machine state to text files, recreated fresh each run (clear + new files). Write debug_out/state.txt with CPU regs + PPU regs + palette + nametable + zero-page + framebuffer non-zero count, plus debug_out/pctrace.txt appending CPU PC each frame (identical lines = infinite loop). cargo run -- dbg <rom> mode clears debug_out/ and renders/, runs N frames, writes snapshot
|
||||
- Expected outcomes: PC trace identical every frame = stuck loop (look at what the CPU polls); mask never gets bit 3 + palette stays zero = PPU writes not landing (check Ppu::write masking / vram_write routing); regs set but framebuffer 0 = pipeline/render_bg bug
|
||||
- After diagnosis, fix and re-run until SMB title screen appears in renders/frame_XXXX.ppm
|
||||
3. PPU-2 sprites + scrolling + $4014 OAM DMA: makes SMB actually playable
|
||||
4. GUI (egui + winit, first external deps): display framebuffer, 60fps loop, keyboard -> controller ($4016/$4017). First "games running on screen" moment
|
||||
5. Mappers: 2 (UNROM), 7 (AOROM) simple; 4 (MMC3) complex - includes scanline IRQ counter required for SMB3 status bar. Verified by running the real backups
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
90D4 CYC:29781
|
||||
90DE CYC:59566
|
||||
90DE CYC:89351
|
||||
90DE CYC:119136
|
||||
90DE CYC:148921
|
||||
90DE CYC:178706
|
||||
90DE CYC:208491
|
||||
90DE CYC:238276
|
||||
90DE CYC:268061
|
||||
90DE CYC:297846
|
||||
90DE CYC:327631
|
||||
90DE CYC:357416
|
||||
90DE CYC:387201
|
||||
90DE CYC:416986
|
||||
90DE CYC:446771
|
||||
90DE CYC:476556
|
||||
90DE CYC:506341
|
||||
90DE CYC:536126
|
||||
90DE CYC:565911
|
||||
90DE CYC:595696
|
||||
90DE CYC:625481
|
||||
90D4 CYC:655262
|
||||
90DE CYC:685047
|
||||
90DE CYC:714832
|
||||
90DE CYC:744617
|
||||
90DE CYC:774402
|
||||
90DE CYC:804187
|
||||
90DE CYC:833972
|
||||
90DE CYC:863757
|
||||
90DE CYC:893542
|
||||
90DE CYC:923327
|
||||
90DE CYC:953112
|
||||
90DE CYC:982897
|
||||
90DE CYC:1012682
|
||||
90DE CYC:1042467
|
||||
90DE CYC:1072252
|
||||
90DE CYC:1102037
|
||||
90DE CYC:1131822
|
||||
90DE CYC:1161607
|
||||
90DE CYC:1191392
|
||||
90DE CYC:1221177
|
||||
90DE CYC:1250962
|
||||
90D4 CYC:1280743
|
||||
90DE CYC:1310528
|
||||
90DE CYC:1340313
|
||||
90DE CYC:1370098
|
||||
90DE CYC:1399883
|
||||
90DE CYC:1429668
|
||||
90DE CYC:1459453
|
||||
90DE CYC:1489238
|
||||
90DE CYC:1519023
|
||||
90DE CYC:1548808
|
||||
90DE CYC:1578593
|
||||
90DE CYC:1608378
|
||||
90DE CYC:1638163
|
||||
90DE CYC:1667948
|
||||
90DE CYC:1697733
|
||||
90DE CYC:1727518
|
||||
90DE CYC:1757303
|
||||
90DE CYC:1787088
|
||||
90DE CYC:1816873
|
||||
90DE CYC:1846658
|
||||
90DE CYC:1876443
|
||||
90D4 CYC:1906224
|
||||
90DE CYC:1936009
|
||||
90DE CYC:1965794
|
||||
90DE CYC:1995579
|
||||
90DE CYC:2025364
|
||||
90DE CYC:2055149
|
||||
90DE CYC:2084934
|
||||
90DE CYC:2114719
|
||||
90DE CYC:2144504
|
||||
90DE CYC:2174289
|
||||
90DE CYC:2204074
|
||||
90DE CYC:2233859
|
||||
90DE CYC:2263644
|
||||
90DE CYC:2293429
|
||||
90DE CYC:2323214
|
||||
90DE CYC:2352999
|
||||
90DE CYC:2382784
|
||||
90DE CYC:2412569
|
||||
90DE CYC:2442354
|
||||
90DE CYC:2472139
|
||||
90DE CYC:2501924
|
||||
90D4 CYC:2531705
|
||||
90DE CYC:2561490
|
||||
90DE CYC:2591275
|
||||
90DE CYC:2621060
|
||||
90DE CYC:2650845
|
||||
90DE CYC:2680630
|
||||
90DE CYC:2710415
|
||||
90DE CYC:2740200
|
||||
90DE CYC:2769985
|
||||
90DE CYC:2799770
|
||||
90DE CYC:2829555
|
||||
90DE CYC:2859340
|
||||
90DE CYC:2889125
|
||||
90DE CYC:2918910
|
||||
90DE CYC:2948695
|
||||
90DE CYC:2978480
|
||||
90DE CYC:3008265
|
||||
90DE CYC:3038050
|
||||
90DE CYC:3067835
|
||||
90DE CYC:3097620
|
||||
90DE CYC:3127405
|
||||
90D4 CYC:3157186
|
||||
90DE CYC:3186971
|
||||
90DE CYC:3216756
|
||||
90DE CYC:3246541
|
||||
90DE CYC:3276326
|
||||
90DE CYC:3306111
|
||||
90DE CYC:3335896
|
||||
90DE CYC:3365681
|
||||
90DE CYC:3395466
|
||||
90DE CYC:3425251
|
||||
90DE CYC:3455036
|
||||
90DE CYC:3484821
|
||||
90DE CYC:3514606
|
||||
90DE CYC:3544391
|
||||
90DE CYC:3574176
|
||||
90DE CYC:3603961
|
||||
90DE CYC:3633746
|
||||
90DE CYC:3663531
|
||||
90DE CYC:3693316
|
||||
90DE CYC:3723101
|
||||
90DE CYC:3752886
|
||||
90D4 CYC:3782667
|
||||
90DE CYC:3812452
|
||||
90DE CYC:3842237
|
||||
90DE CYC:3872022
|
||||
90DE CYC:3901807
|
||||
90DE CYC:3931592
|
||||
90DE CYC:3961377
|
||||
90DE CYC:3991162
|
||||
90DE CYC:4020947
|
||||
90DE CYC:4050732
|
||||
90DE CYC:4080517
|
||||
90DE CYC:4110302
|
||||
90DE CYC:4140087
|
||||
90DE CYC:4169872
|
||||
90DE CYC:4199657
|
||||
90DE CYC:4229442
|
||||
90DE CYC:4259227
|
||||
90DE CYC:4289012
|
||||
90DE CYC:4318797
|
||||
90DE CYC:4348582
|
||||
90DE CYC:4378367
|
||||
90D4 CYC:4408148
|
||||
90DE CYC:4437933
|
||||
90DE CYC:4467718
|
||||
90DE CYC:4497503
|
||||
90DE CYC:4527288
|
||||
90DE CYC:4557073
|
||||
90DE CYC:4586858
|
||||
90DE CYC:4616643
|
||||
90DE CYC:4646428
|
||||
90DE CYC:4676213
|
||||
90DE CYC:4705998
|
||||
90DE CYC:4735783
|
||||
90DE CYC:4765568
|
||||
90DE CYC:4795353
|
||||
90DE CYC:4825138
|
||||
90DE CYC:4854923
|
||||
90DE CYC:4884708
|
||||
90DE CYC:4914493
|
||||
90DE CYC:4944278
|
||||
90DE CYC:4974063
|
||||
90DE CYC:5003848
|
||||
90D4 CYC:5033629
|
||||
90DE CYC:5063414
|
||||
90DE CYC:5093199
|
||||
90DE CYC:5122984
|
||||
90DE CYC:5152769
|
||||
90DE CYC:5182554
|
||||
90DE CYC:5212339
|
||||
90DE CYC:5242124
|
||||
90DE CYC:5271909
|
||||
90DE CYC:5301694
|
||||
90DE CYC:5331479
|
||||
90DE CYC:5361264
|
||||
+4500
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,9 @@ impl NesBus {
|
||||
pub fn begin_frame(&mut self) {
|
||||
self.ppu.begin_frame();
|
||||
}
|
||||
|
||||
pub fn ppu(&self) -> &Ppu { &self.ppu }
|
||||
pub fn ram(&self) -> &[u8; 0x800] { &self.ram }
|
||||
}
|
||||
|
||||
impl Bus for NesBus {
|
||||
|
||||
@@ -96,6 +96,15 @@ impl Cpu {
|
||||
pub fn set_nmi(&mut self) { self.nmi_pending = true; }
|
||||
pub fn set_irq(&mut self) { self.irq_pending = true; }
|
||||
|
||||
// read-only accessor for the headless state dump
|
||||
pub fn pc(&self) -> u16 { self.pc }
|
||||
pub fn a(&self) -> u8 { self.a }
|
||||
pub fn x(&self) -> u8 { self.x }
|
||||
pub fn y(&self) -> u8 { self.y }
|
||||
pub fn sp(&self) -> u8 { self.sp }
|
||||
pub fn p(&self) -> u8 { self.p }
|
||||
pub fn cycles(&self) -> u64 { self.cycles }
|
||||
|
||||
// shared interrumpt function
|
||||
fn interrupt(&mut self, bus: &mut impl Bus, vector: u16) -> u8 {
|
||||
self.push(bus, (self.pc >> 8) as u8);
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
use crate::bus::NesBus;
|
||||
use crate::cpu::Cpu;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
||||
// Headless machine-state dump: run with `cargo run -- dbg <rom>`.
|
||||
// Writes debug_out/state.txt
|
||||
|
||||
pub struct Dumper {
|
||||
state: fs::File,
|
||||
pc_trace: fs::File,
|
||||
}
|
||||
|
||||
impl Dumper {
|
||||
pub fn new() -> Self {
|
||||
let _ = fs::remove_dir_all("debug_out");
|
||||
let _ = fs::remove_dir_all("renders");
|
||||
fs::create_dir_all("debug_out").expect("failed to create debug_out dir");
|
||||
Self {
|
||||
state: fs::File::create("debug_out/state.txt").expect("state.txt"),
|
||||
pc_trace: fs::File::create("debug_out/pctrace.txt").expect("pctrace.txt"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snapshot(&mut self, frame: u32, bus: &NesBus, cpu: &Cpu) {
|
||||
// --- CPU ---
|
||||
writeln!(self.state, "=== Frame {frame:04} ===").unwrap();
|
||||
writeln!(self.state,
|
||||
"CPU PC:{:04X} A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X} CYC:{}",
|
||||
cpu.pc(), cpu.a(), cpu.x(), cpu.y(), cpu.p(), cpu.sp(), cpu.cycles()
|
||||
).unwrap();
|
||||
|
||||
// --- PPU ---
|
||||
let ppu = bus.ppu();
|
||||
writeln!(self.state,
|
||||
"PPU CTRL:{:02X} MASK:{:02X} STATUS:{:02X} SCANLINE:{} CYCLE:{} v:{:04X} t:{:04X}",
|
||||
ppu.ctrl(), ppu.mask(), ppu.status(), ppu.scanline(), ppu.cycle(),
|
||||
ppu.vram_addr(), ppu.t()
|
||||
).unwrap();
|
||||
|
||||
// --- palette ---
|
||||
let pal = ppu.palette();
|
||||
let mut line = String::from("PAL ");
|
||||
for (i, &b) in pal.iter().enumerate() {
|
||||
line.push_str(&format!("{b:02X} "));
|
||||
if i % 16 == 15 {
|
||||
writeln!(self.state, "{line}").unwrap();
|
||||
line = String::from("PAL ");
|
||||
}
|
||||
}
|
||||
if !line.trim().is_empty() { writeln!(self.state, "{line}").unwrap(); }
|
||||
|
||||
// --- first nametable ---
|
||||
let vram = ppu.vram();
|
||||
let nt_nonzero = vram[0..0x400].iter().filter(|&&b| b != 0).count();
|
||||
let first: Vec<String> = vram[0..32].iter().map(|b| format!("{b:02X}")).collect();
|
||||
writeln!(self.state, "NT0 nonzero:{nt_nonzero} first: {}", first.join(" ")).unwrap();
|
||||
|
||||
// --- zero page ---
|
||||
let ram = bus.ram();
|
||||
let mut line = String::from("ZP ");
|
||||
for (i, &b) in ram[0..256].iter().enumerate() {
|
||||
line.push_str(&format!("{b:02X} "));
|
||||
if i % 16 == 15 {
|
||||
writeln!(self.state, "{line}").unwrap();
|
||||
line = String::from("ZP ");
|
||||
}
|
||||
}
|
||||
|
||||
// --- framebuffer ---
|
||||
writeln!(self.state, "FB nonzero:{} / 61440", ppu.framebuffer_nonzero()).unwrap();
|
||||
writeln!(self.state).unwrap();
|
||||
|
||||
// --- PC trace ---
|
||||
writeln!(self.pc_trace, "{:04X} CYC:{}", cpu.pc(), cpu.cycles()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-2
@@ -5,6 +5,7 @@ mod mapper;
|
||||
mod palette;
|
||||
mod render;
|
||||
mod ppu;
|
||||
mod dump;
|
||||
|
||||
use crate::bus::{Bus, NesBus};
|
||||
use crate::cartridge::Cartridge;
|
||||
@@ -17,6 +18,7 @@ fn main() {
|
||||
match args.len() {
|
||||
1 => run_nestest(),
|
||||
3 if args[1] == "blargg" => run_blargg(&args[2]),
|
||||
3 if args[1] == "dbg" => run_dbg(&args[2]),
|
||||
2 => run_cart(&args[1]),
|
||||
_ => eprintln!("usage: rnes [<rom> | blargg <rom>]"),
|
||||
}
|
||||
@@ -28,14 +30,14 @@ fn run_cart(path: &str) {
|
||||
let mut cpu = Cpu::new();
|
||||
cpu.reset(&mut bus);
|
||||
let mut renderer = PpmRenderer::new();
|
||||
let frames: u32 = 60;
|
||||
let frames: u32 = 180;
|
||||
|
||||
for _ in 0..frames {
|
||||
while !bus.frame_done() {
|
||||
let cycles = cpu.step(&mut bus);
|
||||
bus.tick_ppu(cycles as u64);
|
||||
if bus.take_nmi() { cpu.set_nmi(); } // NMI fires when vblank hits, mid-frame
|
||||
}
|
||||
if bus.take_nmi() { cpu.set_nmi(); }
|
||||
renderer.present(bus.framebuffer(), 256, 240);
|
||||
bus.begin_frame();
|
||||
}
|
||||
@@ -70,3 +72,23 @@ fn run_nestest() {
|
||||
cpu.step(&mut bus);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_dbg(path: &str) {
|
||||
let cart = Cartridge::from_file(path).unwrap();
|
||||
let mut bus = NesBus::new(cart);
|
||||
let mut cpu = Cpu::new();
|
||||
cpu.reset(&mut bus);
|
||||
let mut dumper = dump::Dumper::new();
|
||||
let frames: u32 = 180;
|
||||
|
||||
for f in 0..frames {
|
||||
while !bus.frame_done() {
|
||||
let cycles = cpu.step(&mut bus);
|
||||
bus.tick_ppu(cycles as u64);
|
||||
if bus.take_nmi() { cpu.set_nmi(); }
|
||||
}
|
||||
dumper.snapshot(f, &bus, &cpu);
|
||||
bus.begin_frame();
|
||||
}
|
||||
println!("wrote debug_out/ (state.txt + pctrace.txt), {frames} frames");
|
||||
}
|
||||
+14
@@ -325,6 +325,20 @@ impl Ppu {
|
||||
pub fn framebuffer(&self) -> &[u8] { &self.framebuffer }
|
||||
pub fn begin_frame(&mut self) { self.frame_complete = false; self.scanline = 0; self.cycle = 0; }
|
||||
|
||||
// read-only accessors for the headless state dump
|
||||
pub fn ctrl(&self) -> u8 { self.ctrl }
|
||||
pub fn mask(&self) -> u8 { self.mask }
|
||||
pub fn status(&self) -> u8 { self.status }
|
||||
pub fn scanline(&self) -> u32 { self.scanline }
|
||||
pub fn cycle(&self) -> u32 { self.cycle }
|
||||
pub fn vram_addr(&self) -> u16 { self.vram_addr }
|
||||
pub fn t(&self) -> u16 { self.t }
|
||||
pub fn palette(&self) -> &[u8; 32] { &self.palette }
|
||||
pub fn vram(&self) -> &[u8; 0x1000] { &self.vram }
|
||||
pub fn framebuffer_nonzero(&self) -> usize {
|
||||
self.framebuffer.iter().filter(|&&b| b != 0).count()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user