diff --git a/src/dma.rs b/src/dma.rs new file mode 100644 index 0000000..a6b7eb7 --- /dev/null +++ b/src/dma.rs @@ -0,0 +1,74 @@ +use super::arm7tdmi::{Addr, Bus}; +use super::ioregs::consts::*; +use super::sysbus::SysBus; +use super::{EmuIoDev, Interrupt}; + +#[allow(non_camel_case_types)] +#[derive(Debug)] +pub struct DmaChannel { + src_ioreg: Addr, /* Source Address register */ + dst_ioreg: Addr, /* Destination Address register */ + wc_ioreg: Addr, /* Word Count 14bit */ +} + +#[derive(Debug, Primitive)] +enum DmaAddrControl { + Increment = 0, + Decrement = 1, + Fixed = 2, + IncrementReloadProhibited = 3, +} + +#[derive(Debug)] +enum DmaTransferType { + Xfer16bit, + Xfer32bit, +} + +#[derive(Debug, Primitive)] +enum DmaStartTiming { + Immediately = 0, + VBlank = 1, + HBlank = 2, + Special = 3, +} + +#[derive(Debug)] +struct DmaControl { + dst_addr_ctl: DmaAddrControl, + src_addr_ctl: DmaAddrControl, + repeat: bool, + xfer: DmaTransferType, + start_timing: DmaStartTiming, + irq_upon_end_of_wc: bool, + enable: bool, +} + +impl DmaChannel { + pub fn new(src_ioreg: Addr, dst_ioreg: Addr, wc_ioreg: Addr) -> DmaChannel { + DmaChannel { + src_ioreg, + dst_ioreg, + wc_ioreg, + } + } + + fn src_addr(&self, sysbus: &SysBus) -> Addr { + sysbus.ioregs.read_32(self.src_ioreg - IO_BASE) as Addr + } + + fn dst_addr(&self, sysbus: &SysBus) -> Addr { + sysbus.ioregs.read_32(self.dst_ioreg - IO_BASE) as Addr + } + + fn word_count(&self, sysbus: &SysBus) -> usize { + sysbus.ioregs.read_reg(self.wc_ioreg) as usize + } +} + +impl EmuIoDev for DmaChannel { + fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> (usize, Option) { + // TODO + (0, None) + } +} diff --git a/src/gba.rs b/src/gba.rs index 175153a..9de9dc3 100644 --- a/src/gba.rs +++ b/src/gba.rs @@ -1,9 +1,12 @@ -use super::arm7tdmi::{Core, DecodedInstruction}; -use super::cartridge::Cartridge; -use super::lcd::Lcd; -use super::sysbus::SysBus; /// Struct containing everything /// +use super::arm7tdmi::{Core, DecodedInstruction}; +use super::cartridge::Cartridge; +use super::dma::DmaChannel; +use super::ioregs::consts::*; +use super::lcd::Lcd; +use super::sysbus::SysBus; + use super::{EmuIoDev, GBAResult}; #[derive(Debug)] @@ -13,6 +16,10 @@ pub struct GameBoyAdvance { // io devices lcd: Lcd, + dma0: DmaChannel, + dma1: DmaChannel, + dma2: DmaChannel, + dma3: DmaChannel, post_bool_flags: bool, } @@ -26,6 +33,10 @@ impl GameBoyAdvance { sysbus: sysbus, lcd: Lcd::new(), + dma0: DmaChannel::new(REG_DMA0SAD, REG_DMA0DAD, REG_DMA0DAD), + dma1: DmaChannel::new(REG_DMA1SAD, REG_DMA1DAD, REG_DMA1DAD), + dma2: DmaChannel::new(REG_DMA2SAD, REG_DMA2DAD, REG_DMA2DAD), + dma3: DmaChannel::new(REG_DMA3SAD, REG_DMA3DAD, REG_DMA3DAD), post_bool_flags: false, } @@ -34,9 +45,25 @@ impl GameBoyAdvance { pub fn step(&mut self) -> GBAResult { let previous_cycles = self.cpu.cycles; let decoded = self.cpu.step_one(&mut self.sysbus)?; - let cycles = self.cpu.cycles - previous_cycles; - self.lcd.step(cycles, &mut self.sysbus); // drop interrupts at the moment + // drop interrupts at the moment + let cycles = self.cpu.cycles - previous_cycles; + let (dma_cycles, _) = self.dma0.step(cycles, &mut self.sysbus); + let cycles = cycles + dma_cycles; + + let cycles = self.cpu.cycles - previous_cycles; + let (dma_cycles, _) = self.dma1.step(cycles, &mut self.sysbus); + let cycles = cycles + dma_cycles; + + let cycles = self.cpu.cycles - previous_cycles; + let (dma_cycles, _) = self.dma2.step(cycles, &mut self.sysbus); + let cycles = cycles + dma_cycles; + + let cycles = self.cpu.cycles - previous_cycles; + let (dma_cycles, _) = self.dma3.step(cycles, &mut self.sysbus); + let cycles = cycles + dma_cycles; + + let (lcd_cycles, _) = self.lcd.step(cycles, &mut self.sysbus); Ok(decoded) // return the decoded instruction for the debugger } diff --git a/src/lcd.rs b/src/lcd.rs index 2e28b7a..7cc843a 100644 --- a/src/lcd.rs +++ b/src/lcd.rs @@ -96,15 +96,13 @@ impl Lcd { } impl EmuIoDev for Lcd { - fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> Option { + fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> (usize, Option) { self.cycles += cycles; - let mut result = None; - let mut dispcnt = DisplayControl::from(sysbus.ioregs.read_reg(REG_DISPCNT)); - let mut dispstat = DisplayStatus::from(sysbus.ioregs.read_reg(REG_DISPSTAT)); + // let mut dispcnt = DisplayControl::from(sysbus.ioregs.read_reg(REG_DISPCNT)); + // let mut dispstat = DisplayStatus::from(sysbus.ioregs.read_reg(REG_DISPSTAT)); // TODO - - result + (0, None) } } diff --git a/src/lib.rs b/src/lib.rs index 5310dfc..d110c28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,12 +25,13 @@ pub mod ioregs; pub use interrupt::Interrupt; pub mod gba; pub use gba::GameBoyAdvance; +pub mod dma; pub mod lcd; pub mod palette; pub mod util; pub trait EmuIoDev { - fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> Option; + fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> (usize, Option); } #[derive(Debug)]