Add VRAM DMA; Add basic timer support

This commit is contained in:
Kevin Hamacher 2016-05-28 23:57:14 +02:00
parent 6d675616f1
commit 44c8b2e7d8
3 changed files with 53 additions and 6 deletions

View File

@ -1050,7 +1050,9 @@ impl CPU {
// ADC
0x88 ... 0x8F => {
let reg_id = (instruction - 0x88) as usize;
println!("ADC {}", REG_NAMES[reg_id]);
if self.debug {
println!("ADC {}", REG_NAMES[reg_id]);
}
let old = self.regs[REG_A];
let mut new = old.wrapping_add(self.get_8bit_reg(reg_id));

View File

@ -27,7 +27,10 @@ pub struct Interconnect {
serial: serial::Serial,
timer: timer::Timer,
vram_dma_source_high: u8,
vram_dma_source_low: u8,
vram_dma_destination_high: u8,
vram_dma_destination_low: u8,
}
impl Interconnect {
@ -37,7 +40,7 @@ impl Interconnect {
cartridge: cartridge::Cartridge::new(rom),
ram: vec![0; WRAM_SIZE].into_boxed_slice(),
hiram: vec![0; HIRAM_SIZE].into_boxed_slice(),
wram_bank: 0,
wram_bank: 1,
sound: sound::Sound::new(),
display: display::Display::new(),
// Refactor those
@ -48,12 +51,17 @@ impl Interconnect {
timer: timer::Timer::new(),
serial: serial::Serial::new(),
vram_dma_source_high: 0,
vram_dma_source_low: 0,
vram_dma_destination_high: 0,
vram_dma_destination_low: 0,
}
}
// Somehow we need different timers for this.
pub fn tick(&mut self, cycles: u8) {
self.display.tick(cycles as u16 * 4);
self.timer.tick(cycles as u16 * 4);
if self.display.vblank_interrupt() {
self.interrupt_request_flags |= INTERRUPT_DISPLAY_VBLANK;
@ -108,6 +116,14 @@ impl Interconnect {
0xFF50 => {
self.disable_bootrom
},
0xFF51 => self.vram_dma_source_high,
0xFF52 => self.vram_dma_source_low,
0xFF53 => self.vram_dma_destination_high,
0xFF54 => self.vram_dma_destination_low,
0xFF55 => {
println!("Read from 0xFF55 (DMA length/mode/start) not fully supported");
0xFF
}
0xFF56 => {
self.infrared_com_port
},
@ -163,7 +179,7 @@ impl Interconnect {
self.display.write_byte(addr, val);
},
0xFF46 => {
println!("DMA transfer: ");
println!("OAM DMA transfer: ");
for x in 0x00 .. 0x9F {
let dma_b = self.read_byte(((val as u16) << 8) | x);
self.write_byte(0xFE00 | x, dma_b);
@ -175,10 +191,30 @@ impl Interconnect {
println!("Disabling boot rom.");
self.disable_bootrom = val;
},
0xFF51 => self.vram_dma_source_high = val,
0xFF52 => self.vram_dma_source_low = val,
0xFF53 => self.vram_dma_destination_high = val,
0xFF54 => self.vram_dma_destination_low = val,
0xFF55 => {
let src: u16 = ((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16;
let dst: u16 = ((self.vram_dma_destination_high as u16) << 8) | self.vram_dma_destination_low as u16;
println!("VRAM DMA transfer from {:04X} to {:04X}; {:02X}", src, dst, val);
let len: u16 = ((val & 0x7F) + 1) as u16 * 0x10 - 1;
for i in 0..len {
let v = self.read_byte(src.wrapping_add(i));
self.write_byte(dst.wrapping_add(i), v);
}
}
0xFF56 => {
self.infrared_com_port = val;
},
0xFF70 => self.wram_bank = val,
0xFF70 => {
println!("Set wram bank to {:02X}", val);
if val > 7 {
panic!("R u sure this is correct?");
}
self.wram_bank = val;
}
0xFF80 ... 0xFFFE => {
self.hiram[(addr - 0xFF80) as usize] = val;
},

View File

@ -3,7 +3,8 @@ pub struct Timer {
tima: u8,
tma: u8,
tac: u8,
timer_interrupt: bool
timer_interrupt: bool,
ctr: u16,
}
impl Timer {
@ -11,6 +12,14 @@ impl Timer {
Timer::default()
}
pub fn tick(&mut self, ticks: u16) {
self.ctr += ticks;
if self.ctr > 0x1000 {
self.ctr = 0;
self.timer_interrupt = true;
}
}
pub fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0xFF05 => self.tima = val,