From 965db0e0cb7fbfbd9a1d8c5391c76cb270e3c14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sat, 6 May 2023 09:54:49 +0100 Subject: [PATCH] chore: initial support for the DMA controller This is only a structure change and no real DMA implementation has been done. --- src/cpu.rs | 11 +++++++++++ src/dma.rs | 17 +++++++++++++++++ src/gb.rs | 38 +++++++++++++++++++++++++++++++++++++- src/lib.rs | 1 + src/mmu.rs | 16 ++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/dma.rs diff --git a/src/cpu.rs b/src/cpu.rs index ba60309d..39bb3c01 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -3,6 +3,7 @@ use std::{cell::RefCell, rc::Rc}; use crate::{ apu::Apu, debugln, + dma::Dma, gb::GameBoyConfig, inst::{EXTENDED, INSTRUCTIONS}, mmu::Mmu, @@ -334,6 +335,16 @@ impl Cpu { self.mmu_i().apu_i() } + #[inline(always)] + pub fn dma(&mut self) -> &mut Dma { + self.mmu().dma() + } + + #[inline(always)] + pub fn dma_i(&self) -> &Dma { + self.mmu_i().dma_i() + } + #[inline(always)] pub fn pad(&mut self) -> &mut Pad { self.mmu().pad() diff --git a/src/dma.rs b/src/dma.rs new file mode 100644 index 00000000..9f6d014c --- /dev/null +++ b/src/dma.rs @@ -0,0 +1,17 @@ +pub struct Dma {} + +impl Dma { + pub fn new() -> Self { + Self {} + } + + pub fn reset(&mut self) {} + + pub fn clock(&mut self, cycles: u8) {} +} + +impl Default for Dma { + fn default() -> Self { + Self::new() + } +} diff --git a/src/gb.rs b/src/gb.rs index 9be41c40..9de814b6 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -10,6 +10,7 @@ use crate::{ cpu::Cpu, data::{BootRom, CGB_BOOT, DMG_BOOT, DMG_BOOTIX, MGB_BOOTIX, SGB_BOOT}, devices::{printer::PrinterDevice, stdout::StdoutDevice}, + dma::Dma, gen::{COMPILATION_DATE, COMPILATION_TIME, COMPILER, COMPILER_VERSION, VERSION}, mmu::Mmu, pad::{Pad, PadKey}, @@ -133,6 +134,9 @@ pub struct GameBoyConfig { /// If the APU is enabled, it will be clocked. apu_enabled: bool, + /// if the DMA is enabled, it will be clocked. + dma_enabled: bool, + /// If the timer is enabled, it will be clocked. timer_enabled: bool, @@ -186,6 +190,14 @@ impl GameBoyConfig { self.apu_enabled = value; } + pub fn dma_enabled(&self) -> bool { + self.dma_enabled + } + + pub fn set_dma_enabled(&mut self, value: bool) { + self.dma_enabled = value; + } + pub fn timer_enabled(&self) -> bool { self.timer_enabled } @@ -217,6 +229,7 @@ impl Default for GameBoyConfig { mode: GameBoyMode::Dmg, ppu_enabled: true, apu_enabled: true, + dma_enabled: true, timer_enabled: true, serial_enabled: true, clock_freq: GameBoy::CPU_FREQ, @@ -246,6 +259,11 @@ pub struct GameBoy { /// kept for performance reasons. apu_enabled: bool, + /// If the DMA is enabled, it will be clocked. + /// This is a clone of the configuration value + /// kept for performance reasons. + dma_enabled: bool, + /// If the timer is enabled, it will be clocked. /// This is a clone of the configuration value /// kept for performance reasons. @@ -314,6 +332,7 @@ impl GameBoy { mode, ppu_enabled: true, apu_enabled: true, + dma_enabled: true, timer_enabled: true, serial_enabled: true, clock_freq: GameBoy::CPU_FREQ, @@ -321,16 +340,18 @@ impl GameBoy { let ppu = Ppu::new(mode, gbc.clone()); let apu = Apu::default(); + let dma = Dma::default(); let pad = Pad::default(); let timer = Timer::default(); let serial = Serial::default(); - let mmu = Mmu::new(ppu, apu, pad, timer, serial, mode, gbc.clone()); + let mmu = Mmu::new(ppu, apu, dma, pad, timer, serial, mode, gbc.clone()); let cpu = Cpu::new(mmu, gbc.clone()); Self { mode, ppu_enabled: true, apu_enabled: true, + dma_enabled: true, timer_enabled: true, serial_enabled: true, clock_freq: GameBoy::CPU_FREQ, @@ -356,6 +377,9 @@ impl GameBoy { if self.apu_enabled { self.apu_clock(cycles); } + if self.dma_enabled { + self.dma_clock(cycles); + } if self.timer_enabled { self.timer_clock(cycles); } @@ -385,6 +409,10 @@ impl GameBoy { self.apu().clock(cycles) } + pub fn dma_clock(&mut self, cycles: u8) { + self.dma().clock(cycles) + } + pub fn timer_clock(&mut self, cycles: u8) { self.timer().clock(cycles) } @@ -735,6 +763,14 @@ impl GameBoy { self.cpu.apu_i() } + pub fn dma(&mut self) -> &mut Dma { + self.cpu.dma() + } + + pub fn dma_i(&self) -> &Dma { + self.cpu.dma_i() + } + pub fn pad(&mut self) -> &mut Pad { self.cpu.pad() } diff --git a/src/lib.rs b/src/lib.rs index 80f4f5b8..d25f5ac6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ pub mod apu; pub mod cpu; pub mod data; pub mod devices; +pub mod dma; pub mod gb; pub mod gen; pub mod inst; diff --git a/src/mmu.rs b/src/mmu.rs index c6a0eea1..6b7ebe86 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -3,6 +3,7 @@ use std::{cell::RefCell, rc::Rc}; use crate::{ apu::Apu, debugln, + dma::Dma, gb::{GameBoyConfig, GameBoyMode, GameBoySpeed}, pad::Pad, ppu::Ppu, @@ -44,6 +45,11 @@ pub struct Mmu { /// some of the access operations. apu: Apu, + /// Reference to the DMA (Direct Memory Access) controller that is going + /// to be used for quick and CPU offloaded memory transfers. + /// There are multiple execution modes for the DMA. + dma: Dma, + /// Reference to the Gamepad structure that is going to control /// the I/O access to this device. pad: Pad, @@ -95,6 +101,7 @@ impl Mmu { pub fn new( ppu: Ppu, apu: Apu, + dma: Dma, pad: Pad, timer: Timer, serial: Serial, @@ -104,6 +111,7 @@ impl Mmu { Self { ppu, apu, + dma, pad, timer, serial, @@ -161,6 +169,14 @@ impl Mmu { &self.apu } + pub fn dma(&mut self) -> &mut Dma { + &mut self.dma + } + + pub fn dma_i(&self) -> &Dma { + &self.dma + } + pub fn pad(&mut self) -> &mut Pad { &mut self.pad } -- GitLab