Continue working on DMA sound.
Cleanup timer.rs run cargo fmt restore debugging continue&frame commands Fix bug introduced in previous commit causing the bios animation to hang Former-commit-id: 188acaa1121503a97f2d3be816f6f57835e17fe1
This commit is contained in:
parent
70cb99161d
commit
fefeddbc40
|
@ -57,6 +57,8 @@ pub struct Core {
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
|
|
||||||
pub trace_opcodes: bool,
|
pub trace_opcodes: bool,
|
||||||
|
|
||||||
|
pub trace_exceptions: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CpuExecResult = CpuResult<()>;
|
pub type CpuExecResult = CpuResult<()>;
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Core {
|
||||||
Irq => (CpuMode::Irq, true, false),
|
Irq => (CpuMode::Irq, true, false),
|
||||||
Fiq => (CpuMode::Fiq, true, true),
|
Fiq => (CpuMode::Fiq, true, true),
|
||||||
};
|
};
|
||||||
if self.verbose {
|
if self.trace_exceptions {
|
||||||
println!(
|
println!(
|
||||||
"{}: {:?}, pc: {:#x}, new_mode: {:?} old_mode: {:?}",
|
"{}: {:?}, pc: {:#x}, new_mode: {:?} old_mode: {:?}",
|
||||||
"Exception".cyan(),
|
"Exception".cyan(),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use super::arm7tdmi::{Addr, Bus};
|
use super::arm7tdmi::{Addr, Bus};
|
||||||
|
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
|
||||||
use super::sysbus::SysBus;
|
use super::sysbus::SysBus;
|
||||||
use super::{Interrupt, IrqBitmask};
|
use super::{Interrupt, IrqBitmask};
|
||||||
|
|
||||||
|
@ -99,7 +100,10 @@ impl DmaChannel {
|
||||||
self.internal.src_addr = self.src;
|
self.internal.src_addr = self.src;
|
||||||
self.internal.dst_addr = self.dst;
|
self.internal.dst_addr = self.dst;
|
||||||
self.internal.count = self.wc;
|
self.internal.count = self.wc;
|
||||||
self.fifo_mode = timing == 3 && (self.id == 0 || self.id == 1);
|
self.fifo_mode = timing == 3
|
||||||
|
&& ctrl.repeat()
|
||||||
|
&& (self.id == 1 || self.id == 2)
|
||||||
|
&& (self.dst == REG_FIFO_A || self.dst == REG_FIFO_B);
|
||||||
}
|
}
|
||||||
self.ctrl = ctrl;
|
self.ctrl = ctrl;
|
||||||
return start_immediately;
|
return start_immediately;
|
||||||
|
@ -133,11 +137,10 @@ impl DmaChannel {
|
||||||
let fifo_mode = self.fifo_mode;
|
let fifo_mode = self.fifo_mode;
|
||||||
|
|
||||||
if fifo_mode {
|
if fifo_mode {
|
||||||
println!("FIFO Tranfer");
|
for _ in 0..4 {
|
||||||
for _ in 0..count {
|
let v = sb.read_32(self.internal.src_addr);
|
||||||
let v = sb.read_16(self.internal.src_addr);
|
sb.write_32(self.internal.dst_addr, v);
|
||||||
sb.write_16(self.internal.dst_addr, v);
|
self.internal.src_addr += 4;
|
||||||
self.internal.src_addr += 2;
|
|
||||||
}
|
}
|
||||||
} else if word_size == 4 {
|
} else if word_size == 4 {
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
|
|
|
@ -8,9 +8,6 @@ use super::gpu::*;
|
||||||
use super::interrupt::*;
|
use super::interrupt::*;
|
||||||
use super::iodev::*;
|
use super::iodev::*;
|
||||||
use super::sysbus::SysBus;
|
use super::sysbus::SysBus;
|
||||||
use super::timer::TimerEvent;
|
|
||||||
|
|
||||||
use super::SyncedIoDevice;
|
|
||||||
|
|
||||||
use super::super::{AudioInterface, InputInterface, VideoInterface};
|
use super::super::{AudioInterface, InputInterface, VideoInterface};
|
||||||
|
|
||||||
|
@ -51,8 +48,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame(&mut self) {
|
#[inline]
|
||||||
|
pub fn key_poll(&mut self) {
|
||||||
self.sysbus.io.keyinput = self.input_device.borrow_mut().poll();
|
self.sysbus.io.keyinput = self.input_device.borrow_mut().poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frame(&mut self) {
|
||||||
|
self.key_poll();
|
||||||
while self.sysbus.io.gpu.state != GpuState::VBlank {
|
while self.sysbus.io.gpu.state != GpuState::VBlank {
|
||||||
self.step();
|
self.step();
|
||||||
}
|
}
|
||||||
|
@ -114,7 +116,7 @@ where
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
io.timers.tick(cycles, &mut self.sysbus, &mut irqs);
|
io.timers.step(cycles, &mut self.sysbus, &mut irqs);
|
||||||
|
|
||||||
if let Some(new_gpu_state) = 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 {
|
match new_gpu_state {
|
||||||
|
|
|
@ -28,7 +28,6 @@ pub struct IoDevices {
|
||||||
pub post_boot_flag: bool,
|
pub post_boot_flag: bool,
|
||||||
pub waitcnt: WaitControl, // TODO also implement 4000800
|
pub waitcnt: WaitControl, // TODO also implement 4000800
|
||||||
pub haltcnt: HaltState,
|
pub haltcnt: HaltState,
|
||||||
pub sound_bias: u16,
|
|
||||||
|
|
||||||
mem: BoxedMemory,
|
mem: BoxedMemory,
|
||||||
}
|
}
|
||||||
|
@ -46,7 +45,6 @@ impl IoDevices {
|
||||||
haltcnt: HaltState::Running,
|
haltcnt: HaltState::Running,
|
||||||
keyinput: keypad::KEYINPUT_ALL_RELEASED,
|
keyinput: keypad::KEYINPUT_ALL_RELEASED,
|
||||||
waitcnt: WaitControl(0),
|
waitcnt: WaitControl(0),
|
||||||
sound_bias: 0x200,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,30 +85,20 @@ impl Bus for IoDevices {
|
||||||
REG_IE => io.intc.interrupt_enable.0 as u16,
|
REG_IE => io.intc.interrupt_enable.0 as u16,
|
||||||
REG_IF => io.intc.interrupt_flags.0 as u16,
|
REG_IF => io.intc.interrupt_flags.0 as u16,
|
||||||
|
|
||||||
REG_TM0CNT_L => io.timers[0].timer_data,
|
REG_TM0CNT_L..=REG_TM3CNT_H => io.timers.handle_read(io_addr),
|
||||||
REG_TM0CNT_H => io.timers[0].timer_ctl.0,
|
|
||||||
REG_TM1CNT_L => io.timers[1].timer_data,
|
|
||||||
REG_TM1CNT_H => io.timers[1].timer_ctl.0,
|
|
||||||
REG_TM2CNT_L => io.timers[2].timer_data,
|
|
||||||
REG_TM2CNT_H => io.timers[2].timer_ctl.0,
|
|
||||||
REG_TM3CNT_L => io.timers[3].timer_data,
|
|
||||||
REG_TM3CNT_H => io.timers[3].timer_ctl.0,
|
|
||||||
|
|
||||||
|
REG_SOUND1CNT_L..DMA_BASE => io.sound.handle_read(io_addr),
|
||||||
REG_DMA0CNT_H => io.dmac.channels[0].ctrl.0,
|
REG_DMA0CNT_H => io.dmac.channels[0].ctrl.0,
|
||||||
REG_DMA1CNT_H => io.dmac.channels[1].ctrl.0,
|
REG_DMA1CNT_H => io.dmac.channels[1].ctrl.0,
|
||||||
REG_DMA2CNT_H => io.dmac.channels[2].ctrl.0,
|
REG_DMA2CNT_H => io.dmac.channels[2].ctrl.0,
|
||||||
REG_DMA3CNT_H => io.dmac.channels[3].ctrl.0,
|
REG_DMA3CNT_H => io.dmac.channels[3].ctrl.0,
|
||||||
|
|
||||||
REG_SOUNDBIAS => io.sound_bias,
|
|
||||||
|
|
||||||
REG_WAITCNT => io.waitcnt.0,
|
REG_WAITCNT => io.waitcnt.0,
|
||||||
|
|
||||||
REG_POSTFLG => io.post_boot_flag as u16,
|
REG_POSTFLG => io.post_boot_flag as u16,
|
||||||
REG_HALTCNT => 0,
|
REG_HALTCNT => 0,
|
||||||
REG_KEYINPUT => io.keyinput as u16,
|
REG_KEYINPUT => io.keyinput as u16,
|
||||||
|
|
||||||
REG_SOUND1CNT_L..=DMA_BASE => io.sound.handle_read(io_addr),
|
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
// println!(
|
// println!(
|
||||||
// "Unimplemented read from {:x} {}",
|
// "Unimplemented read from {:x} {}",
|
||||||
|
@ -216,29 +204,11 @@ impl Bus for IoDevices {
|
||||||
REG_IE => io.intc.interrupt_enable.0 = value,
|
REG_IE => io.intc.interrupt_enable.0 = value,
|
||||||
REG_IF => io.intc.interrupt_flags.0 &= !value,
|
REG_IF => io.intc.interrupt_flags.0 &= !value,
|
||||||
|
|
||||||
REG_TM0CNT_L => {
|
REG_TM0CNT_L..=REG_TM3CNT_H => io.timers.handle_write(io_addr, value),
|
||||||
io.timers[0].timer_data = value;
|
|
||||||
io.timers[0].initial_data = value;
|
|
||||||
}
|
|
||||||
REG_TM0CNT_H => io.timers.write_timer_ctl(0, value),
|
|
||||||
|
|
||||||
REG_TM1CNT_L => {
|
REG_SOUND1CNT_L..DMA_BASE => {
|
||||||
io.timers[1].timer_data = value;
|
io.sound.handle_write(io_addr, value);
|
||||||
io.timers[1].initial_data = value;
|
|
||||||
}
|
}
|
||||||
REG_TM1CNT_H => io.timers.write_timer_ctl(1, value),
|
|
||||||
|
|
||||||
REG_TM2CNT_L => {
|
|
||||||
io.timers[2].timer_data = value;
|
|
||||||
io.timers[2].initial_data = value;
|
|
||||||
}
|
|
||||||
REG_TM2CNT_H => io.timers.write_timer_ctl(2, value),
|
|
||||||
|
|
||||||
REG_TM3CNT_L => {
|
|
||||||
io.timers[3].timer_data = value;
|
|
||||||
io.timers[3].initial_data = value;
|
|
||||||
}
|
|
||||||
REG_TM3CNT_H => io.timers.write_timer_ctl(3, value),
|
|
||||||
|
|
||||||
DMA_BASE..=REG_DMA3CNT_H => {
|
DMA_BASE..=REG_DMA3CNT_H => {
|
||||||
let ofs = io_addr - DMA_BASE;
|
let ofs = io_addr - DMA_BASE;
|
||||||
|
@ -246,8 +216,6 @@ impl Bus for IoDevices {
|
||||||
io.dmac.write_16(channel_id, ofs % 12, value)
|
io.dmac.write_16(channel_id, ofs % 12, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
REG_SOUNDBIAS => io.sound_bias = value & 0xc3fe,
|
|
||||||
|
|
||||||
REG_WAITCNT => io.waitcnt.0 = value,
|
REG_WAITCNT => io.waitcnt.0 = value,
|
||||||
|
|
||||||
REG_POSTFLG => io.post_boot_flag = value != 0,
|
REG_POSTFLG => io.post_boot_flag = value != 0,
|
||||||
|
@ -260,9 +228,6 @@ impl Bus for IoDevices {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
REG_SOUND1CNT_L..=DMA_BASE => {
|
|
||||||
io.sound.handle_write(io_addr, value);
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
// println!(
|
// println!(
|
||||||
// "Unimplemented write to {:x} {}",
|
// "Unimplemented write to {:x} {}",
|
||||||
|
|
|
@ -36,6 +36,12 @@ impl Default for DmaSound {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const REG_FIFO_A_L: u32 = REG_FIFO_A;
|
||||||
|
const REG_FIFO_A_H: u32 = REG_FIFO_A + 2;
|
||||||
|
|
||||||
|
const REG_FIFO_B_L: u32 = REG_FIFO_B;
|
||||||
|
const REG_FIFO_B_H: u32 = REG_FIFO_B + 2;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SoundController {
|
pub struct SoundController {
|
||||||
sample_rate_to_cpu_freq: usize, // how many "cycles" are a sample?
|
sample_rate_to_cpu_freq: usize, // how many "cycles" are a sample?
|
||||||
|
@ -66,6 +72,8 @@ pub struct SoundController {
|
||||||
sqr1_initial_vol: usize,
|
sqr1_initial_vol: usize,
|
||||||
sqr1_cur_vol: usize,
|
sqr1_cur_vol: usize,
|
||||||
|
|
||||||
|
sound_bias: u16,
|
||||||
|
|
||||||
sound_a: DmaSound,
|
sound_a: DmaSound,
|
||||||
sound_b: DmaSound,
|
sound_b: DmaSound,
|
||||||
}
|
}
|
||||||
|
@ -95,6 +103,7 @@ impl SoundController {
|
||||||
sqr1_step_increase: false,
|
sqr1_step_increase: false,
|
||||||
sqr1_initial_vol: 0,
|
sqr1_initial_vol: 0,
|
||||||
sqr1_cur_vol: 0,
|
sqr1_cur_vol: 0,
|
||||||
|
sound_bias: 0x200,
|
||||||
sound_a: Default::default(),
|
sound_a: Default::default(),
|
||||||
sound_b: Default::default(),
|
sound_b: Default::default(),
|
||||||
}
|
}
|
||||||
|
@ -137,6 +146,8 @@ impl SoundController {
|
||||||
| cbit(14, self.sound_b.timer_select != 0)
|
| cbit(14, self.sound_b.timer_select != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REG_SOUNDBIAS => self.sound_bias,
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
println!(
|
println!(
|
||||||
"Unimplemented read from {:x} {}",
|
"Unimplemented read from {:x} {}",
|
||||||
|
@ -174,7 +185,7 @@ impl SoundController {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.mse {
|
if !self.mse {
|
||||||
println!("MSE disabled, refusing to write");
|
// println!("MSE disabled, refusing to write");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,16 +238,18 @@ impl SoundController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
REG_FIFO_A => {
|
REG_FIFO_A_L | REG_FIFO_A_H => {
|
||||||
self.sound_a.fifo.write((value & 0xff00 >> 8) as i8);
|
self.sound_a.fifo.write(((value >> 8) & 0xff) as i8);
|
||||||
self.sound_a.fifo.write((value & 0xff) as i8);
|
self.sound_a.fifo.write((value & 0xff) as i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
REG_FIFO_B => {
|
REG_FIFO_B_L | REG_FIFO_B_H => {
|
||||||
self.sound_b.fifo.write((value & 0xff00 >> 8) as i8);
|
self.sound_b.fifo.write(((value >> 8) & 0xff) as i8);
|
||||||
self.sound_b.fifo.write((value & 0xff) as i8);
|
self.sound_b.fifo.write((value & 0xff) as i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REG_SOUNDBIAS => self.sound_bias = value & 0xc3fe,
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
println!(
|
println!(
|
||||||
"Unimplemented write to {:x} {}",
|
"Unimplemented write to {:x} {}",
|
||||||
|
|
|
@ -1,29 +1,23 @@
|
||||||
use super::interrupt::{Interrupt, IrqBitmask};
|
use super::interrupt::{Interrupt, IrqBitmask};
|
||||||
|
use super::iodev::consts::*;
|
||||||
use super::sysbus::SysBus;
|
use super::sysbus::SysBus;
|
||||||
use super::SyncedIoDevice;
|
|
||||||
|
|
||||||
use num::FromPrimitive;
|
use num::FromPrimitive;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
// registers
|
// registers
|
||||||
pub timer_ctl: TimerCtl,
|
pub ctl: TimerCtl,
|
||||||
pub timer_data: u16,
|
pub data: u16,
|
||||||
|
|
||||||
|
irq: Interrupt,
|
||||||
|
|
||||||
timer_id: usize,
|
timer_id: usize,
|
||||||
reg: u32,
|
|
||||||
target: u32,
|
|
||||||
fired: bool,
|
|
||||||
pub initial_data: u16,
|
pub initial_data: u16,
|
||||||
|
|
||||||
pub cycles: usize,
|
pub cycles: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TimerEvent {
|
|
||||||
Overflow(usize, usize),
|
|
||||||
Increment(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
pub fn new(timer_id: usize) -> Timer {
|
pub fn new(timer_id: usize) -> Timer {
|
||||||
if timer_id > 3 {
|
if timer_id > 3 {
|
||||||
|
@ -31,16 +25,16 @@ impl Timer {
|
||||||
}
|
}
|
||||||
Timer {
|
Timer {
|
||||||
timer_id: timer_id,
|
timer_id: timer_id,
|
||||||
..Timer::default()
|
irq: Interrupt::from_usize(timer_id + 8).unwrap(),
|
||||||
|
data: 0,
|
||||||
|
ctl: TimerCtl(0),
|
||||||
|
initial_data: 0,
|
||||||
|
cycles: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_irq(&self) -> Interrupt {
|
|
||||||
Interrupt::from_usize(self.timer_id + 8).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frequency(&self) -> usize {
|
fn frequency(&self) -> usize {
|
||||||
match self.timer_ctl.prescalar() {
|
match self.ctl.prescalar() {
|
||||||
0 => 1,
|
0 => 1,
|
||||||
1 => 64,
|
1 => 64,
|
||||||
2 => 256,
|
2 => 256,
|
||||||
|
@ -48,29 +42,6 @@ impl Timer {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_cycles(&mut self, cycles: usize, irqs: &mut IrqBitmask) -> TimerEvent {
|
|
||||||
let mut num_overflows = 0;
|
|
||||||
self.cycles += cycles;
|
|
||||||
|
|
||||||
let frequency = self.frequency();
|
|
||||||
while self.cycles >= frequency {
|
|
||||||
self.cycles -= frequency;
|
|
||||||
self.timer_data = self.timer_data.wrapping_add(1);
|
|
||||||
if self.timer_data == 0 {
|
|
||||||
if self.timer_ctl.irq_enabled() {
|
|
||||||
irqs.add_irq(self.get_irq());
|
|
||||||
}
|
|
||||||
self.timer_data = self.initial_data;
|
|
||||||
num_overflows += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if num_overflows > 0 {
|
|
||||||
return TimerEvent::Overflow(self.timer_id, num_overflows);
|
|
||||||
} else {
|
|
||||||
return TimerEvent::Increment(self.timer_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -96,14 +67,14 @@ impl Timers {
|
||||||
pub fn new() -> Timers {
|
pub fn new() -> Timers {
|
||||||
Timers {
|
Timers {
|
||||||
timers: [Timer::new(0), Timer::new(1), Timer::new(2), Timer::new(3)],
|
timers: [Timer::new(0), Timer::new(1), Timer::new(2), Timer::new(3)],
|
||||||
trace: false,
|
trace: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_timer_ctl(&mut self, id: usize, value: u16) {
|
pub fn write_timer_ctl(&mut self, id: usize, value: u16) {
|
||||||
let old_enabled = self[id].timer_ctl.enabled();
|
let old_enabled = self[id].ctl.enabled();
|
||||||
self[id].timer_ctl.0 = value;
|
self[id].ctl.0 = value;
|
||||||
let new_enabled = self[id].timer_ctl.enabled();
|
let new_enabled = self[id].ctl.enabled();
|
||||||
if self.trace && old_enabled != new_enabled {
|
if self.trace && old_enabled != new_enabled {
|
||||||
println!(
|
println!(
|
||||||
"TMR{} {}",
|
"TMR{} {}",
|
||||||
|
@ -113,36 +84,88 @@ impl Timers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(
|
pub fn handle_read(&self, io_addr: u32) -> u16 {
|
||||||
&mut self,
|
match io_addr {
|
||||||
cycles: usize,
|
REG_TM0CNT_L => self.timers[0].data,
|
||||||
sb: &mut SysBus,
|
REG_TM0CNT_H => self.timers[0].ctl.0,
|
||||||
irqs: &mut IrqBitmask,
|
REG_TM1CNT_L => self.timers[1].data,
|
||||||
) -> Option<TimerEvent> {
|
REG_TM1CNT_H => self.timers[1].ctl.0,
|
||||||
for i in 0..4 {
|
REG_TM2CNT_L => self.timers[2].data,
|
||||||
if self[i].timer_ctl.enabled() && !self[i].timer_ctl.cascade() {
|
REG_TM2CNT_H => self.timers[2].ctl.0,
|
||||||
let event = self[i].add_cycles(cycles, irqs);
|
REG_TM3CNT_L => self.timers[3].data,
|
||||||
match event {
|
REG_TM3CNT_H => self.timers[3].ctl.0,
|
||||||
TimerEvent::Overflow(_, num_overflows) => {
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_write(&mut self, io_addr: u32, value: u16) {
|
||||||
|
match io_addr {
|
||||||
|
REG_TM0CNT_L => {
|
||||||
|
self.timers[0].data = value;
|
||||||
|
self.timers[0].initial_data = value;
|
||||||
|
}
|
||||||
|
REG_TM0CNT_H => self.write_timer_ctl(0, value),
|
||||||
|
|
||||||
|
REG_TM1CNT_L => {
|
||||||
|
self.timers[1].data = value;
|
||||||
|
self.timers[1].initial_data = value;
|
||||||
|
}
|
||||||
|
REG_TM1CNT_H => self.write_timer_ctl(1, value),
|
||||||
|
|
||||||
|
REG_TM2CNT_L => {
|
||||||
|
self.timers[2].data = value;
|
||||||
|
self.timers[2].initial_data = value;
|
||||||
|
}
|
||||||
|
REG_TM2CNT_H => self.write_timer_ctl(2, value),
|
||||||
|
|
||||||
|
REG_TM3CNT_L => {
|
||||||
|
self.timers[3].data = value;
|
||||||
|
self.timers[3].initial_data = value;
|
||||||
|
}
|
||||||
|
REG_TM3CNT_H => self.write_timer_ctl(3, value),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_timer(&mut self, id: usize, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask) {
|
||||||
|
let timer = &mut self.timers[id];
|
||||||
|
timer.cycles += cycles;
|
||||||
|
let mut num_overflows = 0;
|
||||||
|
let freq = timer.frequency();
|
||||||
|
while timer.cycles >= freq {
|
||||||
|
timer.cycles -= freq;
|
||||||
|
timer.data = timer.data.wrapping_add(1);
|
||||||
|
if timer.data == 0 {
|
||||||
if self.trace {
|
if self.trace {
|
||||||
println!("TMR{} overflown!", i);
|
println!("TMR{} overflown!", id);
|
||||||
}
|
}
|
||||||
if i != 3 {
|
if timer.ctl.irq_enabled() {
|
||||||
let next_i = i + 1;
|
irqs.add_irq(timer.irq);
|
||||||
if self[next_i].timer_ctl.cascade() {
|
}
|
||||||
self[next_i].add_cycles(num_overflows, irqs);
|
timer.data = timer.initial_data;
|
||||||
|
num_overflows += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if i == 0 || i == 1 {
|
|
||||||
sb.io.sound.handle_timer_overflow(&mut sb.io.dmac, i);
|
if num_overflows > 0 {
|
||||||
|
if id != 3 {
|
||||||
|
let next_timer = &mut self.timers[id + 1];
|
||||||
|
if next_timer.ctl.cascade() {
|
||||||
|
self.update_timer(id + 1, num_overflows, sb, irqs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
if id == 0 || id == 1 {
|
||||||
}
|
sb.io.sound.handle_timer_overflow(&mut sb.io.dmac, id);
|
||||||
return Some(event);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask) {
|
||||||
|
for i in 0..4 {
|
||||||
|
if self.timers[i].ctl.enabled() && !self.timers[i].ctl.cascade() {
|
||||||
|
self.update_timer(i, cycles, sb, irqs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ bitflags! {
|
||||||
const TRACE_OPCODE = 0b00000010;
|
const TRACE_OPCODE = 0b00000010;
|
||||||
const TRACE_DMA = 0b00000100;
|
const TRACE_DMA = 0b00000100;
|
||||||
const TRACE_TIMERS = 0b000001000;
|
const TRACE_TIMERS = 0b000001000;
|
||||||
|
const TRACE_EXCEPTIONS = 0b000001000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,31 +109,30 @@ where
|
||||||
}
|
}
|
||||||
println!("{}\n", self.gba.cpu);
|
println!("{}\n", self.gba.cpu);
|
||||||
}
|
}
|
||||||
// Continue => {
|
Continue => {
|
||||||
// self.ctrlc_flag.store(true, Ordering::SeqCst);
|
self.ctrlc_flag.store(true, Ordering::SeqCst);
|
||||||
// while self.ctrlc_flag.load(Ordering::SeqCst) {
|
while self.ctrlc_flag.load(Ordering::SeqCst) {
|
||||||
// let start_time = time::Instant::now();
|
self.gba.key_poll();
|
||||||
// self.gba.update_key_state();
|
match self.gba.check_breakpoint() {
|
||||||
// match self.gba.check_breakpoint() {
|
Some(addr) => {
|
||||||
// Some(addr) => {
|
println!("Breakpoint reached! @{:x}", addr);
|
||||||
// println!("Breakpoint reached! @{:x}", addr);
|
break;
|
||||||
// break;
|
}
|
||||||
// }
|
_ => {
|
||||||
// _ => {
|
self.gba.step();
|
||||||
// self.gba.step();
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
Frame(count) => {
|
||||||
// Frame(count) => {
|
use super::time::PreciseTime;
|
||||||
// use super::time::PreciseTime;
|
let start = PreciseTime::now();
|
||||||
// let start = PreciseTime::now();
|
for _ in 0..count {
|
||||||
// for _ in 0..count {
|
self.gba.frame();
|
||||||
// self.gba.frame();
|
}
|
||||||
// }
|
let end = PreciseTime::now();
|
||||||
// let end = PreciseTime::now();
|
println!("that took {} seconds", start.to(end));
|
||||||
// println!("that took {} seconds", start.to(end));
|
}
|
||||||
// }
|
|
||||||
HexDump(addr, nbytes) => {
|
HexDump(addr, nbytes) => {
|
||||||
let bytes = self.gba.sysbus.get_bytes(addr..addr + nbytes);
|
let bytes = self.gba.sysbus.get_bytes(addr..addr + nbytes);
|
||||||
hexdump::hexdump(&bytes);
|
hexdump::hexdump(&bytes);
|
||||||
|
@ -205,6 +205,17 @@ where
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if flags.contains(TraceFlags::TRACE_EXCEPTIONS) {
|
||||||
|
self.gba.cpu.trace_exceptions = !self.gba.cpu.trace_exceptions;
|
||||||
|
println!(
|
||||||
|
"[*] exception tracing {}",
|
||||||
|
if self.gba.cpu.trace_exceptions {
|
||||||
|
"on"
|
||||||
|
} else {
|
||||||
|
"off"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
if flags.contains(TraceFlags::TRACE_DMA) {
|
if flags.contains(TraceFlags::TRACE_DMA) {
|
||||||
println!("[*] dma tracing not implemented");
|
println!("[*] dma tracing not implemented");
|
||||||
}
|
}
|
||||||
|
@ -420,7 +431,7 @@ where
|
||||||
"r" | "reset" => Ok(Command::Reset),
|
"r" | "reset" => Ok(Command::Reset),
|
||||||
"trace" => {
|
"trace" => {
|
||||||
let usage = DebuggerError::InvalidCommandFormat(String::from(
|
let usage = DebuggerError::InvalidCommandFormat(String::from(
|
||||||
"trace [sysbus|opcode|dma|all]",
|
"trace [sysbus|opcode|dma|all|exceptions]",
|
||||||
));
|
));
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
Err(usage)
|
Err(usage)
|
||||||
|
@ -429,6 +440,7 @@ where
|
||||||
let flags = match flag_str.as_ref() {
|
let flags = match flag_str.as_ref() {
|
||||||
"sysbus" => TraceFlags::TRACE_SYSBUS,
|
"sysbus" => TraceFlags::TRACE_SYSBUS,
|
||||||
"opcode" => TraceFlags::TRACE_OPCODE,
|
"opcode" => TraceFlags::TRACE_OPCODE,
|
||||||
|
"exceptions" => TraceFlags::TRACE_EXCEPTIONS,
|
||||||
"dma" => TraceFlags::TRACE_DMA,
|
"dma" => TraceFlags::TRACE_DMA,
|
||||||
"timers" => TraceFlags::TRACE_TIMERS,
|
"timers" => TraceFlags::TRACE_TIMERS,
|
||||||
"all" => TraceFlags::all(),
|
"all" => TraceFlags::all(),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
#![feature(exclusive_range_pattern)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate enum_primitive_derive;
|
extern crate enum_primitive_derive;
|
||||||
|
|
|
@ -11,9 +11,9 @@ extern crate clap;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustboyadvance_ng;
|
extern crate rustboyadvance_ng;
|
||||||
|
use rustboyadvance_ng::core::keypad;
|
||||||
use rustboyadvance_ng::prelude::*;
|
use rustboyadvance_ng::prelude::*;
|
||||||
use rustboyadvance_ng::util::FpsCounter;
|
use rustboyadvance_ng::util::FpsCounter;
|
||||||
use rustboyadvance_ng::core::keypad;
|
|
||||||
|
|
||||||
extern crate bit;
|
extern crate bit;
|
||||||
use bit::BitIndex;
|
use bit::BitIndex;
|
||||||
|
@ -80,7 +80,6 @@ impl AudioInterface for MiniFb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let yaml = load_yaml!("cli.yml");
|
let yaml = load_yaml!("cli.yml");
|
||||||
let matches = clap::App::from_yaml(yaml).get_matches();
|
let matches = clap::App::from_yaml(yaml).get_matches();
|
||||||
|
@ -118,8 +117,14 @@ fn main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut fps_counter = FpsCounter::default();
|
let mut fps_counter = FpsCounter::default();
|
||||||
let mut gba: GameBoyAdvance<MiniFb, MiniFb, MiniFb> =
|
let mut gba: GameBoyAdvance<MiniFb, MiniFb, MiniFb> = GameBoyAdvance::new(
|
||||||
GameBoyAdvance::new(cpu, bios_bin, cart, minifb.clone(), minifb.clone(), minifb.clone());
|
cpu,
|
||||||
|
bios_bin,
|
||||||
|
cart,
|
||||||
|
minifb.clone(),
|
||||||
|
minifb.clone(),
|
||||||
|
minifb.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
gba.cpu.set_verbose(true);
|
gba.cpu.set_verbose(true);
|
||||||
|
|
Reference in a new issue