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:
Michel Heily 2019-12-21 20:19:43 +02:00
parent 70cb99161d
commit fefeddbc40
10 changed files with 185 additions and 159 deletions

View file

@ -57,6 +57,8 @@ pub struct Core {
pub verbose: bool,
pub trace_opcodes: bool,
pub trace_exceptions: bool,
}
pub type CpuExecResult = CpuResult<()>;

View file

@ -30,7 +30,7 @@ impl Core {
Irq => (CpuMode::Irq, true, false),
Fiq => (CpuMode::Fiq, true, true),
};
if self.verbose {
if self.trace_exceptions {
println!(
"{}: {:?}, pc: {:#x}, new_mode: {:?} old_mode: {:?}",
"Exception".cyan(),

View file

@ -1,6 +1,7 @@
use std::collections::VecDeque;
use super::arm7tdmi::{Addr, Bus};
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
use super::sysbus::SysBus;
use super::{Interrupt, IrqBitmask};
@ -99,7 +100,10 @@ impl DmaChannel {
self.internal.src_addr = self.src;
self.internal.dst_addr = self.dst;
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;
return start_immediately;
@ -133,11 +137,10 @@ impl DmaChannel {
let fifo_mode = self.fifo_mode;
if fifo_mode {
println!("FIFO Tranfer");
for _ in 0..count {
let v = sb.read_16(self.internal.src_addr);
sb.write_16(self.internal.dst_addr, v);
self.internal.src_addr += 2;
for _ in 0..4 {
let v = sb.read_32(self.internal.src_addr);
sb.write_32(self.internal.dst_addr, v);
self.internal.src_addr += 4;
}
} else if word_size == 4 {
for _ in 0..count {

View file

@ -8,9 +8,6 @@ use super::gpu::*;
use super::interrupt::*;
use super::iodev::*;
use super::sysbus::SysBus;
use super::timer::TimerEvent;
use super::SyncedIoDevice;
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();
}
pub fn frame(&mut self) {
self.key_poll();
while self.sysbus.io.gpu.state != GpuState::VBlank {
self.step();
}
@ -114,7 +116,7 @@ where
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) {
match new_gpu_state {

View file

@ -28,7 +28,6 @@ pub struct IoDevices {
pub post_boot_flag: bool,
pub waitcnt: WaitControl, // TODO also implement 4000800
pub haltcnt: HaltState,
pub sound_bias: u16,
mem: BoxedMemory,
}
@ -46,7 +45,6 @@ impl IoDevices {
haltcnt: HaltState::Running,
keyinput: keypad::KEYINPUT_ALL_RELEASED,
waitcnt: WaitControl(0),
sound_bias: 0x200,
}
}
}
@ -87,30 +85,20 @@ impl Bus for IoDevices {
REG_IE => io.intc.interrupt_enable.0 as u16,
REG_IF => io.intc.interrupt_flags.0 as u16,
REG_TM0CNT_L => io.timers[0].timer_data,
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_TM0CNT_L..=REG_TM3CNT_H => io.timers.handle_read(io_addr),
REG_SOUND1CNT_L..DMA_BASE => io.sound.handle_read(io_addr),
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_SOUNDBIAS => io.sound_bias,
REG_WAITCNT => io.waitcnt.0,
REG_POSTFLG => io.post_boot_flag as u16,
REG_HALTCNT => 0,
REG_KEYINPUT => io.keyinput as u16,
REG_SOUND1CNT_L..=DMA_BASE => io.sound.handle_read(io_addr),
_ => {
// println!(
// "Unimplemented read from {:x} {}",
@ -216,29 +204,11 @@ impl Bus for IoDevices {
REG_IE => io.intc.interrupt_enable.0 = value,
REG_IF => io.intc.interrupt_flags.0 &= !value,
REG_TM0CNT_L => {
io.timers[0].timer_data = value;
io.timers[0].initial_data = value;
}
REG_TM0CNT_H => io.timers.write_timer_ctl(0, value),
REG_TM0CNT_L..=REG_TM3CNT_H => io.timers.handle_write(io_addr, value),
REG_TM1CNT_L => {
io.timers[1].timer_data = value;
io.timers[1].initial_data = value;
REG_SOUND1CNT_L..DMA_BASE => {
io.sound.handle_write(io_addr, 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 => {
let ofs = io_addr - DMA_BASE;
@ -246,8 +216,6 @@ impl Bus for IoDevices {
io.dmac.write_16(channel_id, ofs % 12, value)
}
REG_SOUNDBIAS => io.sound_bias = value & 0xc3fe,
REG_WAITCNT => io.waitcnt.0 = value,
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!(
// "Unimplemented write to {:x} {}",

View file

@ -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)]
pub struct SoundController {
sample_rate_to_cpu_freq: usize, // how many "cycles" are a sample?
@ -66,6 +72,8 @@ pub struct SoundController {
sqr1_initial_vol: usize,
sqr1_cur_vol: usize,
sound_bias: u16,
sound_a: DmaSound,
sound_b: DmaSound,
}
@ -95,6 +103,7 @@ impl SoundController {
sqr1_step_increase: false,
sqr1_initial_vol: 0,
sqr1_cur_vol: 0,
sound_bias: 0x200,
sound_a: Default::default(),
sound_b: Default::default(),
}
@ -137,6 +146,8 @@ impl SoundController {
| cbit(14, self.sound_b.timer_select != 0)
}
REG_SOUNDBIAS => self.sound_bias,
_ => {
println!(
"Unimplemented read from {:x} {}",
@ -174,7 +185,7 @@ impl SoundController {
}
if !self.mse {
println!("MSE disabled, refusing to write");
// println!("MSE disabled, refusing to write");
return;
}
@ -227,16 +238,18 @@ impl SoundController {
}
}
REG_FIFO_A => {
self.sound_a.fifo.write((value & 0xff00 >> 8) as i8);
REG_FIFO_A_L | REG_FIFO_A_H => {
self.sound_a.fifo.write(((value >> 8) & 0xff) as i8);
self.sound_a.fifo.write((value & 0xff) as i8);
}
REG_FIFO_B => {
self.sound_b.fifo.write((value & 0xff00 >> 8) as i8);
REG_FIFO_B_L | REG_FIFO_B_H => {
self.sound_b.fifo.write(((value >> 8) & 0xff) as i8);
self.sound_b.fifo.write((value & 0xff) as i8);
}
REG_SOUNDBIAS => self.sound_bias = value & 0xc3fe,
_ => {
println!(
"Unimplemented write to {:x} {}",

View file

@ -1,29 +1,23 @@
use super::interrupt::{Interrupt, IrqBitmask};
use super::iodev::consts::*;
use super::sysbus::SysBus;
use super::SyncedIoDevice;
use num::FromPrimitive;
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct Timer {
// registers
pub timer_ctl: TimerCtl,
pub timer_data: u16,
pub ctl: TimerCtl,
pub data: u16,
irq: Interrupt,
timer_id: usize,
reg: u32,
target: u32,
fired: bool,
pub initial_data: u16,
pub cycles: usize,
}
pub enum TimerEvent {
Overflow(usize, usize),
Increment(usize),
}
impl Timer {
pub fn new(timer_id: usize) -> Timer {
if timer_id > 3 {
@ -31,16 +25,16 @@ impl Timer {
}
Timer {
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 {
match self.timer_ctl.prescalar() {
match self.ctl.prescalar() {
0 => 1,
1 => 64,
2 => 256,
@ -48,29 +42,6 @@ impl Timer {
_ => 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)]
@ -96,14 +67,14 @@ impl Timers {
pub fn new() -> Timers {
Timers {
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) {
let old_enabled = self[id].timer_ctl.enabled();
self[id].timer_ctl.0 = value;
let new_enabled = self[id].timer_ctl.enabled();
let old_enabled = self[id].ctl.enabled();
self[id].ctl.0 = value;
let new_enabled = self[id].ctl.enabled();
if self.trace && old_enabled != new_enabled {
println!(
"TMR{} {}",
@ -113,36 +84,88 @@ impl Timers {
}
}
pub fn tick(
&mut self,
cycles: usize,
sb: &mut SysBus,
irqs: &mut IrqBitmask,
) -> Option<TimerEvent> {
for i in 0..4 {
if self[i].timer_ctl.enabled() && !self[i].timer_ctl.cascade() {
let event = self[i].add_cycles(cycles, irqs);
match event {
TimerEvent::Overflow(_, num_overflows) => {
pub fn handle_read(&self, io_addr: u32) -> u16 {
match io_addr {
REG_TM0CNT_L => self.timers[0].data,
REG_TM0CNT_H => self.timers[0].ctl.0,
REG_TM1CNT_L => self.timers[1].data,
REG_TM1CNT_H => self.timers[1].ctl.0,
REG_TM2CNT_L => self.timers[2].data,
REG_TM2CNT_H => self.timers[2].ctl.0,
REG_TM3CNT_L => self.timers[3].data,
REG_TM3CNT_H => self.timers[3].ctl.0,
_ => 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 {
println!("TMR{} overflown!", i);
println!("TMR{} overflown!", id);
}
if i != 3 {
let next_i = i + 1;
if self[next_i].timer_ctl.cascade() {
self[next_i].add_cycles(num_overflows, irqs);
if timer.ctl.irq_enabled() {
irqs.add_irq(timer.irq);
}
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);
}
}
_ => {}
}
return Some(event);
if id == 0 || id == 1 {
sb.io.sound.handle_timer_overflow(&mut sb.io.dmac, id);
}
}
}
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
}
}

View file

@ -38,6 +38,7 @@ bitflags! {
const TRACE_OPCODE = 0b00000010;
const TRACE_DMA = 0b00000100;
const TRACE_TIMERS = 0b000001000;
const TRACE_EXCEPTIONS = 0b000001000;
}
}
@ -108,31 +109,30 @@ where
}
println!("{}\n", self.gba.cpu);
}
// Continue => {
// self.ctrlc_flag.store(true, Ordering::SeqCst);
// while self.ctrlc_flag.load(Ordering::SeqCst) {
// let start_time = time::Instant::now();
// self.gba.update_key_state();
// match self.gba.check_breakpoint() {
// Some(addr) => {
// println!("Breakpoint reached! @{:x}", addr);
// break;
// }
// _ => {
// self.gba.step();
// }
// }
// }
// }
// Frame(count) => {
// use super::time::PreciseTime;
// let start = PreciseTime::now();
// for _ in 0..count {
// self.gba.frame();
// }
// let end = PreciseTime::now();
// println!("that took {} seconds", start.to(end));
// }
Continue => {
self.ctrlc_flag.store(true, Ordering::SeqCst);
while self.ctrlc_flag.load(Ordering::SeqCst) {
self.gba.key_poll();
match self.gba.check_breakpoint() {
Some(addr) => {
println!("Breakpoint reached! @{:x}", addr);
break;
}
_ => {
self.gba.step();
}
}
}
}
Frame(count) => {
use super::time::PreciseTime;
let start = PreciseTime::now();
for _ in 0..count {
self.gba.frame();
}
let end = PreciseTime::now();
println!("that took {} seconds", start.to(end));
}
HexDump(addr, nbytes) => {
let bytes = self.gba.sysbus.get_bytes(addr..addr + nbytes);
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) {
println!("[*] dma tracing not implemented");
}
@ -420,7 +431,7 @@ where
"r" | "reset" => Ok(Command::Reset),
"trace" => {
let usage = DebuggerError::InvalidCommandFormat(String::from(
"trace [sysbus|opcode|dma|all]",
"trace [sysbus|opcode|dma|all|exceptions]",
));
if args.len() != 1 {
Err(usage)
@ -429,6 +440,7 @@ where
let flags = match flag_str.as_ref() {
"sysbus" => TraceFlags::TRACE_SYSBUS,
"opcode" => TraceFlags::TRACE_OPCODE,
"exceptions" => TraceFlags::TRACE_EXCEPTIONS,
"dma" => TraceFlags::TRACE_DMA,
"timers" => TraceFlags::TRACE_TIMERS,
"all" => TraceFlags::all(),

View file

@ -1,5 +1,6 @@
#![feature(asm)]
#![feature(core_intrinsics)]
#![feature(exclusive_range_pattern)]
#[macro_use]
extern crate enum_primitive_derive;

View file

@ -11,9 +11,9 @@ extern crate clap;
#[macro_use]
extern crate rustboyadvance_ng;
use rustboyadvance_ng::core::keypad;
use rustboyadvance_ng::prelude::*;
use rustboyadvance_ng::util::FpsCounter;
use rustboyadvance_ng::core::keypad;
extern crate bit;
use bit::BitIndex;
@ -80,7 +80,6 @@ impl AudioInterface for MiniFb {
}
}
fn main() {
let yaml = load_yaml!("cli.yml");
let matches = clap::App::from_yaml(yaml).get_matches();
@ -118,8 +117,14 @@ fn main() {
}));
let mut fps_counter = FpsCounter::default();
let mut gba: GameBoyAdvance<MiniFb, MiniFb, MiniFb> =
GameBoyAdvance::new(cpu, bios_bin, cart, minifb.clone(), minifb.clone(), minifb.clone());
let mut gba: GameBoyAdvance<MiniFb, MiniFb, MiniFb> = GameBoyAdvance::new(
cpu,
bios_bin,
cart,
minifb.clone(),
minifb.clone(),
minifb.clone(),
);
if debug {
gba.cpu.set_verbose(true);