Begin modeling DMA
Former-commit-id: 83ab601e70666f76ed3ebfb22340c6b1868af3ac
This commit is contained in:
parent
c2685c14d7
commit
c92bde54a1
74
src/dma.rs
Normal file
74
src/dma.rs
Normal 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)
|
||||
}
|
||||
}
|
39
src/gba.rs
39
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<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
|
||||
}
|
||||
|
|
10
src/lcd.rs
10
src/lcd.rs
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
Reference in a new issue