Partial audio implementation
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 10s
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 10s
This commit is contained in:
127
src/ppu.rs
127
src/ppu.rs
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user