Working Sprite implementation
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 9s
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 9s
This commit is contained in:
@@ -35,7 +35,10 @@ use tracing_subscriber::EnvFilter;
|
|||||||
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "int_nmi_exit_timing.nes");
|
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "int_nmi_exit_timing.nes");
|
||||||
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "render-updating.nes");
|
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "render-updating.nes");
|
||||||
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "ppu_palette_shared.nes");
|
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "ppu_palette_shared.nes");
|
||||||
const ROM_FILE: &str = "./Super Mario Bros. (World).nes";
|
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "input_test.nes");
|
||||||
|
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "scrolling.nes");
|
||||||
|
const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "sprites.nes");
|
||||||
|
// const ROM_FILE: &str = "./Super Mario Bros. (World).nes";
|
||||||
// const ROM_FILE: &str = "./cpu_timing_test.nes";
|
// const ROM_FILE: &str = "./cpu_timing_test.nes";
|
||||||
// const ROM_FILE: &str = "../nes-test-roms/instr_test-v5/official_only.nes";
|
// const ROM_FILE: &str = "../nes-test-roms/instr_test-v5/official_only.nes";
|
||||||
|
|
||||||
@@ -178,7 +181,7 @@ impl Emulator {
|
|||||||
nes,
|
nes,
|
||||||
windows: HashMap::from_iter([
|
windows: HashMap::from_iter([
|
||||||
(win, WindowType::Main),
|
(win, WindowType::Main),
|
||||||
(win_2, WindowType::Memory(MemoryTy::OAM, HexView {}))
|
(win_2, WindowType::Debugger)
|
||||||
]),
|
]),
|
||||||
debugger: DebuggerState::new(),
|
debugger: DebuggerState::new(),
|
||||||
main_win_size: Size::new(0., 0.),
|
main_win_size: Size::new(0., 0.),
|
||||||
|
|||||||
268
src/ppu.rs
268
src/ppu.rs
@@ -88,11 +88,205 @@ pub enum PPUMMRegisters {
|
|||||||
Palette,
|
Palette,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitfield::bitfield! {
|
||||||
|
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SpriteAttrs(u8);
|
||||||
|
impl Debug;
|
||||||
|
vflip, set_vflip: 7;
|
||||||
|
hflip, set_hflip: 6;
|
||||||
|
priority, set_priority: 5;
|
||||||
|
palette, set_palette: 1, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
struct SpriteOutputUnit {
|
||||||
|
high: u8,
|
||||||
|
low: u8,
|
||||||
|
x_pos: u8,
|
||||||
|
y_pos: u8,
|
||||||
|
tile: u8,
|
||||||
|
attrs: SpriteAttrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum OamState {
|
||||||
|
ReadY,
|
||||||
|
ReadTile,
|
||||||
|
ReadAttrs,
|
||||||
|
ReadX,
|
||||||
|
OverflowScan,
|
||||||
|
Wait,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OAM {
|
pub struct OAM {
|
||||||
mem: Vec<u8>,
|
mem: Vec<u8>,
|
||||||
|
secondary: Vec<u8>,
|
||||||
addr: u8,
|
addr: u8,
|
||||||
|
count: u8,
|
||||||
|
state: OamState,
|
||||||
|
oam_read_buffer: u8,
|
||||||
edit_ver: usize,
|
edit_ver: usize,
|
||||||
|
sprite_output_units: Vec<SpriteOutputUnit>,
|
||||||
|
overflow: bool,
|
||||||
|
sprite_offset_0x1000: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OAM {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
mem: vec![0u8; 256],
|
||||||
|
addr: 0,
|
||||||
|
count: 0,
|
||||||
|
edit_ver: 0,
|
||||||
|
secondary: vec![0xFF; 32],
|
||||||
|
sprite_output_units: vec![SpriteOutputUnit::default(); 8],
|
||||||
|
state: OamState::ReadY,
|
||||||
|
oam_read_buffer: 0,
|
||||||
|
overflow: false,
|
||||||
|
sprite_offset_0x1000: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ppu_cycle(&mut self, pixel: usize, line: usize, mem: &mut PpuMem<'_>) {
|
||||||
|
if pixel < 64 {
|
||||||
|
} else if pixel == 64 {
|
||||||
|
self.secondary.fill(0xFF);
|
||||||
|
self.state = OamState::ReadY;
|
||||||
|
self.addr = 0;
|
||||||
|
self.count = 0;
|
||||||
|
} else if pixel <= 256 {
|
||||||
|
// Fetch/evalute sprites for next line
|
||||||
|
if pixel % 2 == 1 && !matches!(self.state, OamState::Wait) {
|
||||||
|
self.oam_read_buffer = self.mem[self.addr as usize];
|
||||||
|
if self.addr == 255 {
|
||||||
|
self.addr = 0;
|
||||||
|
} else {
|
||||||
|
self.addr += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.state {
|
||||||
|
OamState::ReadY => {
|
||||||
|
let l = self.oam_read_buffer as usize;
|
||||||
|
if self.count < 8 {
|
||||||
|
if l <= line && line < l + 8 {
|
||||||
|
self.secondary[self.count as usize * 4] = self.oam_read_buffer;
|
||||||
|
self.state = OamState::ReadTile;
|
||||||
|
} else {
|
||||||
|
if self.addr < 0xFD {
|
||||||
|
self.addr += 3;
|
||||||
|
} else {
|
||||||
|
self.state = OamState::Wait; // Should be Overflow scan...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.state = OamState::Wait; // Should be Overflow scan...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OamState::ReadTile => {
|
||||||
|
self.secondary[self.count as usize * 4 + 1] = self.oam_read_buffer;
|
||||||
|
self.state = OamState::ReadAttrs;
|
||||||
|
}
|
||||||
|
OamState::ReadAttrs => {
|
||||||
|
self.secondary[self.count as usize * 4 + 2] = self.oam_read_buffer;
|
||||||
|
self.state = OamState::ReadX;
|
||||||
|
}
|
||||||
|
OamState::ReadX => {
|
||||||
|
self.secondary[self.count as usize * 4 + 3] = self.oam_read_buffer;
|
||||||
|
self.state = OamState::ReadY;
|
||||||
|
self.count += 1;
|
||||||
|
if self.count == 8 {
|
||||||
|
self.state = OamState::Wait; // Should be Overflow scan...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OamState::OverflowScan => todo!(),
|
||||||
|
OamState::Wait => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if pixel <= 320 {
|
||||||
|
if pixel == 257 {
|
||||||
|
// Reset output units
|
||||||
|
self.sprite_output_units.fill(SpriteOutputUnit::default());
|
||||||
|
}
|
||||||
|
let run = pixel - 257;
|
||||||
|
if run / 8 < self.count as usize {
|
||||||
|
if run % 8 == 0 {
|
||||||
|
self.sprite_output_units[run / 8].y_pos = self.secondary[(run / 8) * 4];
|
||||||
|
} else if run % 8 == 1 {
|
||||||
|
self.sprite_output_units[run / 8].tile = self.secondary[(run / 8) * 4 + 1];
|
||||||
|
} else if run % 8 == 2 {
|
||||||
|
self.sprite_output_units[run / 8].attrs.0 = self.secondary[(run / 8) * 4 + 2];
|
||||||
|
} else if run % 8 == 3 {
|
||||||
|
self.sprite_output_units[run / 8].x_pos = self.secondary[(run / 8) * 4 + 3];
|
||||||
|
} else if run % 8 == 4 {
|
||||||
|
} else if run % 8 == 5 {
|
||||||
|
let off = line - self.sprite_output_units[run / 8].y_pos as usize;
|
||||||
|
let off = if self.sprite_output_units[run / 8].attrs.vflip() {
|
||||||
|
7 - off
|
||||||
|
} else {
|
||||||
|
off
|
||||||
|
};
|
||||||
|
let addr = if self.sprite_offset_0x1000 {
|
||||||
|
0x1000
|
||||||
|
} else {
|
||||||
|
0x0000
|
||||||
|
} + 16 * self.sprite_output_units[run / 8].tile as u16
|
||||||
|
+ off as u16;
|
||||||
|
self.sprite_output_units[run / 8].low = mem.read(addr).reg_map(|_, _| todo!());
|
||||||
|
} else if run % 8 == 6 {
|
||||||
|
} else if run % 8 == 7 {
|
||||||
|
let off = line - self.sprite_output_units[run / 8].y_pos as usize;
|
||||||
|
let off = if self.sprite_output_units[run / 8].attrs.vflip() {
|
||||||
|
7 - off
|
||||||
|
} else {
|
||||||
|
off
|
||||||
|
};
|
||||||
|
let addr = if self.sprite_offset_0x1000 {
|
||||||
|
0x1000
|
||||||
|
} else {
|
||||||
|
0x0000
|
||||||
|
} + 16 * self.sprite_output_units[run / 8].tile as u16
|
||||||
|
+ off as u16
|
||||||
|
+ 8;
|
||||||
|
self.sprite_output_units[run / 8].high = mem.read(addr).reg_map(|_, _| todo!());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns Some((palette index, above background))
|
||||||
|
fn pixel(&mut self, pixel: usize, _line: usize) -> Option<(u8, bool, bool)> {
|
||||||
|
self.sprite_output_units
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, s)| {
|
||||||
|
if pixel >= s.x_pos as usize && pixel < s.x_pos as usize + 8 && s.x_pos < 0xFF {
|
||||||
|
let bit_pos = pixel - s.x_pos as usize;
|
||||||
|
let bit_pos = if s.attrs.hflip() {
|
||||||
|
bit_pos
|
||||||
|
} else {
|
||||||
|
7 - bit_pos
|
||||||
|
};
|
||||||
|
// println!("Shifting: 0b{:08b} by {}", s.high, 8 - bit_pos);
|
||||||
|
let hi = (s.high >> bit_pos) & 1;
|
||||||
|
// 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,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -463,9 +657,9 @@ pub struct Palette {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Palette {
|
impl Palette {
|
||||||
pub fn color(&self, idx: u8, palette: u8) -> Color {
|
pub fn color(&self, idx: u8) -> Color {
|
||||||
debug_assert!(idx < 0x20, "Palette index out of range");
|
debug_assert!(idx < 0x20, "Palette index out of range");
|
||||||
self.colors[(self.ram[idx as usize + palette as usize * 4] & 0x3F) as usize]
|
self.colors[(self.ram[idx as usize] & 0x3F) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ram(&self, offset: u8) -> u8 {
|
pub fn ram(&self, offset: u8) -> u8 {
|
||||||
@@ -487,6 +681,7 @@ pub struct PPU {
|
|||||||
|
|
||||||
pub mask: Mask,
|
pub mask: Mask,
|
||||||
pub vblank: bool,
|
pub vblank: bool,
|
||||||
|
sprite_zero_hit: bool,
|
||||||
|
|
||||||
pub palette: Palette,
|
pub palette: Palette,
|
||||||
pub background: Background,
|
pub background: Background,
|
||||||
@@ -542,6 +737,7 @@ impl PPU {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
vblank: false,
|
vblank: false,
|
||||||
|
sprite_zero_hit: false,
|
||||||
frame_count: 0,
|
frame_count: 0,
|
||||||
nmi_enabled: false,
|
nmi_enabled: false,
|
||||||
// nmi_waiting: false,
|
// nmi_waiting: false,
|
||||||
@@ -566,11 +762,7 @@ impl PPU {
|
|||||||
next_attr: 0,
|
next_attr: 0,
|
||||||
next_attr_2: 0,
|
next_attr_2: 0,
|
||||||
},
|
},
|
||||||
oam: OAM {
|
oam: OAM::new(),
|
||||||
mem: vec![0u8; 256],
|
|
||||||
addr: 0,
|
|
||||||
edit_ver: 0,
|
|
||||||
},
|
|
||||||
vram_buffer: 0,
|
vram_buffer: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -587,7 +779,9 @@ impl PPU {
|
|||||||
0 => panic!("ppuctrl is write-only"),
|
0 => panic!("ppuctrl is write-only"),
|
||||||
1 => panic!("ppumask is write-only"),
|
1 => panic!("ppumask is write-only"),
|
||||||
2 => {
|
2 => {
|
||||||
let tmp = if self.vblank { 0b1000_0000 } else { 0 };
|
let tmp = if self.vblank { 0b1000_0000 } else { 0 }
|
||||||
|
| if self.sprite_zero_hit { 0b0100_0000 } else { 0 }
|
||||||
|
| if self.oam.overflow { 0b0010_0000 } else { 0 };
|
||||||
self.vblank = false;
|
self.vblank = false;
|
||||||
self.background.w = false;
|
self.background.w = false;
|
||||||
tmp
|
tmp
|
||||||
@@ -605,10 +799,11 @@ impl PPU {
|
|||||||
let val = self.vram_buffer;
|
let val = self.vram_buffer;
|
||||||
self.vram_buffer = v;
|
self.vram_buffer = v;
|
||||||
val
|
val
|
||||||
},
|
}
|
||||||
Value::Register { reg: PPUMMRegisters::Palette, offset } => {
|
Value::Register {
|
||||||
self.palette.ram[offset as usize]
|
reg: PPUMMRegisters::Palette,
|
||||||
},
|
offset,
|
||||||
|
} => self.palette.ram[offset as usize],
|
||||||
};
|
};
|
||||||
// .reg_map(|a, off| match a {
|
// .reg_map(|a, off| match a {
|
||||||
// PPUMMRegisters::Palette => self.palette.ram[off as usize],
|
// PPUMMRegisters::Palette => self.palette.ram[off as usize],
|
||||||
@@ -626,9 +821,10 @@ impl PPU {
|
|||||||
0x00 => {
|
0x00 => {
|
||||||
self.nmi_enabled = val & 0b1000_0000 != 0;
|
self.nmi_enabled = val & 0b1000_0000 != 0;
|
||||||
self.background.t =
|
self.background.t =
|
||||||
(self.background.t & 0b0001_1000_0000_0000) | (((val & 0b11) as u16) << 10);
|
(self.background.t & !0b0001_1000_0000_0000) | (((val & 0b11) as u16) << 10);
|
||||||
self.background.vram_column = val & 0b0000_0100 != 0;
|
self.background.vram_column = val & 0b0000_0100 != 0;
|
||||||
self.background.second_pattern = val & 0b0001_0000 != 0;
|
self.background.second_pattern = val & 0b0001_0000 != 0;
|
||||||
|
self.oam.sprite_offset_0x1000 = val & 0b0000_1000 != 0;
|
||||||
// TODO: other control fields
|
// TODO: other control fields
|
||||||
}
|
}
|
||||||
0x01 => {
|
0x01 => {
|
||||||
@@ -752,31 +948,54 @@ impl PPU {
|
|||||||
self.background.cur_shift_high <<= 1;
|
self.background.cur_shift_high <<= 1;
|
||||||
self.background.cur_shift_low <<= 1;
|
self.background.cur_shift_low <<= 1;
|
||||||
}
|
}
|
||||||
|
if self.scanline != 261 {
|
||||||
|
self.oam.ppu_cycle(self.pixel, self.scanline, mem);
|
||||||
|
}
|
||||||
// TODO
|
// TODO
|
||||||
if self.pixel == 0 {
|
if self.pixel == 0 {
|
||||||
|
if self.scanline < 9 {
|
||||||
|
// dbg!((self.scanline, &self.oam.sprite_output_units[0]));
|
||||||
|
// dbg!(&self.oam.secondary);
|
||||||
|
}
|
||||||
// self.dbg_int = true;
|
// self.dbg_int = true;
|
||||||
// idle cycle
|
// idle cycle
|
||||||
} else if self.pixel < 257 || self.pixel > 320 {
|
} else if self.pixel < 257 || self.pixel > 320 {
|
||||||
// self.dbg_int = true;
|
// self.dbg_int = true;
|
||||||
const POS: u32 = 1 << 15;
|
// 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
|
// Determine background color
|
||||||
let a = self.background.cur_shift_high & POS;
|
let a = (self.background.cur_shift_high >> bit_pos) & 1;
|
||||||
let b = self.background.cur_shift_low & POS;
|
let b = (self.background.cur_shift_low >> bit_pos) & 1;
|
||||||
let val = (a >> 14) | (b >> 15);
|
let val = (a << 1) | b;
|
||||||
debug_assert!(val < 4);
|
debug_assert!(val < 4);
|
||||||
|
|
||||||
let h_off = ((self.pixel - 1) / 16) % 2;
|
let h_off = ((self.pixel - 1) / 16) % 2;
|
||||||
let v_off = (self.scanline / 16) % 2;
|
let v_off = (self.scanline / 16) % 2;
|
||||||
let off = v_off * 4 + h_off * 2;
|
let off = v_off * 4 + h_off * 2;
|
||||||
let palette = (self.background.cur_attr >> off) & 0x3;
|
let palette = (self.background.cur_attr >> off) & 0x3;
|
||||||
|
let color = val as u8 + if val != 0 { palette * 4 } else { 0 };
|
||||||
|
|
||||||
if self.scanline < 240 && self.pixel < 257 {
|
if self.scanline < 240 && self.pixel < 257 {
|
||||||
|
let color = if let Some((sp_color, above, is_sprite_zero)) =
|
||||||
|
self.oam.pixel(self.pixel, self.scanline)
|
||||||
|
{
|
||||||
|
if is_sprite_zero && sp_color != 0 && color != 0 {
|
||||||
|
self.sprite_zero_hit = true;
|
||||||
|
}
|
||||||
|
if sp_color == 0 || (color != 0 && !above) {
|
||||||
|
color
|
||||||
|
} else {
|
||||||
|
sp_color
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
color
|
||||||
|
};
|
||||||
// Write to screen
|
// Write to screen
|
||||||
self.render_buffer.write(
|
self.render_buffer.write(
|
||||||
self.scanline,
|
self.scanline,
|
||||||
self.pixel - 1,
|
self.pixel - 1,
|
||||||
self.palette
|
self.palette.color(color), // self.palette.colors[val as usize],
|
||||||
.color(val as u8, if val != 0 { palette } else { 0 }), // self.palette.colors[val as usize],
|
|
||||||
); // TODO: this should come from shift registers
|
); // TODO: this should come from shift registers
|
||||||
}
|
}
|
||||||
if self.pixel < 337 {
|
if self.pixel < 337 {
|
||||||
@@ -868,7 +1087,8 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
if self.scanline == 261 && self.pixel == 1 {
|
if self.scanline == 261 && self.pixel == 1 {
|
||||||
self.vblank = false;
|
self.vblank = false;
|
||||||
// TODO: clear sprite 0 & sprite overflow
|
self.sprite_zero_hit = false;
|
||||||
|
self.oam.overflow = false;
|
||||||
}
|
}
|
||||||
if self.scanline == 241 && self.pixel == 1 {
|
if self.scanline == 241 && self.pixel == 1 {
|
||||||
self.vblank = true;
|
self.vblank = true;
|
||||||
@@ -930,10 +1150,10 @@ impl PPU {
|
|||||||
),
|
),
|
||||||
Size::new(1., 1.),
|
Size::new(1., 1.),
|
||||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||||
(false, false) => self.palette.color(0, 0),
|
(false, false) => self.palette.color(0),
|
||||||
(true, false) => self.palette.color(1, palette),
|
(true, false) => self.palette.color(1 + 4 * palette),
|
||||||
(false, true) => self.palette.color(2, palette),
|
(false, true) => self.palette.color(2 + 4 * palette),
|
||||||
(true, true) => self.palette.color(3, palette),
|
(true, true) => self.palette.color(3 + 4 * palette),
|
||||||
// (false, false) => Color { r: 0, g: 0, b: 0 },
|
// (false, false) => Color { r: 0, g: 0, b: 0 },
|
||||||
// (true, false) => Color {
|
// (true, false) => Color {
|
||||||
// r: 64,
|
// r: 64,
|
||||||
|
|||||||
335
src/test_roms/input_test.s
Normal file
335
src/test_roms/input_test.s
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
|
||||||
|
; Verifies that reset doesn't alter any RAM.
|
||||||
|
|
||||||
|
.include "testing.s"
|
||||||
|
; patterns_bin "pat.bin"
|
||||||
|
.macro chr b,s
|
||||||
|
.repeat s
|
||||||
|
.byte b
|
||||||
|
.endrepeat
|
||||||
|
.endmacro
|
||||||
|
.pushseg
|
||||||
|
.segment "CHARS"
|
||||||
|
T_EMPTY = 0
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_TOP_LEFT = 1
|
||||||
|
.repeat 2 ; Top Left 1
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_TOP_RIGHT = 2
|
||||||
|
.repeat 2 ; Top Right 2
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_RIGHT = 3
|
||||||
|
.repeat 2 ; Bottom Right 3
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_LEFT = 4
|
||||||
|
.repeat 2 ; Bottom Left 4
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_FORWARD = 5
|
||||||
|
.repeat 2 ; FW 5
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00111000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_BACKWARD = 6
|
||||||
|
.repeat 2 ; BW 6
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %00111000
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_PILL_L = 7
|
||||||
|
.repeat 2 ; Pill L 7
|
||||||
|
.byte %00111111
|
||||||
|
.byte %01111111
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01111111
|
||||||
|
.byte %00111111
|
||||||
|
.endrepeat
|
||||||
|
T_PILL_R = 8
|
||||||
|
.repeat 2 ; Pill R 8
|
||||||
|
.byte %11111100
|
||||||
|
.byte %11111110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %11111110
|
||||||
|
.byte %11111100
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
.popseg
|
||||||
|
|
||||||
|
zp_res TEMP
|
||||||
|
|
||||||
|
.macro load_ppu_addr addr
|
||||||
|
lda #.hibyte(addr)
|
||||||
|
sta PPUADDR
|
||||||
|
lda #.lobyte(addr)
|
||||||
|
sta PPUADDR ; Load $2000
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
ldx #$FF
|
||||||
|
txs
|
||||||
|
|
||||||
|
; Init PPU
|
||||||
|
bit PPUSTATUS
|
||||||
|
vwait1:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait1
|
||||||
|
vwait2:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait2
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUCTRL ; NMI off, PPU slave, Small sprites, 0 addresses
|
||||||
|
|
||||||
|
; Fill NT0
|
||||||
|
load_ppu_addr $2000
|
||||||
|
ldx #$00
|
||||||
|
ldy #$04
|
||||||
|
lda #$00
|
||||||
|
fill_loop:
|
||||||
|
sta PPUDATA
|
||||||
|
dex
|
||||||
|
bne fill_loop
|
||||||
|
dey
|
||||||
|
bne fill_loop
|
||||||
|
; Set specific tiles
|
||||||
|
load_ppu_addr $2184
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21A4
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E2
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C6
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E6
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2204
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $2224
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21EA
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$00
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D2
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $3F00
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$20
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$09
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUSCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK
|
||||||
|
lda #$80
|
||||||
|
sta PPUCTRL ; NMI on, PPU slave, Small sprites, 0 addresses
|
||||||
|
loop:
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
.macro shl_a count
|
||||||
|
.scope
|
||||||
|
ldx #count
|
||||||
|
a_l:asl A
|
||||||
|
dex
|
||||||
|
bne a_l
|
||||||
|
.endscope
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
nmi:
|
||||||
|
lda PPUSTATUS
|
||||||
|
lda #%00000110
|
||||||
|
sta PPUMASK ; Force blank
|
||||||
|
lda #$01
|
||||||
|
sta JOY1
|
||||||
|
lda #$00
|
||||||
|
sta JOY1
|
||||||
|
|
||||||
|
load_ppu_addr $23DC ; A
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
shl_a 6
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $23DD ; B
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
shl_a 6
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $23DA ; Select
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
shl_a 6
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $23DB ; Start
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
shl_a 6
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda JOY1 ; Up
|
||||||
|
and #$01
|
||||||
|
sta TEMP
|
||||||
|
|
||||||
|
load_ppu_addr $23E1 ; Down
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $23D8 ; Left
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
shl_a 6
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $23D9 ; Right
|
||||||
|
lda JOY1
|
||||||
|
and #$01
|
||||||
|
shl_a 6
|
||||||
|
ora TEMP
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUSCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK ; Enable rendering
|
||||||
|
rti
|
||||||
|
exit:
|
||||||
|
stp
|
||||||
|
|
||||||
|
irq:
|
||||||
|
stp
|
||||||
@@ -36,6 +36,8 @@ macro_rules! rom_test {
|
|||||||
|
|
||||||
pub(crate) use rom_test;
|
pub(crate) use rom_test;
|
||||||
|
|
||||||
|
use crate::{Break, NES};
|
||||||
|
|
||||||
rom_test!(basic_cpu, "basic-cpu.nes", |nes| {
|
rom_test!(basic_cpu, "basic-cpu.nes", |nes| {
|
||||||
assert_eq!(nes.last_instruction(), "0x8001 HLT :2 []");
|
assert_eq!(nes.last_instruction(), "0x8001 HLT :2 []");
|
||||||
assert_eq!(nes.cpu_cycle(), 10);
|
assert_eq!(nes.cpu_cycle(), 10);
|
||||||
@@ -136,6 +138,67 @@ rom_test!(even_odd, "even_odd.nes", |nes| {
|
|||||||
assert_eq!(nes.cpu.y, 0x00);
|
assert_eq!(nes.cpu.y, 0x00);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fn run_frame(nes: &mut NES) {
|
||||||
|
nes.run_one_clock_cycle(&Break::default());
|
||||||
|
while nes.ppu().scanline != 241 || nes.ppu().pixel != 0 {
|
||||||
|
nes.run_one_clock_cycle(&Break::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rom_test!(input_test, "input_test.nes", timeout = 86964*3, |nes| {
|
||||||
|
const A: u16 = 0x23DC; // 0 || 0b01000000
|
||||||
|
const B: u16 = 0x23DD; // 0 || 0b01000000
|
||||||
|
const SELECT: u16 = 0x23DA; // 0 || 0b01000000
|
||||||
|
const START: u16 = 0x23DB; // 0 || 0b01000000
|
||||||
|
const DOWN: u16 = 0x23E1; // 0 || 1
|
||||||
|
const LEFT: u16 = 0x23D8; // 0 || 0b01000000
|
||||||
|
const UP_RIGHT: u16 = 0x23D9; // 0 || 0b01000000 | 1
|
||||||
|
run_frame(&mut nes);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(A).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(B).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(SELECT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(START).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(DOWN).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(LEFT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(UP_RIGHT).unwrap(), 0);
|
||||||
|
nes.controller_1().set_a(true);
|
||||||
|
run_frame(&mut nes);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(A).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(B).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(SELECT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(START).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(DOWN).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(LEFT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(UP_RIGHT).unwrap(), 0);
|
||||||
|
nes.controller_1().set_b(true);
|
||||||
|
run_frame(&mut nes);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(A).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(B).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(SELECT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(START).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(DOWN).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(LEFT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(UP_RIGHT).unwrap(), 0);
|
||||||
|
nes.controller_1().0 = 0xFF;
|
||||||
|
run_frame(&mut nes);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(A).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(B).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(SELECT).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(START).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(DOWN).unwrap(), 0x01);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(LEFT).unwrap(), 0x40);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(UP_RIGHT).unwrap(), 0x41);
|
||||||
|
nes.controller_1().0 = 0;
|
||||||
|
run_frame(&mut nes);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(A).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(B).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(SELECT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(START).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(DOWN).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(LEFT).unwrap(), 0);
|
||||||
|
assert_eq!(nes.mapped.peek_ppu(UP_RIGHT).unwrap(), 0);
|
||||||
|
});
|
||||||
|
|
||||||
// rom_test!(even_odd, "even_odd.nes", |nes| {
|
// rom_test!(even_odd, "even_odd.nes", |nes| {
|
||||||
// assert_eq!(nes.last_instruction(), "0x8023 HLT :2 []");
|
// assert_eq!(nes.last_instruction(), "0x8023 HLT :2 []");
|
||||||
// assert_eq!(nes.cpu_cycle(), 57182);
|
// assert_eq!(nes.cpu_cycle(), 57182);
|
||||||
|
|||||||
@@ -94,3 +94,8 @@ rom_test!(ppu_palette_shared, "ppu_palette_shared.nes", |nes| {
|
|||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sets up an image, and scrolls a specific number of pixels over
|
||||||
|
rom_test!(ppu_scrolling, "ppu_fine_x_scrolling.nes", timeout = 86964*4, |nes| {
|
||||||
|
assert_eq!(nes.image().read(0, 0), Color { r: 0xFF, g: 0xFE, b: 0xFF });
|
||||||
|
});
|
||||||
|
|||||||
306
src/test_roms/ppu_fine_x_scrolling.s
Normal file
306
src/test_roms/ppu_fine_x_scrolling.s
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
.include "testing.s"
|
||||||
|
; patterns_bin "pat.bin"
|
||||||
|
.macro chr b,s
|
||||||
|
.repeat s
|
||||||
|
.byte b
|
||||||
|
.endrepeat
|
||||||
|
.endmacro
|
||||||
|
.pushseg
|
||||||
|
.segment "CHARS"
|
||||||
|
T_EMPTY = 0
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_TOP_LEFT = 1
|
||||||
|
.repeat 2 ; Top Left 1
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_TOP_RIGHT = 2
|
||||||
|
.repeat 2 ; Top Right 2
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_RIGHT = 3
|
||||||
|
.repeat 2 ; Bottom Right 3
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_LEFT = 4
|
||||||
|
.repeat 2 ; Bottom Left 4
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_FORWARD = 5
|
||||||
|
.repeat 2 ; FW 5
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00111000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_BACKWARD = 6
|
||||||
|
.repeat 2 ; BW 6
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %00111000
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_PILL_L = 7
|
||||||
|
.repeat 2 ; Pill L 7
|
||||||
|
.byte %00111111
|
||||||
|
.byte %01111111
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01111111
|
||||||
|
.byte %00111111
|
||||||
|
.endrepeat
|
||||||
|
T_PILL_R = 8
|
||||||
|
.repeat 2 ; Pill R 8
|
||||||
|
.byte %11111100
|
||||||
|
.byte %11111110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %11111110
|
||||||
|
.byte %11111100
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_LINE = 9
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
.popseg
|
||||||
|
|
||||||
|
zp_res Y_SCROLL
|
||||||
|
zp_res X_SCROLL
|
||||||
|
zp_res CTRL_BYTE
|
||||||
|
|
||||||
|
.macro load_ppu_addr addr
|
||||||
|
lda #.hibyte(addr)
|
||||||
|
sta PPUADDR
|
||||||
|
lda #.lobyte(addr)
|
||||||
|
sta PPUADDR ; Load $2000
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
ldx #$FF
|
||||||
|
txs
|
||||||
|
|
||||||
|
; Init PPU
|
||||||
|
bit PPUSTATUS
|
||||||
|
vwait1:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait1
|
||||||
|
vwait2:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait2
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUCTRL ; NMI off, PPU slave, Small sprites, 0 addresses
|
||||||
|
|
||||||
|
; Fill NT0
|
||||||
|
load_ppu_addr $2000
|
||||||
|
ldx #$00
|
||||||
|
ldy #$04
|
||||||
|
lda #$00
|
||||||
|
fill_loop:
|
||||||
|
sta PPUDATA
|
||||||
|
dex
|
||||||
|
bne fill_loop
|
||||||
|
dey
|
||||||
|
bne fill_loop
|
||||||
|
; Set specific tiles
|
||||||
|
load_ppu_addr $2184
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21A4
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E2
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C6
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E6
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2204
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $2224
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21EA
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$00
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D2
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $3F00
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$20
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$09
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2001
|
||||||
|
lda #T_LINE
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUSCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK
|
||||||
|
lda #$80
|
||||||
|
sta PPUCTRL ; NMI on, PPU slave, Small sprites, 0 addresses
|
||||||
|
sta CTRL_BYTE
|
||||||
|
loop:
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
nmi:
|
||||||
|
lda PPUSTATUS
|
||||||
|
lda #%00000110
|
||||||
|
sta PPUMASK ; Force blank
|
||||||
|
|
||||||
|
lda #$0A
|
||||||
|
; adc X_SCROLL
|
||||||
|
; sta X_SCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
; bcc y_scroll
|
||||||
|
; lda #$01
|
||||||
|
; eor CTRL_BYTE
|
||||||
|
; sta CTRL_BYTE
|
||||||
|
; sta PPUCTRL
|
||||||
|
; y_scroll:
|
||||||
|
; clc
|
||||||
|
lda #$00
|
||||||
|
; adc Y_SCROLL
|
||||||
|
; sta Y_SCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
|
||||||
|
lda CTRL_BYTE
|
||||||
|
sta PPUCTRL
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK ; Enable rendering
|
||||||
|
rti
|
||||||
|
exit:
|
||||||
|
stp
|
||||||
|
|
||||||
|
irq:
|
||||||
|
stp
|
||||||
306
src/test_roms/scrolling.s
Normal file
306
src/test_roms/scrolling.s
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
.include "testing.s"
|
||||||
|
; patterns_bin "pat.bin"
|
||||||
|
.macro chr b,s
|
||||||
|
.repeat s
|
||||||
|
.byte b
|
||||||
|
.endrepeat
|
||||||
|
.endmacro
|
||||||
|
.pushseg
|
||||||
|
.segment "CHARS"
|
||||||
|
T_EMPTY = 0
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_TOP_LEFT = 1
|
||||||
|
.repeat 2 ; Top Left 1
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_TOP_RIGHT = 2
|
||||||
|
.repeat 2 ; Top Right 2
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_RIGHT = 3
|
||||||
|
.repeat 2 ; Bottom Right 3
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_LEFT = 4
|
||||||
|
.repeat 2 ; Bottom Left 4
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_FORWARD = 5
|
||||||
|
.repeat 2 ; FW 5
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00111000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_BACKWARD = 6
|
||||||
|
.repeat 2 ; BW 6
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %00111000
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_PILL_L = 7
|
||||||
|
.repeat 2 ; Pill L 7
|
||||||
|
.byte %00111111
|
||||||
|
.byte %01111111
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01111111
|
||||||
|
.byte %00111111
|
||||||
|
.endrepeat
|
||||||
|
T_PILL_R = 8
|
||||||
|
.repeat 2 ; Pill R 8
|
||||||
|
.byte %11111100
|
||||||
|
.byte %11111110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %11111110
|
||||||
|
.byte %11111100
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_LINE = 9
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
.popseg
|
||||||
|
|
||||||
|
zp_res Y_SCROLL
|
||||||
|
zp_res X_SCROLL
|
||||||
|
zp_res CTRL_BYTE
|
||||||
|
|
||||||
|
.macro load_ppu_addr addr
|
||||||
|
lda #.hibyte(addr)
|
||||||
|
sta PPUADDR
|
||||||
|
lda #.lobyte(addr)
|
||||||
|
sta PPUADDR ; Load $2000
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
ldx #$FF
|
||||||
|
txs
|
||||||
|
|
||||||
|
; Init PPU
|
||||||
|
bit PPUSTATUS
|
||||||
|
vwait1:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait1
|
||||||
|
vwait2:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait2
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUCTRL ; NMI off, PPU slave, Small sprites, 0 addresses
|
||||||
|
|
||||||
|
; Fill NT0
|
||||||
|
load_ppu_addr $2000
|
||||||
|
ldx #$00
|
||||||
|
ldy #$04
|
||||||
|
lda #$00
|
||||||
|
fill_loop:
|
||||||
|
sta PPUDATA
|
||||||
|
dex
|
||||||
|
bne fill_loop
|
||||||
|
dey
|
||||||
|
bne fill_loop
|
||||||
|
; Set specific tiles
|
||||||
|
load_ppu_addr $2184
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21A4
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E2
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C6
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E6
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2204
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $2224
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21EA
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$00
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D2
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $3F00
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$20
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$09
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2001
|
||||||
|
lda #T_LINE
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUSCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK
|
||||||
|
lda #$80
|
||||||
|
sta PPUCTRL ; NMI on, PPU slave, Small sprites, 0 addresses
|
||||||
|
sta CTRL_BYTE
|
||||||
|
loop:
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
nmi:
|
||||||
|
lda PPUSTATUS
|
||||||
|
lda #%00000110
|
||||||
|
sta PPUMASK ; Force blank
|
||||||
|
|
||||||
|
lda #$0A
|
||||||
|
adc X_SCROLL
|
||||||
|
sta X_SCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
bcc y_scroll
|
||||||
|
lda #$01
|
||||||
|
eor CTRL_BYTE
|
||||||
|
sta CTRL_BYTE
|
||||||
|
sta PPUCTRL
|
||||||
|
y_scroll:
|
||||||
|
clc
|
||||||
|
lda #$00
|
||||||
|
adc Y_SCROLL
|
||||||
|
sta Y_SCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
|
||||||
|
lda CTRL_BYTE
|
||||||
|
sta PPUCTRL
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK ; Enable rendering
|
||||||
|
rti
|
||||||
|
exit:
|
||||||
|
stp
|
||||||
|
|
||||||
|
irq:
|
||||||
|
stp
|
||||||
321
src/test_roms/sprites.s
Normal file
321
src/test_roms/sprites.s
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
.include "testing.s"
|
||||||
|
|
||||||
|
.pushseg
|
||||||
|
.segment "CHARS"
|
||||||
|
T_EMPTY = 0
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.byte %00000000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_TOP_LEFT = 1
|
||||||
|
.repeat 2 ; Top Left 1
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_TOP_RIGHT = 2
|
||||||
|
.repeat 2 ; Top Right 2
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_RIGHT = 3
|
||||||
|
.repeat 2 ; Bottom Right 3
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_BOTTOM_LEFT = 4
|
||||||
|
.repeat 2 ; Bottom Left 4
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11111111
|
||||||
|
.byte %11111111
|
||||||
|
.endrepeat
|
||||||
|
T_FORWARD = 5
|
||||||
|
.repeat 2 ; FW 5
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00111000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.endrepeat
|
||||||
|
T_BACKWARD = 6
|
||||||
|
.repeat 2 ; BW 6
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01110000
|
||||||
|
.byte %00111000
|
||||||
|
.byte %00011100
|
||||||
|
.byte %00001110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_PILL_L = 7
|
||||||
|
.repeat 2 ; Pill L 7
|
||||||
|
.byte %00111111
|
||||||
|
.byte %01111111
|
||||||
|
.byte %11100000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11000000
|
||||||
|
.byte %11100000
|
||||||
|
.byte %01111111
|
||||||
|
.byte %00111111
|
||||||
|
.endrepeat
|
||||||
|
T_PILL_R = 8
|
||||||
|
.repeat 2 ; Pill R 8
|
||||||
|
.byte %11111100
|
||||||
|
.byte %11111110
|
||||||
|
.byte %00000111
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000011
|
||||||
|
.byte %00000111
|
||||||
|
.byte %11111110
|
||||||
|
.byte %11111100
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
T_LINE = 9
|
||||||
|
.repeat 2 ; Empty 0
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.byte %00100000
|
||||||
|
.endrepeat
|
||||||
|
|
||||||
|
.popseg
|
||||||
|
|
||||||
|
zp_res Y_SCROLL
|
||||||
|
zp_res X_SCROLL
|
||||||
|
zp_res CTRL_BYTE
|
||||||
|
|
||||||
|
.macro load_ppu_addr addr
|
||||||
|
lda #.hibyte(addr)
|
||||||
|
sta PPUADDR
|
||||||
|
lda #.lobyte(addr)
|
||||||
|
sta PPUADDR ; Load $2000
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
ldx #$FF
|
||||||
|
txs
|
||||||
|
|
||||||
|
; Init PPU
|
||||||
|
bit PPUSTATUS
|
||||||
|
vwait1:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait1
|
||||||
|
vwait2:
|
||||||
|
bit PPUSTATUS
|
||||||
|
bpl vwait2
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUCTRL ; NMI off, PPU slave, Small sprites, 0 addresses
|
||||||
|
|
||||||
|
; Fill NT0
|
||||||
|
load_ppu_addr $2000
|
||||||
|
ldx #$00
|
||||||
|
ldy #$04
|
||||||
|
lda #$00
|
||||||
|
fill_loop:
|
||||||
|
sta PPUDATA
|
||||||
|
dex
|
||||||
|
bne fill_loop
|
||||||
|
dey
|
||||||
|
bne fill_loop
|
||||||
|
; Set specific tiles
|
||||||
|
load_ppu_addr $2184
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21A4
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E2
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21C6
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21E6
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2204
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $2224
|
||||||
|
lda #T_BOTTOM_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BOTTOM_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21EA
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$00
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
lda #T_PILL_L
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D2
|
||||||
|
lda #T_FORWARD
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_BACKWARD
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F2
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_TOP_RIGHT
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $21D6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
load_ppu_addr $21F6
|
||||||
|
lda #T_TOP_LEFT
|
||||||
|
sta PPUDATA
|
||||||
|
lda #T_PILL_R
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $3F00
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$20
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$0f
|
||||||
|
sta PPUDATA
|
||||||
|
lda #$09
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
load_ppu_addr $2001
|
||||||
|
lda #T_LINE
|
||||||
|
sta PPUDATA
|
||||||
|
|
||||||
|
ldx #$00
|
||||||
|
sprite_loop:
|
||||||
|
lda sprite_data,x
|
||||||
|
sta $300,x
|
||||||
|
inx
|
||||||
|
cpx #(sprite_data_end - sprite_data)
|
||||||
|
bne sprite_loop
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta PPUSCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
lda #%00001110
|
||||||
|
sta PPUMASK
|
||||||
|
lda #$80
|
||||||
|
sta PPUCTRL ; NMI on, PPU slave, Small sprites, 0 addresses
|
||||||
|
sta CTRL_BYTE
|
||||||
|
loop:
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
nmi:
|
||||||
|
lda PPUSTATUS
|
||||||
|
lda #%00000110
|
||||||
|
sta PPUMASK ; Force blank
|
||||||
|
|
||||||
|
lda #$01
|
||||||
|
adc X_SCROLL
|
||||||
|
sta X_SCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
bcc y_scroll
|
||||||
|
lda #$01
|
||||||
|
eor CTRL_BYTE
|
||||||
|
sta CTRL_BYTE
|
||||||
|
sta PPUCTRL
|
||||||
|
y_scroll:
|
||||||
|
clc
|
||||||
|
lda #$00
|
||||||
|
adc Y_SCROLL
|
||||||
|
sta Y_SCROLL
|
||||||
|
sta PPUSCROLL
|
||||||
|
|
||||||
|
lda #$00
|
||||||
|
sta SPRADDR
|
||||||
|
lda #$03
|
||||||
|
sta SPRDMA
|
||||||
|
|
||||||
|
lda CTRL_BYTE
|
||||||
|
sta PPUCTRL
|
||||||
|
lda #%00011110
|
||||||
|
sta PPUMASK ; Enable rendering
|
||||||
|
rti
|
||||||
|
exit:
|
||||||
|
stp
|
||||||
|
|
||||||
|
irq:
|
||||||
|
stp
|
||||||
|
|
||||||
|
sprite_data:
|
||||||
|
.byte $00
|
||||||
|
.byte T_PILL_R
|
||||||
|
.byte $00
|
||||||
|
.byte $00
|
||||||
|
sprite_data_end:
|
||||||
Reference in New Issue
Block a user