ppu can trigger NMIs
This commit is contained in:
@@ -11,7 +11,7 @@ Usage:
|
||||
```
|
||||
Make sure to compile with `--release` for 60 fps.
|
||||
|
||||

|
||||

|
||||
|
||||
### what works
|
||||
* CPU
|
||||
|
||||
13
src/main.rs
13
src/main.rs
@@ -110,7 +110,7 @@ fn main() -> Result<(), Error> {
|
||||
}).collect();
|
||||
|
||||
// Main loop
|
||||
let mut run = true;
|
||||
let mut run = false;
|
||||
while let Some(event) = events.next(&mut window) {
|
||||
if let Some(_) = event.render_args() {
|
||||
// Run enough clocks to render the next frame
|
||||
@@ -121,8 +121,8 @@ fn main() -> Result<(), Error> {
|
||||
let mut ppu = nes.ppu.borrow_mut();
|
||||
let ppu_bus = nes.ppu_bus.borrow();
|
||||
// main_texture.update(&mut texture_ctx, &ppu.canvas_main).unwrap();
|
||||
pattern_table_textures[0].update(&mut texture_ctx, &ppu.get_pattern_table(&*ppu_bus, 0, 1)).unwrap();
|
||||
pattern_table_textures[1].update(&mut texture_ctx, &ppu.get_pattern_table(&*ppu_bus, 1, 1)).unwrap();
|
||||
pattern_table_textures[0].update(&mut texture_ctx, &ppu.get_pattern_table(&*ppu_bus, 0, 0)).unwrap();
|
||||
pattern_table_textures[1].update(&mut texture_ctx, &ppu.get_pattern_table(&*ppu_bus, 1, 0)).unwrap();
|
||||
palette_textures[0].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 0)).unwrap();
|
||||
palette_textures[1].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 1)).unwrap();
|
||||
palette_textures[2].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 2)).unwrap();
|
||||
@@ -249,6 +249,13 @@ fn render_cpu(glyphs: &mut GlyphBrush<Resources, Factory>, cpu: &CPU, offset: [f
|
||||
cpu.is_flag_set(Flags::CARRY)
|
||||
],
|
||||
offset);
|
||||
glyphs.queue(Section {
|
||||
text: &format!("({:#04x})", cpu.regs.flags.bits()),
|
||||
scale: *FT_SCALE,
|
||||
screen_position: (offset[0]+200.0, offset[1]+FT_SIZE_PX) ,
|
||||
color: FT_COLOR_WHITE,
|
||||
..Section::default()
|
||||
});
|
||||
|
||||
let cpu_register_texts = [
|
||||
&format!("A: {0:#x} ({0})", cpu.regs.a),
|
||||
|
||||
@@ -74,7 +74,13 @@ impl NES {
|
||||
if self.clock_count % 3 == 0 {
|
||||
self.cpu.clock(&mut self.bus);
|
||||
}
|
||||
self.ppu.borrow_mut().clock(&mut *self.ppu_bus.borrow_mut());
|
||||
let mut ppu = self.ppu.borrow_mut();
|
||||
ppu.clock(&mut *self.ppu_bus.borrow_mut());
|
||||
if ppu.nmi {
|
||||
ppu.nmi = false;
|
||||
self.cpu.nmi(&mut self.bus);
|
||||
debug!("NMI triggered by PPU.")
|
||||
}
|
||||
if self.clock_count % 100000 == 0 {
|
||||
info!("clock {}", self.clock_count);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,41 @@ impl CPU {
|
||||
self.curr_op = 0x00;
|
||||
}
|
||||
|
||||
fn interrupt<T: Memory>(&mut self, mem: &mut T, pc_addr: Addr) {
|
||||
// push pc to stack
|
||||
self.pushb_sp(mem, (self.regs.pc >> 8) as Byte);
|
||||
self.pushb_sp(mem, self.regs.pc as Byte);
|
||||
|
||||
// push status reg with set interrupt flags to stack
|
||||
self.set_flag(Flags::BREAK, false);
|
||||
self.set_flag(Flags::UNUSED, true);
|
||||
self.set_flag(Flags::IRQ, true);
|
||||
self.pushb_sp(mem, self.regs.flags.bits());
|
||||
|
||||
// read new pc
|
||||
let lo = mem.readb(pc_addr);
|
||||
let hi = mem.readb(pc_addr + 1);
|
||||
self.regs.pc = ((hi as Addr) << 8) | lo as Addr;
|
||||
}
|
||||
|
||||
// Non maskable interrupt
|
||||
pub fn nmi<T: Memory>(&mut self, mem: &mut T) {
|
||||
let new_pc_addr = 0xFFFA;
|
||||
self.interrupt(mem, new_pc_addr);
|
||||
self.cycles_ahead = 8;
|
||||
}
|
||||
|
||||
// Interrupt request: Same as nmi, but only takes place if interrupts are
|
||||
// allowed
|
||||
pub fn irq<T: Memory>(&mut self, mem: &mut T) {
|
||||
if self.is_flag_set(Flags::IRQ) {
|
||||
let new_pc_addr = 0xFFFE;
|
||||
self.interrupt(mem, new_pc_addr);
|
||||
self.cycles_ahead = 7;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// True if the operation is not finished yet
|
||||
pub fn is_ahead(&self) -> bool {
|
||||
return self.cycles_ahead > 0;
|
||||
|
||||
@@ -98,10 +98,11 @@ pub struct PPU {
|
||||
pub regs: Registers,
|
||||
pub cycle: u16,
|
||||
pub scanline: u16,
|
||||
pub frame_ready: bool,
|
||||
pub nmi: bool,
|
||||
pub canvas_main: Sprite,
|
||||
pub pattern_tables: [Sprite; 2],
|
||||
pub palettes: [Sprite; 8],
|
||||
pub frame_ready: bool,
|
||||
addr_latch_set: bool,
|
||||
data_buffer: Byte,
|
||||
}
|
||||
@@ -112,6 +113,8 @@ impl PPU {
|
||||
regs: Registers::new(),
|
||||
cycle: 0,
|
||||
scanline: 0,
|
||||
frame_ready: false,
|
||||
nmi: false,
|
||||
canvas_main: ImageBuffer::from_pixel(256, 240, PALETTE[&0x00]),
|
||||
pattern_tables: [
|
||||
ImageBuffer::from_pixel(128, 128, PALETTE[&0x00]),
|
||||
@@ -127,7 +130,6 @@ impl PPU {
|
||||
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||
],
|
||||
frame_ready: false,
|
||||
addr_latch_set: false,
|
||||
data_buffer: 0
|
||||
}
|
||||
@@ -190,6 +192,9 @@ impl PPU {
|
||||
// set/clear vblank flag
|
||||
if self.scanline == 241 && self.cycle == 1 {
|
||||
self.set_status(Status::VERTICAL_BLANK, true);
|
||||
if self.get_control(Control::ENABLE_NMI) {
|
||||
self.nmi = true;
|
||||
}
|
||||
|
||||
} else if self.scanline == 261 && self.cycle == 1 {
|
||||
self.set_status(Status::VERTICAL_BLANK, false);
|
||||
@@ -221,7 +226,7 @@ impl PPU {
|
||||
// palette memory
|
||||
let data = self.data_buffer;
|
||||
self.data_buffer = mem.readb_ppu(addr);
|
||||
|
||||
|
||||
if addr > 0x3F00 { // everything above 0x3F00 is palette
|
||||
self.data_buffer
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user