From e962150aafe5eef39a7b578fb1969752ec0e44aa Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Mon, 29 Jul 2019 01:28:22 +0300 Subject: [PATCH] Start working on Interrupts. it kinda works now, but needs testing. Former-commit-id: 8510314cce248a737d492d935cf5b48f86d920ed --- src/core/arm7tdmi/arm/mod.rs | 12 +++--- src/core/arm7tdmi/exception.rs | 5 ++- src/core/arm7tdmi/thumb/mod.rs | 8 ++-- src/core/gba.rs | 38 +++++++++-------- src/core/sysbus.rs | 76 +++++++++++++++++++++------------- 5 files changed, 82 insertions(+), 57 deletions(-) diff --git a/src/core/arm7tdmi/arm/mod.rs b/src/core/arm7tdmi/arm/mod.rs index 3577950..3b06e9e 100644 --- a/src/core/arm7tdmi/arm/mod.rs +++ b/src/core/arm7tdmi/arm/mod.rs @@ -375,7 +375,7 @@ mod tests { let mut core = Core::new(); let bytes = vec![]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); // swi #0x1337 let decoded = ArmInstruction::decode(0xef001337, 0).unwrap(); @@ -406,7 +406,7 @@ mod tests { core.pc = 0x20 + 8; let bytes = vec![]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(core.did_pipeline_flush(), true); @@ -429,7 +429,7 @@ mod tests { core.pc = 0x20 + 8; let bytes = vec![]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(core.did_pipeline_flush(), true); @@ -472,7 +472,7 @@ mod tests { /* 20h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(core.gpr[2], 0x1337); @@ -513,7 +513,7 @@ mod tests { /* 20h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(mem.read_32(0), 0xabababab); @@ -538,7 +538,7 @@ mod tests { /* c: */ 0xaa, 0xbb, 0xcc, 0xdd, /* 10: */ 0xaa, 0xbb, 0xcc, 0xdd, ]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); assert_ne!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); core.exec_arm(&mut mem, decoded).unwrap(); diff --git a/src/core/arm7tdmi/exception.rs b/src/core/arm7tdmi/exception.rs index e1139be..aedfc25 100644 --- a/src/core/arm7tdmi/exception.rs +++ b/src/core/arm7tdmi/exception.rs @@ -36,11 +36,12 @@ impl Core { let new_mode = CpuMode::from(e); if self.verbose { println!( - "{}: {:?}, pc: {:#x}, new_mode: {:?}", + "{}: {:?}, pc: {:#x}, new_mode: {:?} old_mode: {:?}", "Exception".cyan(), e, self.pc, - new_mode + new_mode, + self.cpsr.mode(), ); } diff --git a/src/core/arm7tdmi/thumb/mod.rs b/src/core/arm7tdmi/thumb/mod.rs index de32368..698057f 100644 --- a/src/core/arm7tdmi/thumb/mod.rs +++ b/src/core/arm7tdmi/thumb/mod.rs @@ -358,7 +358,7 @@ mod tests { #[test] fn mov_low_reg() { let bytes = vec![]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); let mut core = Core::new(); core.set_reg(0, 0); @@ -390,7 +390,7 @@ mod tests { /* 8: */ 0x00, 0x00, 0x00, 0x00, /* c: */ 0x78, 0x56, 0x34, 0x12, ]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); let mut core = Core::new(); core.set_reg(0, 0); @@ -420,7 +420,7 @@ mod tests { /* 0ch: */ 0xaa, 0xbb, 0xcc, 0xdd, /* 10h: */ 0xaa, 0xbb, 0xcc, 0xdd, ]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); assert_eq!(format!("{}", str_insn), "str\tr0, [r4, r1]"); assert_eq!(format!("{}", ldr_insn), "ldrb\tr2, [r4, r1]"); @@ -440,7 +440,7 @@ mod tests { /* 08h: */ 0xaa, 0xbb, 0xcc, 0xdd, 0xaa, 0xbb, 0xcc, 0xdd, /* 10h: */ 0xaa, 0xbb, 0xcc, 0xdd, 0xaa, 0xbb, 0xcc, 0xdd, ]; - let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); core.gpr[4] = 0x12345678; core.gpr[3] = 0x2; diff --git a/src/core/gba.rs b/src/core/gba.rs index aa17ce2..74be21f 100644 --- a/src/core/gba.rs +++ b/src/core/gba.rs @@ -11,6 +11,8 @@ use super::EmuIoDev; use super::{GBAError, GBAResult}; use crate::backend::*; +use crate::bit::BitIndex; + pub struct GameBoyAdvance { backend: Box, pub cpu: Core, @@ -86,23 +88,27 @@ impl GameBoyAdvance { let previous_cycles = self.cpu.cycles; self.cpu.step(&mut self.sysbus).unwrap(); let cycles = self.cpu.cycles - previous_cycles; - self.gpu.step(cycles, &mut self.sysbus); + let (_, irq) = self.gpu.step(cycles, &mut self.sysbus); + if let Some(irq) = irq { + self.request_irq(irq); + } } fn interrupts_disabled(&self) -> bool { - self.sysbus.ioregs.read_reg(REG_IME) & 1 == 0 + self.cpu.cpsr.irq_disabled() | (self.sysbus.ioregs.read_reg(REG_IME) & 1 == 0) } fn request_irq(&mut self, irq: Interrupt) { - // if self.interrupts_disabled() { - // return; - // } - // let irq_bit = irq as usize; - // let reg_ie = self.sysbus.ioregs.read_reg(REG_IE); - // if reg_ie & (1 << irq_bit) != 0 { - // println!("entering {:?}", irq); - // self.cpu.exception(Exception::Irq); - // } + if self.interrupts_disabled() { + return; + } + let irq_bit_index = irq as usize; + let reg_ie = self.sysbus.ioregs.read_reg(REG_IE); + if reg_ie.bit(irq_bit_index) { + self.sysbus.ioregs.write_reg(REG_IF, (1 << irq_bit_index) as u16); + println!("entering {:?}", irq); + self.cpu.exception(Exception::Irq); + } } pub fn step(&mut self) -> GBAResult { @@ -125,12 +131,10 @@ impl GameBoyAdvance { // let (dma_cycles, _) = self.dma3.step(cycles, &mut self.sysbus); // cycles += dma_cycles; - /* let (_, irq) = */ - self.gpu.step(cycles, &mut self.sysbus); - // if let Some(irq) = irq { - // self.request_irq(irq); - // } - // cycles += lcd_cycles; + let (_, irq) = self.gpu.step(cycles, &mut self.sysbus); + if let Some(irq) = irq { + self.request_irq(irq); + } Ok(executed_insn) } diff --git a/src/core/sysbus.rs b/src/core/sysbus.rs index 1c229ad..33a11c9 100644 --- a/src/core/sysbus.rs +++ b/src/core/sysbus.rs @@ -9,20 +9,32 @@ use super::arm7tdmi::Addr; const VIDEO_RAM_SIZE: usize = 128 * 1024; const WORK_RAM_SIZE: usize = 256 * 1024; -const INTERNAL_RAM: usize = 32 * 1024; +const INTERNAL_RAM_SIZE: usize = 32 * 1024; const PALETTE_RAM_SIZE: usize = 1 * 1024; const OAM_SIZE: usize = 1 * 1024; #[derive(Debug)] -pub struct BoxedMemory(Box<[u8]>, WaitState); +pub struct BoxedMemory { + mem: Box<[u8]>, + ws: WaitState, + mask: u32, +} impl BoxedMemory { - pub fn new(boxed_slice: Box<[u8]>) -> BoxedMemory { - BoxedMemory(boxed_slice, Default::default()) + pub fn new(boxed_slice: Box<[u8]>, mask: u32) -> BoxedMemory { + BoxedMemory { + mem: boxed_slice, + mask: mask, + ws: WaitState::default(), + } } - pub fn new_with_waitstate(boxed_slice: Box<[u8]>, ws: WaitState) -> BoxedMemory { - BoxedMemory(boxed_slice, ws) + pub fn new_with_waitstate(boxed_slice: Box<[u8]>, mask: u32, ws: WaitState) -> BoxedMemory { + BoxedMemory { + mem: boxed_slice, + mask: mask, + ws: ws, + } } } @@ -51,50 +63,52 @@ impl Default for WaitState { impl Bus for BoxedMemory { fn read_32(&self, addr: Addr) -> u32 { - (&self.0[addr as usize..]) + (&self.mem[(addr & self.mask) as usize..]) .read_u32::() .unwrap() } fn read_16(&self, addr: Addr) -> u16 { - (&self.0[addr as usize..]) + (&self.mem[(addr & self.mask) as usize..]) .read_u16::() .unwrap() } fn read_8(&self, addr: Addr) -> u8 { - (&self.0[addr as usize..])[0] + (&self.mem[(addr & self.mask) as usize..])[0] } fn write_32(&mut self, addr: Addr, value: u32) { - (&mut self.0[addr as usize..]) + (&mut self.mem[(addr & self.mask) as usize..]) .write_u32::(value) .unwrap() } fn write_16(&mut self, addr: Addr, value: u16) { - (&mut self.0[addr as usize..]) + (&mut self.mem[(addr & self.mask) as usize..]) .write_u16::(value) .unwrap() } fn write_8(&mut self, addr: Addr, value: u8) { - (&mut self.0[addr as usize..]).write_u8(value).unwrap() + (&mut self.mem[(addr & self.mask) as usize..]) + .write_u8(value) + .unwrap() } fn get_bytes(&self, addr: Addr) -> &[u8] { - &self.0[addr as usize..] + &self.mem[(addr & self.mask) as usize..] } fn get_bytes_mut(&mut self, addr: Addr) -> &mut [u8] { - &mut self.0[addr as usize..] + &mut self.mem[(addr & self.mask) as usize..] } fn get_cycles(&self, _addr: Addr, access: MemoryAccess) -> usize { match access.1 { - MemoryAccessWidth::MemoryAccess8 => self.1.access8, - MemoryAccessWidth::MemoryAccess16 => self.1.access16, - MemoryAccessWidth::MemoryAccess32 => self.1.access32, + MemoryAccessWidth::MemoryAccess8 => self.ws.access8, + MemoryAccessWidth::MemoryAccess16 => self.ws.access16, + MemoryAccessWidth::MemoryAccess32 => self.ws.access32, } } } @@ -151,22 +165,28 @@ pub struct SysBus { impl SysBus { pub fn new(bios_rom: Vec, gamepak: Cartridge) -> SysBus { SysBus { - bios: BoxedMemory::new(bios_rom.into_boxed_slice()), + bios: BoxedMemory::new(bios_rom.into_boxed_slice(), 0xff_ffff), onboard_work_ram: BoxedMemory::new_with_waitstate( vec![0; WORK_RAM_SIZE].into_boxed_slice(), + (WORK_RAM_SIZE as u32) - 1, WaitState::new(3, 3, 6), ), - internal_work_ram: BoxedMemory::new(vec![0; INTERNAL_RAM].into_boxed_slice()), + internal_work_ram: BoxedMemory::new( + vec![0; INTERNAL_RAM_SIZE].into_boxed_slice(), + 0x7fff, + ), ioregs: IoRegs::default(), palette_ram: BoxedMemory::new_with_waitstate( vec![0; PALETTE_RAM_SIZE].into_boxed_slice(), + (PALETTE_RAM_SIZE as u32) - 1, WaitState::new(1, 1, 2), ), vram: BoxedMemory::new_with_waitstate( vec![0; VIDEO_RAM_SIZE].into_boxed_slice(), + (VIDEO_RAM_SIZE as u32) - 1, WaitState::new(1, 1, 2), ), - oam: BoxedMemory::new(vec![0; OAM_SIZE].into_boxed_slice()), + oam: BoxedMemory::new(vec![0; OAM_SIZE].into_boxed_slice(), (OAM_SIZE as u32) - 1), gamepak: gamepak, dummy: DummyBus([0; 4]), } @@ -175,11 +195,11 @@ impl SysBus { fn map(&self, addr: Addr) -> &Bus { match addr as usize { 0x0000_0000...0x0000_3fff => &self.bios, - 0x0200_0000...0x0203_ffff => &self.onboard_work_ram, - 0x0300_0000...0x0300_7fff => &self.internal_work_ram, + 0x0200_0000...0x02ff_ffff => &self.onboard_work_ram, + 0x0300_0000...0x03ff_ffff => &self.internal_work_ram, 0x0400_0000...0x0400_03fe => &self.ioregs, - 0x0500_0000...0x0500_03ff => &self.palette_ram, - 0x0600_0000...0x0601_7fff => &self.vram, + 0x0500_0000...0x05ff_ffff => &self.palette_ram, + 0x0600_0000...0x06ff_ffff => &self.vram, 0x0700_0000...0x0700_03ff => &self.oam, 0x0800_0000...0x09ff_ffff => &self.gamepak, _ => &self.dummy, @@ -190,11 +210,11 @@ impl SysBus { fn map_mut(&mut self, addr: Addr) -> &mut Bus { match addr as usize { 0x0000_0000...0x0000_3fff => &mut self.bios, - 0x0200_0000...0x0203_ffff => &mut self.onboard_work_ram, - 0x0300_0000...0x0300_7fff => &mut self.internal_work_ram, + 0x0200_0000...0x02ff_ffff => &mut self.onboard_work_ram, + 0x0300_0000...0x03ff_ffff => &mut self.internal_work_ram, 0x0400_0000...0x0400_03fe => &mut self.ioregs, - 0x0500_0000...0x0500_03ff => &mut self.palette_ram, - 0x0600_0000...0x0601_7fff => &mut self.vram, + 0x0500_0000...0x05ff_ffff => &mut self.palette_ram, + 0x0600_0000...0x06ff_ffff => &mut self.vram, 0x0700_0000...0x0700_03ff => &mut self.oam, 0x0800_0000...0x09ff_ffff => &mut self.gamepak, _ => &mut self.dummy,