diff --git a/src/core/dma.rs b/src/core/dma.rs index 4bf1094..9999ba6 100644 --- a/src/core/dma.rs +++ b/src/core/dma.rs @@ -1,74 +1,210 @@ -// use super::arm7tdmi::{Addr, Bus}; -// use super::ioregs::consts::*; -// use super::sysbus::SysBus; -// use super::{EmuIoDev, Interrupt}; +use std::collections::VecDeque; -// #[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 */ -// } +use super::arm7tdmi::{Addr, Bus}; +use super::sysbus::SysBus; +use super::{Interrupt, IrqBitmask, SyncedIoDevice}; -// #[derive(Debug, Primitive)] -// enum DmaAddrControl { -// Increment = 0, -// Decrement = 1, -// Fixed = 2, -// IncrementReloadProhibited = 3, -// } +use num::FromPrimitive; -// #[derive(Debug)] -// enum DmaTransferType { -// Xfer16bit, -// Xfer32bit, -// } +#[derive(Debug)] +enum DmaTransferType { + Xfer16bit, + Xfer32bit, +} -// #[derive(Debug, Primitive)] -// enum DmaStartTiming { -// Immediately = 0, -// VBlank = 1, -// HBlank = 2, -// Special = 3, -// } +#[derive(Debug)] +pub struct DmaChannel { + id: usize, -// #[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, -// } + pub src: u32, + pub dst: u32, + pub wc: u32, + pub ctrl: DmaChannelCtrl, -// impl DmaChannel { -// pub fn new(src_ioreg: Addr, dst_ioreg: Addr, wc_ioreg: Addr) -> DmaChannel { -// DmaChannel { -// src_ioreg, -// dst_ioreg, -// wc_ioreg, -// } -// } + running: bool, + cycles: usize, + start_cycles: usize, + irq: Interrupt, +} -// // fn src_addr(&self, sysbus: &SysBus) -> Addr { -// // sysbus.ioregs.read_32(self.src_ioreg - IO_BASE) as Addr -// // } +impl DmaChannel { + pub fn new(id: usize) -> DmaChannel { + if id > 3 { + panic!("invalid dma id {}", id); + } + DmaChannel { + id: id, + irq: Interrupt::from_usize(id + 8).unwrap(), + running: false, + src: 0, + dst: 0, + wc: 0, + ctrl: DmaChannelCtrl(0), + cycles: 0, + start_cycles: 0, + } + } -// // fn dst_addr(&self, sysbus: &SysBus) -> Addr { -// // sysbus.ioregs.read_32(self.dst_ioreg - IO_BASE) as Addr -// // } + pub fn is_running(&self) -> bool { + self.running + } -// // fn word_count(&self, sysbus: &SysBus) -> usize { -// // sysbus.ioregs.read_reg(self.wc_ioreg) as usize -// // } -// } + pub fn write_src_low(&mut self, low: u16) { + let src = self.src; + self.src = (src & 0xffff0000) | (low as u32); + } -// impl EmuIoDev for DmaChannel { -// fn step(&mut self, cycles: usize, sysbus: &mut SysBus) -> (usize, Option) { -// // TODO -// (0, None) -// } -// } + pub fn write_src_high(&mut self, high: u16) { + let src = self.src; + let high = high as u32; + self.src = (src & 0xffff) | (high << 16); + } + + pub fn write_dst_low(&mut self, low: u16) { + let dst = self.dst; + self.dst = (dst & 0xffff0000) | (low as u32); + } + + pub fn write_dst_high(&mut self, high: u16) { + let dst = self.dst; + let high = high as u32; + self.dst = (dst & 0xffff) | (high << 16); + } + + pub fn write_word_count(&mut self, value: u16) { + self.wc = value as u32; + } + + pub fn write_dma_ctrl(&mut self, value: u16) -> bool { + let ctrl = DmaChannelCtrl(value); + let mut start_immediately = false; + if ctrl.is_enabled() { + self.start_cycles = self.cycles; + self.running = true; + if ctrl.timing() == 0 { + start_immediately = true; + } + } + self.ctrl = ctrl; + return start_immediately; + } + + fn xfer(&mut self, sb: &mut SysBus, irqs: &mut IrqBitmask) { + let word_size = if self.ctrl.is_32bit() { 4 } else { 2 }; + let dst_rld = self.dst; + for word in 0..self.wc { + if word_size == 4 { + let w = sb.read_32(self.src); + sb.write_32(self.dst, w) + } else { + let hw = sb.read_16(self.src); + // println!("src {:x} dst {:x}", self.src, self.dst); + sb.write_16(self.dst, hw) + } + match self.ctrl.src_adj() { + /* Increment */ 0 => self.src += word_size, + /* Decrement */ 1 => self.src -= word_size, + /* Fixed */ 2 => {} + _ => panic!("forbidden DMA source address adjustment"), + } + match self.ctrl.dst_adj() { + /* Increment[+Reload] */ 0 | 3 => self.dst += word_size, + /* Decrement */ 1 => self.dst -= word_size, + /* Fixed */ 2 => {} + _ => panic!("forbidden DMA dest address adjustment"), + } + } + if self.ctrl.is_triggering_irq() { + irqs.add_irq(self.irq); + } + if self.ctrl.repeat() { + self.start_cycles = self.cycles; + /* reload */ + if 3 == self.ctrl.dst_adj() { + self.dst = dst_rld; + } + } else { + self.running = false; + self.ctrl.set_enabled(false); + } + } +} + +#[derive(Debug)] +pub struct DmaController { + pub channels: [DmaChannel; 4], + xfers_queue: VecDeque, + cycles: usize, +} + +impl DmaController { + pub fn new() -> DmaController { + DmaController { + channels: [ + DmaChannel::new(0), + DmaChannel::new(1), + DmaChannel::new(2), + DmaChannel::new(3), + ], + xfers_queue: VecDeque::new(), + cycles: 0, + } + } + + pub fn perform_work(&mut self, sb: &mut SysBus, irqs: &mut IrqBitmask) -> bool { + if self.xfers_queue.is_empty() { + false + } else { + while let Some(id) = self.xfers_queue.pop_front() { + self.channels[id].xfer(sb, irqs) + } + true + } + } + + pub fn write_16(&mut self, channel_id: usize, ofs: u32, value: u16) { + match ofs { + 0 => self.channels[channel_id].write_src_low(value), + 2 => self.channels[channel_id].write_src_high(value), + 4 => self.channels[channel_id].write_dst_low(value), + 6 => self.channels[channel_id].write_dst_high(value), + 8 => self.channels[channel_id].write_word_count(value), + 10 => { + if self.channels[channel_id].write_dma_ctrl(value) { + self.xfers_queue.push_back(channel_id) + } + } + _ => panic!("Invalid dma offset"), + } + } + + pub fn notify_vblank(&mut self) { + for i in 0..4 { + if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == 1 { + self.xfers_queue.push_back(i); + } + } + } + + pub fn notify_hblank(&mut self) { + for i in 0..4 { + if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == 2 { + self.xfers_queue.push_back(i); + } + } + } +} + +bitfield! { + #[derive(Default)] + pub struct DmaChannelCtrl(u16); + impl Debug; + u16; + dst_adj, _ : 6, 5; + src_adj, _ : 8, 7; + repeat, _ : 9; + is_32bit, _: 10; + timing, _: 13, 12; + is_triggering_irq, _: 14; + is_enabled, set_enabled: 15; +} diff --git a/src/core/gba.rs b/src/core/gba.rs index de0766d..12e4a52 100644 --- a/src/core/gba.rs +++ b/src/core/gba.rs @@ -1,42 +1,19 @@ /// Struct containing everything -/// -use std::cell::RefCell; -use std::rc::Rc; - use super::arm7tdmi::{exception::Exception, Core, DecodedInstruction}; use super::cartridge::Cartridge; use super::gpu::*; use super::interrupt::*; -use super::ioregs::IoRegs; +use super::iodev::*; use super::sysbus::SysBus; -use super::timer::Timers; + use super::GBAResult; use super::SyncedIoDevice; use crate::backend::*; -#[derive(Debug)] -pub struct IoDevices { - pub intc: InterruptController, - pub gpu: Gpu, - pub timers: Timers, -} - -impl IoDevices { - pub fn new() -> IoDevices { - IoDevices { - intc: InterruptController::new(), - gpu: Gpu::new(), - timers: Timers::new(), - } - } -} - pub struct GameBoyAdvance { - backend: Box, + backend: Box, pub cpu: Core, - pub sysbus: SysBus, - - pub io: Rc>, + pub sysbus: Box, } impl GameBoyAdvance { @@ -44,51 +21,63 @@ impl GameBoyAdvance { cpu: Core, bios_rom: Vec, gamepak: Cartridge, - backend: Box, + backend: Box, ) -> GameBoyAdvance { - let io = Rc::new(RefCell::new(IoDevices::new())); - - let ioregs = IoRegs::new(io.clone()); - let sysbus = SysBus::new(io.clone(), bios_rom, gamepak, ioregs); - + let io = IoDevices::new(); GameBoyAdvance { backend: backend, cpu: cpu, - sysbus: sysbus, - - io: io.clone(), + sysbus: Box::new(SysBus::new(io, bios_rom, gamepak)), } } pub fn frame(&mut self) { self.update_key_state(); - while self.io.borrow().gpu.state != GpuState::VBlank { - let cycles = self.emulate_cpu(); - self.emulate_peripherals(cycles); + while self.sysbus.io.gpu.state != GpuState::VBlank { + self.step_new(); } - self.backend.render(self.io.borrow().gpu.get_framebuffer()); - while self.io.borrow().gpu.state == GpuState::VBlank { - let cycles = self.emulate_cpu(); - self.emulate_peripherals(cycles); + self.backend.render(self.sysbus.io.gpu.get_framebuffer()); + while self.sysbus.io.gpu.state == GpuState::VBlank { + self.step_new(); } } fn update_key_state(&mut self) { - self.sysbus.ioregs.keyinput = self.backend.get_key_state(); + self.sysbus.io.keyinput = self.backend.get_key_state(); } - pub fn emulate_cpu(&mut self) -> usize { + // TODO deprecate + pub fn step(&mut self) -> GBAResult { let previous_cycles = self.cpu.cycles; - self.cpu.step(&mut self.sysbus).unwrap(); - self.cpu.cycles - previous_cycles + let executed_insn = self.cpu.step_one(&mut self.sysbus)?; + let cycles = self.cpu.cycles - previous_cycles; + Ok(executed_insn) } - pub fn emulate_peripherals(&mut self, cycles: usize) { + pub fn step_new(&mut self) { let mut irqs = IrqBitmask(0); - let mut io = self.io.borrow_mut(); + let previous_cycles = self.cpu.cycles; + + // // I hate myself for doing this, but rust left me no choice. + let io = unsafe { + let ptr = &mut *self.sysbus as *mut SysBus; + &mut (*ptr).io as &mut IoDevices + }; + + if !io.dmac.perform_work(&mut self.sysbus, &mut irqs) { + self.cpu.step(&mut self.sysbus).unwrap(); + } + + let cycles = self.cpu.cycles - previous_cycles; io.timers.step(cycles, &mut self.sysbus, &mut irqs); - io.gpu.step(cycles, &mut self.sysbus, &mut irqs); + if let Some(new_gpu_state) = io.gpu.step(cycles, &mut self.sysbus, &mut irqs) { + match new_gpu_state { + GpuState::VBlank => io.dmac.notify_vblank(), + GpuState::HBlank => io.dmac.notify_hblank(), + _ => {} + } + } if !self.cpu.cpsr.irq_disabled() { io.intc.request_irqs(irqs); @@ -97,18 +86,4 @@ impl GameBoyAdvance { } } } - - pub fn step(&mut self) -> GBAResult { - let previous_cycles = self.cpu.cycles; - let executed_insn = self.cpu.step_one(&mut self.sysbus)?; - let cycles = self.cpu.cycles - previous_cycles; - - self.emulate_peripherals(cycles); - - if self.io.borrow().gpu.state == GpuState::VBlank { - self.backend.render(self.io.borrow().gpu.get_framebuffer()); - } - - Ok(executed_insn) - } } diff --git a/src/core/gpu/mod.rs b/src/core/gpu/mod.rs index a69f378..742b213 100644 --- a/src/core/gpu/mod.rs +++ b/src/core/gpu/mod.rs @@ -361,7 +361,7 @@ impl Gpu { } fn scanline_aff_bg(&mut self, bg: usize, sb: &mut SysBus) { - // TODO + // TODO } fn scanline_mode3(&mut self, bg: usize, sb: &mut SysBus) { @@ -444,10 +444,14 @@ impl Gpu { pub fn get_framebuffer(&self) -> &[u32] { &self.frame_buffer.0 } -} -impl SyncedIoDevice for Gpu { - fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask) { + // Returns the new gpu state + pub fn step( + &mut self, + cycles: usize, + sb: &mut SysBus, + irqs: &mut IrqBitmask, + ) -> Option { self.cycles += cycles; if self.dispstat.vcount_setting() != 0 { @@ -472,12 +476,14 @@ impl SyncedIoDevice for Gpu { irqs.set_LCD_HBlank(true); }; self.state = HBlank; + return Some(HBlank); } else { self.dispstat.set_vblank(true); if self.dispstat.vblank_irq_enable() { irqs.set_LCD_VBlank(true); }; self.state = VBlank; + return Some(VBlank); }; } } @@ -487,6 +493,7 @@ impl SyncedIoDevice for Gpu { self.state = HDraw; self.dispstat.set_hblank(false); self.dispstat.set_vblank(false); + return Some(HDraw); } } VBlank => { @@ -497,9 +504,12 @@ impl SyncedIoDevice for Gpu { self.dispstat.set_vblank(false); self.current_scanline = 0; self.render_scanline(sb); + return Some(HDraw); } } } + + return None; } } diff --git a/src/core/ioregs.rs b/src/core/iodev.rs similarity index 92% rename from src/core/ioregs.rs rename to src/core/iodev.rs index 6b49ede..b20f4fd 100644 --- a/src/core/ioregs.rs +++ b/src/core/iodev.rs @@ -1,28 +1,35 @@ -use std::cell::RefCell; -use std::rc::Rc; - use super::arm7tdmi::{Addr, Bus}; -use super::gba::IoDevices; +use super::dma::DmaController; use super::gpu::regs::WindowFlags; +use super::gpu::*; +use super::interrupt::InterruptController; use super::keypad; use super::sysbus::BoxedMemory; +use super::timer::Timers; use consts::*; #[derive(Debug)] -pub struct IoRegs { - mem: BoxedMemory, - pub io: Rc>, +pub struct IoDevices { + pub intc: InterruptController, + pub gpu: Gpu, + pub timers: Timers, + pub dmac: DmaController, pub keyinput: u16, pub post_boot_flag: bool, pub waitcnt: WaitControl, // TODO also implement 4000800 + + mem: BoxedMemory, } -impl IoRegs { - pub fn new(io: Rc>) -> IoRegs { - IoRegs { +impl IoDevices { + pub fn new() -> IoDevices { + IoDevices { + gpu: Gpu::new(), + timers: Timers::new(), + dmac: DmaController::new(), + intc: InterruptController::new(), mem: BoxedMemory::new(vec![0; 0x800].into_boxed_slice()), - io: io, post_boot_flag: false, keyinput: keypad::KEYINPUT_ALL_RELEASED, waitcnt: WaitControl(0), @@ -30,14 +37,15 @@ impl IoRegs { } } -impl Bus for IoRegs { +impl Bus for IoDevices { fn read_32(&self, addr: Addr) -> u32 { (self.read_16(addr + 2) as u32) << 16 | (self.read_16(addr) as u32) } fn read_16(&self, addr: Addr) -> u16 { - let io = self.io.borrow(); - match addr + IO_BASE { + let io = self; + let io_addr = addr + IO_BASE; + match io_addr { REG_DISPCNT => io.gpu.dispcnt.0, REG_DISPSTAT => io.gpu.dispstat.0, REG_VCOUNT => io.gpu.current_scanline as u16, @@ -71,12 +79,24 @@ impl Bus for IoRegs { REG_TM3CNT_L => io.timers[3].timer_data, REG_TM3CNT_H => io.timers[3].timer_ctl.0, - REG_WAITCNT => self.waitcnt.0, + REG_DMA0CNT_H => io.dmac.channels[0].ctrl.0, + REG_DMA1CNT_H => io.dmac.channels[1].ctrl.0, + REG_DMA2CNT_H => io.dmac.channels[2].ctrl.0, + REG_DMA3CNT_H => io.dmac.channels[3].ctrl.0, - REG_POSTFLG => self.post_boot_flag as u16, + REG_WAITCNT => io.waitcnt.0, + + REG_POSTFLG => io.post_boot_flag as u16, REG_HALTCNT => 0, - REG_KEYINPUT => self.keyinput as u16, - _ => self.mem.read_16(addr), + REG_KEYINPUT => io.keyinput as u16, + _ => { + println!( + "Unimplemented read from {:x} {}", + io_addr, + io_reg_string(io_addr) + ); + io.mem.read_16(addr) + } } } @@ -95,8 +115,10 @@ impl Bus for IoRegs { } fn write_16(&mut self, addr: Addr, value: u16) { - let mut io = self.io.borrow_mut(); - match addr + IO_BASE { + let mut io = self; + io.mem.write_16(addr, value); + let io_addr = addr + IO_BASE; + match io_addr { REG_DISPCNT => io.gpu.dispcnt.0 = value, REG_DISPSTAT => io.gpu.dispstat.0 |= value & !3, REG_BG0CNT => io.gpu.bg[0].bgcnt.0 = value, @@ -192,18 +214,22 @@ impl Bus for IoRegs { } REG_TM3CNT_H => io.timers[3].timer_ctl.0 = value, - REG_WAITCNT => self.waitcnt.0 = value, + DMA_BASE..=REG_DMA3CNT_H => { + let ofs = io_addr - DMA_BASE; + let channel_id = (ofs / 12) as usize; + io.dmac.write_16(channel_id, ofs % 12, value) + } - REG_POSTFLG => self.post_boot_flag = value != 0, + REG_WAITCNT => io.waitcnt.0 = value, + + REG_POSTFLG => io.post_boot_flag = value != 0, REG_HALTCNT => {} _ => { - let ioreg_addr = IO_BASE + addr; println!( "Unimplemented write to {:x} {}", - ioreg_addr, - io_reg_string(ioreg_addr) + io_addr, + io_reg_string(io_addr) ); - self.mem.write_16(addr, value); } } } @@ -301,6 +327,7 @@ pub mod consts { pub const REG_WAVE_RAM: Addr = 0x0400_0090; // Channel 3 Wave Pattern RAM (2 banks!!) pub const REG_FIFO_A: Addr = 0x0400_00A0; // 4 W Channel A FIFO, Data 0-3 pub const REG_FIFO_B: Addr = 0x0400_00A4; // 4 W Channel B FIFO, Data 0-3 + pub const DMA_BASE: Addr = REG_DMA0SAD; pub const REG_DMA0SAD: Addr = 0x0400_00B0; // 4 W DMA 0 Source Address pub const REG_DMA0DAD: Addr = 0x0400_00B4; // 4 W DMA 0 Destination Address pub const REG_DMA0CNT_L: Addr = 0x0400_00B8; // 2 W DMA 0 Word Count diff --git a/src/core/mod.rs b/src/core/mod.rs index 7ee97da..124debd 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -4,7 +4,7 @@ pub mod gpu; pub mod sysbus; pub use sysbus::SysBus; pub mod interrupt; -pub mod ioregs; +pub mod iodev; pub use interrupt::Interrupt; pub use interrupt::IrqBitmask; pub mod gba; diff --git a/src/core/sysbus.rs b/src/core/sysbus.rs index f1cf964..30a177e 100644 --- a/src/core/sysbus.rs +++ b/src/core/sysbus.rs @@ -1,15 +1,13 @@ -use std::cell::RefCell; use std::fmt; use std::ops::Add; -use std::rc::Rc; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use super::arm7tdmi::bus::Bus; use super::arm7tdmi::Addr; -use super::gba::IoDevices; +use super::cartridge::Cartridge; use super::gpu::GpuState; -use super::{cartridge::Cartridge, ioregs::IoRegs}; +use super::iodev::IoDevices; const VIDEO_RAM_SIZE: usize = 128 * 1024; const WORK_RAM_SIZE: usize = 256 * 1024; @@ -141,13 +139,11 @@ impl Bus for DummyBus { #[derive(Debug)] pub struct SysBus { - pub io: Rc>, + pub io: IoDevices, bios: BoxedMemory, onboard_work_ram: BoxedMemory, internal_work_ram: BoxedMemory, - /// Currently model the IOMem as regular buffer, later make it into something more sophisticated. - pub ioregs: IoRegs, pub palette_ram: BoxedMemory, pub vram: BoxedMemory, pub oam: BoxedMemory, @@ -156,19 +152,13 @@ pub struct SysBus { } impl SysBus { - pub fn new( - io: Rc>, - bios_rom: Vec, - gamepak: Cartridge, - ioregs: IoRegs, - ) -> SysBus { + pub fn new(io: IoDevices, bios_rom: Vec, gamepak: Cartridge) -> SysBus { SysBus { io: io, bios: BoxedMemory::new(bios_rom.into_boxed_slice()), onboard_work_ram: BoxedMemory::new(vec![0; WORK_RAM_SIZE].into_boxed_slice()), internal_work_ram: BoxedMemory::new(vec![0; INTERNAL_RAM_SIZE].into_boxed_slice()), - ioregs: ioregs, palette_ram: BoxedMemory::new(vec![0; PALETTE_RAM_SIZE].into_boxed_slice()), vram: BoxedMemory::new(vec![0; VIDEO_RAM_SIZE].into_boxed_slice()), oam: BoxedMemory::new(vec![0; OAM_SIZE].into_boxed_slice()), @@ -177,13 +167,13 @@ impl SysBus { } } - fn map(&self, addr: Addr) -> (&Bus, Addr) { + fn map(&self, addr: Addr) -> (&dyn Bus, Addr) { let ofs = addr & 0x00ff_ffff; match addr & 0xff000000 { BIOS_ADDR => (&self.bios, ofs), EWRAM_ADDR => (&self.onboard_work_ram, ofs & 0x3_ffff), IWRAM_ADDR => (&self.internal_work_ram, ofs & 0x7fff), - IOMEM_ADDR => (&self.ioregs, { + IOMEM_ADDR => (&self.io, { if ofs & 0xffff == 0x8000 { 0x800 } else { @@ -205,13 +195,13 @@ impl SysBus { } /// TODO proc-macro for generating this function - fn map_mut(&mut self, addr: Addr) -> (&mut Bus, Addr) { + fn map_mut(&mut self, addr: Addr) -> (&mut dyn Bus, Addr) { let ofs = addr & 0x00ff_ffff; match addr & 0xff000000 { BIOS_ADDR => (&mut self.bios, ofs), EWRAM_ADDR => (&mut self.onboard_work_ram, ofs & 0x3_ffff), IWRAM_ADDR => (&mut self.internal_work_ram, ofs & 0x7fff), - IOMEM_ADDR => (&mut self.ioregs, { + IOMEM_ADDR => (&mut self.io, { if ofs & 0xffff == 0x8000 { 0x800 } else { @@ -249,24 +239,24 @@ impl SysBus { MemoryAccessWidth::MemoryAccess32 => cycles += 2, _ => cycles += 1, } - if self.io.borrow().gpu.state == GpuState::HDraw { + if self.io.gpu.state == GpuState::HDraw { cycles += 1; } } GAMEPAK_WS0_ADDR => match access.0 { MemoryAccessType::NonSeq => match access.1 { MemoryAccessWidth::MemoryAccess32 => { - cycles += nonseq_cycles[self.ioregs.waitcnt.ws0_first_access() as usize]; - cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; + cycles += nonseq_cycles[self.io.waitcnt.ws0_first_access() as usize]; + cycles += seq_cycles[self.io.waitcnt.ws0_second_access() as usize]; } _ => { - cycles += nonseq_cycles[self.ioregs.waitcnt.ws0_first_access() as usize]; + cycles += nonseq_cycles[self.io.waitcnt.ws0_first_access() as usize]; } }, MemoryAccessType::Seq => { - cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; + cycles += seq_cycles[self.io.waitcnt.ws0_second_access() as usize]; if access.1 == MemoryAccessWidth::MemoryAccess32 { - cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; + cycles += seq_cycles[self.io.waitcnt.ws0_second_access() as usize]; } } }, diff --git a/src/debugger/command.rs b/src/debugger/command.rs index efd6266..f0fedb5 100644 --- a/src/debugger/command.rs +++ b/src/debugger/command.rs @@ -6,7 +6,7 @@ use crate::core::GBAError; use crate::disass::Disassembler; use super::palette_view::create_palette_view; -use super::tile_view::create_tile_view; +// use super::tile_view::create_tile_view; use super::{parser::Value, Debugger, DebuggerError, DebuggerResult}; use ansi_term::Colour; @@ -32,7 +32,7 @@ pub enum Command { AddBreakpoint(Addr), DelBreakpoint(Addr), PaletteView, - TileView(u32), + // TileView(u32), ClearBreakpoints, ListBreakpoints, Reset, @@ -44,7 +44,7 @@ impl Command { use Command::*; match *self { Info => println!("{}", debugger.gba.cpu), - DisplayInfo => println!("GPU: {:#?}", debugger.gba.io.borrow().gpu), + DisplayInfo => { /*println!("GPU: {:#?}", debugger.gba.sysbus.io.gpu)*/ } Step(count) => { for _ in 0..count { match debugger.gba.step() { @@ -154,7 +154,7 @@ impl Command { } } PaletteView => create_palette_view(&debugger.gba.sysbus.palette_ram.mem), - TileView(bg) => create_tile_view(bg, &debugger.gba), + // TileView(bg) => create_tile_view(bg, &debugger.gba), Reset => { println!("resetting cpu..."); debugger.gba.cpu.reset(&mut debugger.gba.sysbus); @@ -297,13 +297,13 @@ impl Debugger { ))), }, "palette-view" => Ok(Command::PaletteView), - "tiles" => { - if args.len() != 1 { - return Err(DebuggerError::InvalidCommandFormat("tile ".to_string())); - } - let bg = self.val_number(&args[0])?; - Ok(Command::TileView(bg)) - } + // "tiles" => { + // if args.len() != 1 { + // return Err(DebuggerError::InvalidCommandFormat("tile ".to_string())); + // } + // let bg = self.val_number(&args[0])?; + // Ok(Command::TileView(bg)) + // } "bl" => Ok(Command::ListBreakpoints), "q" | "quit" => Ok(Command::Quit), "r" | "reset" => Ok(Command::Reset), diff --git a/src/debugger/tile_view.rs b/src/debugger/tile_view.rs index 0060d24..e561e11 100644 --- a/src/debugger/tile_view.rs +++ b/src/debugger/tile_view.rs @@ -1,107 +1,107 @@ -use std::time::Duration; +// use std::time::Duration; -use sdl2::event::Event; -use sdl2::pixels::Color; -use sdl2::rect::{Point, Rect}; -use sdl2::render::Canvas; +// use sdl2::event::Event; +// use sdl2::pixels::Color; +// use sdl2::rect::{Point, Rect}; +// use sdl2::render::Canvas; -use crate::core::gba::GameBoyAdvance; -use crate::core::gpu::PixelFormat; +// use crate::core::gba::GameBoyAdvance; +// use crate::core::gpu::PixelFormat; -fn draw_tile( - gba: &GameBoyAdvance, - tile_addr: u32, - pixel_format: PixelFormat, - p: Point, - canvas: &mut Canvas, -) { - let io = gba.io.borrow(); - for y in 0..8 { - for x in 0..8 { - let index = io - .gpu - .read_pixel_index(&gba.sysbus, tile_addr, x, y, pixel_format); - let color = io.gpu.get_palette_color(&gba.sysbus, index as u32, 0, 0); - canvas.set_draw_color(Color::RGB( - (color.r() as u8) << 3, - (color.g() as u8) << 3, - (color.b() as u8) << 3, - )); - canvas.draw_point(p.offset(x as i32, y as i32)).unwrap(); - } - } -} +// fn draw_tile( +// gba: &GameBoyAdvance, +// tile_addr: u32, +// pixel_format: PixelFormat, +// p: Point, +// canvas: &mut Canvas, +// ) { +// let io = &mut gba.sysbus.io; +// for y in 0..8 { +// for x in 0..8 { +// let index = io +// .gpu +// .read_pixel_index(&gba.sysbus, tile_addr, x, y, pixel_format); +// let color = io.gpu.get_palette_color(&gba.sysbus, index as u32, 0, 0); +// canvas.set_draw_color(Color::RGB( +// (color.r() as u8) << 3, +// (color.g() as u8) << 3, +// (color.b() as u8) << 3, +// )); +// canvas.draw_point(p.offset(x as i32, y as i32)).unwrap(); +// } +// } +// } -const TILESET_INITIAL_X: i32 = 0x20; -const TILESET_INITIAL_Y: i32 = 0x20; +// const TILESET_INITIAL_X: i32 = 0x20; +// const TILESET_INITIAL_Y: i32 = 0x20; -pub fn create_tile_view(bg: u32, gba: &GameBoyAdvance) { - let sdl_context = sdl2::init().unwrap(); - let video_subsystem = sdl_context.video().unwrap(); +// pub fn create_tile_view(bg: u32, gba: &GameBoyAdvance) { +// let sdl_context = sdl2::init().unwrap(); +// let video_subsystem = sdl_context.video().unwrap(); - let window = video_subsystem - .window("PaletteView", 512, 512) - .position_centered() - .build() - .unwrap(); +// let window = video_subsystem +// .window("PaletteView", 512, 512) +// .position_centered() +// .build() +// .unwrap(); - let mut canvas = window.into_canvas().build().unwrap(); +// let mut canvas = window.into_canvas().build().unwrap(); - let bgcnt = gba.io.borrow().gpu.bg[bg as usize].bgcnt.clone(); +// let bgcnt = gba.sysbus.io.gpu.bg[bg as usize].bgcnt.clone(); - let (tile_size, pixel_format) = bgcnt.tile_format(); - let tileset_addr = bgcnt.char_block(); - let tilemap_addr = bgcnt.screen_block(); - let tiles_per_row = 32; - let num_tiles = 0x4000 / tile_size; - println!("tileset: {:#x}, tilemap: {:#x}", tileset_addr, tilemap_addr); +// let (tile_size, pixel_format) = bgcnt.tile_format(); +// let tileset_addr = bgcnt.char_block(); +// let tilemap_addr = bgcnt.screen_block(); +// let tiles_per_row = 32; +// let num_tiles = 0x4000 / tile_size; +// println!("tileset: {:#x}, tilemap: {:#x}", tileset_addr, tilemap_addr); - let mut event_pump = sdl_context.event_pump().unwrap(); - 'running: loop { - for event in event_pump.poll_iter() { - match event { - Event::Quit { .. } => break 'running, - Event::MouseButtonDown { x, y, .. } => { - let click_point = Point::new(x, y); - let mut tile_x = TILESET_INITIAL_X; - let mut tile_y = TILESET_INITIAL_Y; - for t in 0..num_tiles { - let tile_addr = tileset_addr + t * tile_size; - if t != 0 && t % tiles_per_row == 0 { - tile_y += 10; - tile_x = TILESET_INITIAL_Y; - } - tile_x += 10; - if Rect::new(tile_x, tile_y, 8, 8).contains_point(click_point) { - println!("tile #{:#x}, addr={:#x}", t, tile_addr); - } - } - } - _ => {} - } - } +// let mut event_pump = sdl_context.event_pump().unwrap(); +// 'running: loop { +// for event in event_pump.poll_iter() { +// match event { +// Event::Quit { .. } => break 'running, +// Event::MouseButtonDown { x, y, .. } => { +// let click_point = Point::new(x, y); +// let mut tile_x = TILESET_INITIAL_X; +// let mut tile_y = TILESET_INITIAL_Y; +// for t in 0..num_tiles { +// let tile_addr = tileset_addr + t * tile_size; +// if t != 0 && t % tiles_per_row == 0 { +// tile_y += 10; +// tile_x = TILESET_INITIAL_Y; +// } +// tile_x += 10; +// if Rect::new(tile_x, tile_y, 8, 8).contains_point(click_point) { +// println!("tile #{:#x}, addr={:#x}", t, tile_addr); +// } +// } +// } +// _ => {} +// } +// } - canvas.set_draw_color(Color::RGB(00, 00, 00)); - canvas.clear(); +// canvas.set_draw_color(Color::RGB(00, 00, 00)); +// canvas.clear(); - let mut tile_x = TILESET_INITIAL_X; - let mut tile_y = TILESET_INITIAL_Y; - for t in 0..num_tiles { - let tile_addr = tileset_addr + t * tile_size; - if t != 0 && t % tiles_per_row == 0 { - tile_y += 10; - tile_x = TILESET_INITIAL_Y; - } - tile_x += 10; - draw_tile( - gba, - tile_addr, - pixel_format, - Point::from((tile_x, tile_y)), - &mut canvas, - ); - } - canvas.present(); - ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); - } -} +// let mut tile_x = TILESET_INITIAL_X; +// let mut tile_y = TILESET_INITIAL_Y; +// for t in 0..num_tiles { +// let tile_addr = tileset_addr + t * tile_size; +// if t != 0 && t % tiles_per_row == 0 { +// tile_y += 10; +// tile_x = TILESET_INITIAL_Y; +// } +// tile_x += 10; +// draw_tile( +// gba, +// tile_addr, +// pixel_format, +// Point::from((tile_x, tile_y)), +// &mut canvas, +// ); +// } +// canvas.present(); +// ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); +// } +// }