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
|
/// 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};
|
use super::{EmuIoDev, GBAResult};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -13,6 +16,10 @@ pub struct GameBoyAdvance {
|
||||||
|
|
||||||
// io devices
|
// io devices
|
||||||
lcd: Lcd,
|
lcd: Lcd,
|
||||||
|
dma0: DmaChannel,
|
||||||
|
dma1: DmaChannel,
|
||||||
|
dma2: DmaChannel,
|
||||||
|
dma3: DmaChannel,
|
||||||
|
|
||||||
post_bool_flags: bool,
|
post_bool_flags: bool,
|
||||||
}
|
}
|
||||||
|
@ -26,6 +33,10 @@ impl GameBoyAdvance {
|
||||||
sysbus: sysbus,
|
sysbus: sysbus,
|
||||||
|
|
||||||
lcd: Lcd::new(),
|
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,
|
post_bool_flags: false,
|
||||||
}
|
}
|
||||||
|
@ -34,9 +45,25 @@ impl GameBoyAdvance {
|
||||||
pub fn step(&mut self) -> GBAResult<DecodedInstruction> {
|
pub fn step(&mut self) -> GBAResult<DecodedInstruction> {
|
||||||
let previous_cycles = self.cpu.cycles;
|
let previous_cycles = self.cpu.cycles;
|
||||||
let decoded = self.cpu.step_one(&mut self.sysbus)?;
|
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
|
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 {
|
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;
|
self.cycles += cycles;
|
||||||
|
|
||||||
let mut result = None;
|
// let mut dispcnt = DisplayControl::from(sysbus.ioregs.read_reg(REG_DISPCNT));
|
||||||
let mut dispcnt = DisplayControl::from(sysbus.ioregs.read_reg(REG_DISPCNT));
|
// let mut dispstat = DisplayStatus::from(sysbus.ioregs.read_reg(REG_DISPSTAT));
|
||||||
let mut dispstat = DisplayStatus::from(sysbus.ioregs.read_reg(REG_DISPSTAT));
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
(0, None)
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,13 @@ pub mod ioregs;
|
||||||
pub use interrupt::Interrupt;
|
pub use interrupt::Interrupt;
|
||||||
pub mod gba;
|
pub mod gba;
|
||||||
pub use gba::GameBoyAdvance;
|
pub use gba::GameBoyAdvance;
|
||||||
|
pub mod dma;
|
||||||
pub mod lcd;
|
pub mod lcd;
|
||||||
pub mod palette;
|
pub mod palette;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub trait EmuIoDev {
|
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)]
|
#[derive(Debug)]
|
||||||
|
|
Reference in a new issue