Newer
Older
use crate::warnln;
pub enum DmaMode {
General = 0x00,
HBlank = 0x01,
}
pub struct Dma {
source: u16,
destination: u16,
impl Dma {
pub fn new() -> Self {
Self {
source: 0x0,
destination: 0x0,
length: 0x0,
mode: DmaMode::General,
pub fn reset(&mut self) {
self.source = 0x0;
self.destination = 0x0;
self.length = 0x0;
self.mode = DmaMode::General;
pub fn clock(&mut self, _cycles: u16) {}
pub fn read(&mut self, addr: u16) -> u8 {
match addr {
// 0xFF55 — HDMA5: VRAM DMA length/mode/start (CGB only)
0xff45 => ((self.length >> 4) - 1) as u8 | ((self.active as u8) << 7),
_ => {
warnln!("Reading from unknown DMA location 0x{:04x}", addr);
0xff
}
}
}
pub fn write(&mut self, addr: u16, value: u8) {
match addr {
// 0xFF51 — HDMA1: VRAM DMA source high (CGB only)
0xff51 => self.source = (self.source & 0x00ff) | ((value as u16) << 8),
// 0xFF52 — HDMA2: VRAM DMA source low (CGB only)
0xff52 => self.source = (self.source & 0xff00) | ((value & 0xf0) as u16),
// 0xFF53 — HDMA3: VRAM DMA destination high (CGB only)
0xff53 => self.destination = (self.destination & 0x00ff) | ((value as u16) << 8),
// 0xFF54 — HDMA4: VRAM DMA destination low (CGB only)
0xff54 => self.destination = (self.destination & 0xff00) | ((value & 0xf0) as u16),
// 0xFF55 — HDMA5: VRAM DMA length/mode/start (CGB only)
0xff55 => {
self.length = (((value & 0x7f) + 0x1) as u16) << 4;
self.mode = match (value & 80) >> 7 {
0 => DmaMode::General,
1 => DmaMode::HBlank,
_ => DmaMode::General,
};
}
_ => warnln!("Writing to unknown DMA location 0x{:04x}", addr),
}
}
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
pub fn source(&self) -> u16 {
self.source
}
pub fn set_source(&mut self, value: u16) {
self.source = value;
}
pub fn destination(&self) -> u16 {
self.destination
}
pub fn set_destination(&mut self, value: u16) {
self.destination = value;
}
pub fn length(&self) -> u16 {
self.length
}
pub fn set_length(&mut self, value: u16) {
self.length = value;
}
pub fn mode(&self) -> DmaMode {
self.mode
}
pub fn set_mode(&mut self, value: DmaMode) {
self.mode = value;
}
pub fn active(&self) -> bool {
self.active
}
pub fn set_active(&mut self, value: bool) {
self.active = value;
}
}
impl Default for Dma {
fn default() -> Self {
Self::new()
}
}
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#[cfg(test)]
mod tests {
use crate::dma::{Dma, DmaMode};
#[test]
fn test_dma_default() {
let dma = Dma::default();
assert_eq!(dma.active, false);
}
#[test]
fn test_dma_reset() {
let mut dma = Dma::new();
dma.source = 0x1234;
dma.destination = 0x5678;
dma.length = 0x9abc;
dma.mode = DmaMode::HBlank;
dma.active = true;
dma.reset();
assert_eq!(dma.source, 0x0);
assert_eq!(dma.destination, 0x0);
assert_eq!(dma.length, 0x0);
assert_eq!(dma.mode, DmaMode::General);
assert_eq!(dma.active, false);
}
#[test]
fn test_dma_set_active() {
let mut dma = Dma::new();
dma.set_active(true);
assert_eq!(dma.active, true);
}
}