Begin modeling DMA

Former-commit-id: 83ab601e70666f76ed3ebfb22340c6b1868af3ac
This commit is contained in:
Michel Heily 2019-07-07 01:33:54 +03:00
parent c2685c14d7
commit c92bde54a1
4 changed files with 113 additions and 13 deletions

74
src/dma.rs Normal file
View file

@ -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<Interrupt>) {
// TODO
(0, None)
}
}

View file

@ -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<DecodedInstruction> {
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
}

View file

@ -96,15 +96,13 @@ impl Lcd {
}
impl EmuIoDev for Lcd {
fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> Option<Interrupt> {
fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> (usize, Option<Interrupt>) {
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)
}
}

View file

@ -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<Interrupt>;
fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> (usize, Option<Interrupt>);
}
#[derive(Debug)]