Partial audio implementation
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 10s

This commit is contained in:
2026-03-14 21:19:16 -05:00
parent 3372559c19
commit b9a30c286a
12 changed files with 1257 additions and 171 deletions

View File

@@ -128,7 +128,8 @@ pub struct OAM {
oam_read_buffer: u8,
edit_ver: usize,
sprite_output_units: Vec<SpriteOutputUnit>,
overflow: bool,
large_sprites: bool,
pub overflow: bool,
sprite_offset_0x1000: bool,
}
@@ -145,6 +146,7 @@ impl OAM {
oam_read_buffer: 0,
overflow: false,
sprite_offset_0x1000: false,
large_sprites: false,
}
}
@@ -272,15 +274,15 @@ impl OAM {
// println!("Shifting: 0b{:08b} by {}", s.low, bit_pos);
let lo = (s.low >> bit_pos) & 1;
let idx = (hi << 1) | lo;
Some((
if idx != 0 {
idx + s.attrs.palette() * 4 + 0x10
} else {
0
},
!s.attrs.priority(),
i == 0,
))
if idx != 0 {
Some((
idx + s.attrs.palette() * 4 + 0x10,
!s.attrs.priority(),
i == 0,
))
} else {
None
}
} else {
None
}
@@ -292,8 +294,10 @@ impl OAM {
#[derive(Debug, Clone)]
pub struct Background {
/// Current vram address, 15 bits
/// yyy NN YYYYY XXXXX (0yyy NNYY YYYX XXXX)
pub v: u16,
/// Temp vram address, 15 bits
/// yyy NN YYYYY XXXXX
pub t: u16,
/// Fine X control, 3 bits
pub x: u8,
@@ -301,18 +305,20 @@ pub struct Background {
/// When false, writes to x
pub w: bool,
copy_v: u8,
/// When true, v is incremented by 32 after each read
pub vram_column: bool,
pub second_pattern: bool,
pub cur_nametable: u8,
pub cur_attr: u8,
pub next_attr: u8,
pub next_attr_2: u8,
pub cur_high: u8,
pub cur_low: u8,
pub cur_shift_high: u32,
pub cur_shift_low: u32,
pub cur_attr_shift_high: u32,
pub cur_attr_shift_low: u32,
}
#[derive(Debug, Clone, Copy)]
@@ -681,11 +687,11 @@ pub struct PPU {
pub mask: Mask,
pub vblank: bool,
sprite_zero_hit: bool,
pub sprite_zero_hit: bool,
pub palette: Palette,
pub background: Background,
oam: OAM,
pub oam: OAM,
pub render_buffer: RenderBuffer<256, 240>,
pub dbg_int: bool,
pub cycle: usize,
@@ -740,8 +746,6 @@ impl PPU {
sprite_zero_hit: false,
frame_count: 0,
nmi_enabled: false,
// nmi_waiting: false,
// TODO: Is even in the right initial state?
even: false,
scanline: 0,
pixel: 25,
@@ -751,16 +755,17 @@ impl PPU {
t: 0,
x: 0,
w: false,
copy_v: 0,
vram_column: false,
second_pattern: false,
cur_high: 0,
cur_low: 0,
cur_shift_high: 0,
cur_shift_low: 0,
cur_attr_shift_high: 0,
cur_attr_shift_low: 0,
cur_nametable: 0,
cur_attr: 0,
next_attr: 0,
next_attr_2: 0,
},
oam: OAM::new(),
vram_buffer: 0,
@@ -791,9 +796,6 @@ impl PPU {
5 => panic!("ppuscroll is write-only"),
6 => panic!("ppuaddr is write-only"),
7 => {
// TODO: read buffer only applies to ppu data, not palette ram...
// println!("Updating v for ppudata read");
// self.vram_buffer =
let val = match mem.read(self.background.v) {
Value::Value(v) => {
let val = self.vram_buffer;
@@ -805,10 +807,6 @@ impl PPU {
offset,
} => self.palette.ram[offset as usize],
};
// .reg_map(|a, off| match a {
// PPUMMRegisters::Palette => self.palette.ram[off as usize],
// });
// if self.background
self.increment_v();
val
}
@@ -819,13 +817,16 @@ impl PPU {
pub fn write_reg(&mut self, mem: &mut PpuMem, offset: u16, mut val: u8) {
match offset {
0x00 => {
self.nmi_enabled = val & 0b1000_0000 != 0;
self.background.t =
(self.background.t & !0b0001_1000_0000_0000) | (((val & 0b11) as u16) << 10);
(self.background.t & !0b0000_1100_0000_0000) | (((val & 0b11) as u16) << 10);
self.background.vram_column = val & 0b0000_0100 != 0;
self.background.second_pattern = val & 0b0001_0000 != 0;
self.oam.sprite_offset_0x1000 = val & 0b0000_1000 != 0;
// TODO: other control fields
self.background.second_pattern = val & 0b0001_0000 != 0;
self.oam.large_sprites = val & 0b0010_0000 != 0;
if val & 0b0100_0000 != 0 {
println!("WARNING: Bit 6 set in PPUCTRL - may cause damage on physical hardware");
}
self.nmi_enabled = val & 0b1000_0000 != 0;
}
0x01 => {
// self.dbg_int = true;
@@ -841,7 +842,6 @@ impl PPU {
}
0x02 => {
todo!("Unable to write to PPU status")
// TODO: ppu status
}
0x03 => self.oam.addr = val,
0x04 => {
@@ -868,19 +868,16 @@ impl PPU {
}
}
0x06 => {
// TODO: this actually sets T, which is copied to v later (~ a pixel later?)
if self.background.w {
self.background.v =
u16::from_le_bytes([val, self.background.v.to_le_bytes()[1]]);
self.background.t =
u16::from_le_bytes([val, self.background.t.to_le_bytes()[1]]);
self.background.w = false;
self.background.copy_v = 2; // Set t to be copied to v in a pixel or so
} else {
self.background.v =
u16::from_le_bytes([self.background.v.to_le_bytes()[0], val & 0b0011_1111]);
self.background.t =
u16::from_le_bytes([self.background.t.to_le_bytes()[0], val & 0b0011_1111]);
self.background.w = true;
}
// println!("Updating v for ppuaddr write: to {:04X}", self.background.v);
// self.dbg_int = true;
// todo!("PPUADDR write")
}
0x07 => {
// println!("Writing: {:02X}, @{:04X}", val, self.background.v);
@@ -897,7 +894,6 @@ impl PPU {
}
});
self.increment_v();
// self.background.v += 1; // TODO: implement inc behavior
}
_ => panic!("No register at {:02X}", offset),
}
@@ -910,18 +906,17 @@ impl PPU {
} else {
self.background.v += 1;
}
// self.background.v = self
// .background
// .v
// .wrapping_add(if self.background.vram_column { 32 } else { 1 });
}
// pub fn write_oamdma(&mut self, val: u8) {
// // TODO: OAM high addr
// }
pub fn run_one_clock_cycle(&mut self, mem: &mut PpuMem<'_>) -> bool {
self.cycle += 1;
self.pixel += 1;
if self.background.copy_v > 0 {
self.background.copy_v -= 1;
if self.background.copy_v == 0 {
self.background.v = self.background.t;
}
}
if self.scanline == 261
&& (self.pixel == 341 || (self.pixel == 340 && self.even && self.rendering_enabled()))
{
@@ -944,16 +939,13 @@ impl PPU {
self.background.v = (self.background.v & 0b0000_0100_0001_1111)
| (self.background.t & 0b0111_1011_1110_0000);
}
if self.pixel > 280 && self.pixel < 320 {
self.background.cur_shift_high <<= 1;
self.background.cur_shift_low <<= 1;
}
if self.scanline != 261 {
self.oam.ppu_cycle(self.pixel, self.scanline, mem);
}
// TODO
if self.pixel == 0 {
if self.scanline < 9 {
if self.scanline == 1 {
// let h_scroll_offset = self.background.x as usize + ((self.background.t as usize & 0b11) << 3);
// dbg!(h_scroll_offset);
// dbg!((self.scanline, &self.oam.sprite_output_units[0]));
// dbg!(&self.oam.secondary);
}
@@ -963,17 +955,16 @@ impl PPU {
// self.dbg_int = true;
// const POS: u32 = 1 << 15;
let bit_pos = 15 - self.background.x;
// let pos: u32 = 1 << (15 + self.background.x*0); // TODO: handle this correctly
// Determine background color
let a = (self.background.cur_shift_high >> bit_pos) & 1;
let b = (self.background.cur_shift_low >> bit_pos) & 1;
let val = (a << 1) | b;
debug_assert!(val < 4);
let h_off = ((self.pixel - 1) / 16) % 2;
let v_off = (self.scanline / 16) % 2;
let off = v_off * 4 + h_off * 2;
let palette = (self.background.cur_attr >> off) & 0x3;
let a = (self.background.cur_attr_shift_high >> bit_pos) & 1;
let b = (self.background.cur_attr_shift_low >> bit_pos) & 1;
let palette = ((a << 1) | b) as u8;
debug_assert!(palette < 4);
let color = val as u8 + if val != 0 { palette * 4 } else { 0 };
if self.scanline < 240 && self.pixel < 257 {
@@ -995,12 +986,14 @@ impl PPU {
self.render_buffer.write(
self.scanline,
self.pixel - 1,
self.palette.color(color), // self.palette.colors[val as usize],
); // TODO: this should come from shift registers
self.palette.color(color),
);
}
if self.pixel < 337 {
self.background.cur_shift_high <<= 1;
self.background.cur_shift_low <<= 1;
self.background.cur_attr_shift_high <<= 1;
self.background.cur_attr_shift_low <<= 1;
}
if self.scanline < 240 || self.scanline == 261 {
@@ -1021,8 +1014,8 @@ impl PPU {
| ((self.background.v >> 2) & 0x07);
// println!("Cur: {:04X}, comp: {:04X}", addr, addr_2);
// assert_eq!(addr, addr_2);
let val = mem.read(addr).reg_map(|_, _| 0); // TODO: handle reg reads
self.background.next_attr_2 = val;
let val = mem.read(addr).reg_map(|_, offset| self.palette.ram(offset as u8));
self.background.next_attr = val;
} else if self.pixel % 8 == 6 {
// BG pattern low
let addr = self.background.cur_nametable as u16 * 16
@@ -1049,8 +1042,14 @@ impl PPU {
self.background.cur_high = val;
self.background.cur_shift_low |= self.background.cur_low as u32;
self.background.cur_shift_high |= self.background.cur_high as u32;
self.background.cur_attr = self.background.next_attr;
self.background.next_attr = self.background.next_attr_2;
let h_off = (self.background.v >> 1) % 2;
let v_off = (self.background.v >> 6) % 2;
let off = h_off * 2 + v_off * 4;
let palette = (self.background.next_attr >> off) & 0b11;
self.background.cur_attr_shift_low |=
if palette & 0b01 == 0 { 0 } else { 0xFF };
self.background.cur_attr_shift_high |=
if palette & 0b10 == 0 { 0 } else { 0xFF };
// Inc horizontal
if self.background.v & 0x1F == 31 {
self.background.v = (self.background.v & !0x1F) ^ 0x400;
@@ -1080,8 +1079,6 @@ impl PPU {
}
}
}
} else {
// TODO: Sprite fetches
}
}
}