Fixed tests after ClockTime and Frequency changes

And also removed HostData
This commit is contained in:
transistor 2023-05-07 20:42:55 -07:00
parent 6389fa0482
commit 5e228c377e
23 changed files with 272 additions and 225 deletions

View File

@ -13,5 +13,5 @@ pub use self::keys::{Key, KeyEvent};
pub use self::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState};
pub use self::controllers::{ControllerDevice, ControllerInput, ControllerEvent};
pub use self::input::{EventSender, EventReceiver, event_queue};
pub use self::traits::{Host, Tty, Audio, HostData, ClockedQueue, DummyAudio};
pub use self::traits::{Host, Tty, Audio, ClockedQueue, DummyAudio};

View File

@ -1,6 +1,6 @@
use std::collections::VecDeque;
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::{Arc, Mutex};
use crate::{ClockTime, Error};
use crate::host::gfx::FrameReceiver;
@ -50,30 +50,6 @@ pub trait Audio {
}
#[derive(Clone, Debug)]
pub struct HostData<T>(Arc<Mutex<T>>);
impl<T> HostData<T> {
pub fn new(init: T) -> HostData<T> {
HostData(Arc::new(Mutex::new(init)))
}
pub fn lock(&self) -> MutexGuard<'_, T> {
self.0.lock().unwrap()
}
}
impl<T: Copy> HostData<T> {
pub fn set(&mut self, value: T) {
*(self.0.lock().unwrap()) = value;
}
pub fn get(&mut self) -> T {
*(self.0.lock().unwrap())
}
}
#[derive(Clone, Default)]
pub struct ClockedQueue<T>(Arc<Mutex<VecDeque<(ClockTime, T)>>>, usize);

View File

@ -4,7 +4,7 @@ mod decode_unit_tests {
use std::rc::Rc;
use std::cell::RefCell;
use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, wrap_transmutable};
use moa_core::{Bus, BusPort, ClockTime, Address, Addressable, MemoryBlock, wrap_transmutable};
use crate::M68kType;
use crate::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister};
@ -22,7 +22,7 @@ mod decode_unit_tests {
} else {
BusPort::new(0, 32, 32, bus)
};
let decoder = M68kDecoder::new(cputype, 0);
let decoder = M68kDecoder::new(cputype, ClockTime::START, 0);
(port, decoder)
}
@ -57,7 +57,7 @@ mod decode_unit_tests {
let size = Size::Long;
let expected = 0x12345678;
port.write_beu32(INIT_ADDR, expected).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b010, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectAReg(2));
@ -70,7 +70,7 @@ mod decode_unit_tests {
let size = Size::Long;
let expected = 0x12345678;
port.write_beu32(INIT_ADDR, expected).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b011, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectARegInc(2));
@ -83,7 +83,7 @@ mod decode_unit_tests {
let size = Size::Long;
let expected = 0x12345678;
port.write_beu32(INIT_ADDR, expected).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b100, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectARegDec(2));
@ -96,7 +96,7 @@ mod decode_unit_tests {
let size = Size::Long;
let offset = -8;
port.write_beu16(INIT_ADDR, (offset as i16) as u16).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b101, 0b100, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset));
@ -110,8 +110,8 @@ mod decode_unit_tests {
let offset = -8;
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
port.write_beu16(INIT_ADDR, brief_extension).unwrap();
port.write_beu16(INIT_ADDR + 2, (offset as i16) as u16).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, brief_extension).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset));
@ -125,8 +125,8 @@ mod decode_unit_tests {
let offset = -1843235 as i32;
let brief_extension = 0xF330;
port.write_beu16(INIT_ADDR, brief_extension).unwrap();
port.write_beu32(INIT_ADDR + 2, offset as u32).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, brief_extension).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
@ -140,8 +140,8 @@ mod decode_unit_tests {
let offset = -1843235 as i32;
let brief_extension = 0xF3B0;
port.write_beu16(INIT_ADDR, brief_extension).unwrap();
port.write_beu32(INIT_ADDR + 2, offset as u32).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, brief_extension).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
@ -155,8 +155,8 @@ mod decode_unit_tests {
let offset = -1843235 as i32;
let brief_extension = 0xF370;
port.write_beu16(INIT_ADDR, brief_extension).unwrap();
port.write_beu32(INIT_ADDR + 2, offset as u32).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, brief_extension).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset));
@ -169,7 +169,7 @@ mod decode_unit_tests {
let size = Size::Long;
let offset = -8;
port.write_beu16(INIT_ADDR, (offset as i16) as u16).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset));
@ -183,8 +183,8 @@ mod decode_unit_tests {
let offset = -8;
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
port.write_beu16(INIT_ADDR, brief_extension).unwrap();
port.write_beu16(INIT_ADDR + 2, (offset as i16) as u16).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, brief_extension).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b011, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset));
@ -198,8 +198,8 @@ mod decode_unit_tests {
let offset = -1843235 as i32;
let brief_extension = 0xF330;
port.write_beu16(INIT_ADDR, brief_extension).unwrap();
port.write_beu32(INIT_ADDR + 2, offset as u32).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, brief_extension).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b011, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
@ -213,7 +213,7 @@ mod decode_unit_tests {
let size = Size::Word;
let expected = 0x1234;
port.write_beu16(INIT_ADDR, expected as u16).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, expected as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b000, Some(size)).unwrap();
assert_eq!(target, Target::IndirectMemory(expected, Size::Word));
@ -226,7 +226,7 @@ mod decode_unit_tests {
let size = Size::Word;
let expected = 0x12345678;
port.write_beu32(INIT_ADDR, expected).unwrap();
port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b001, Some(size)).unwrap();
assert_eq!(target, Target::IndirectMemory(expected, Size::Long));
@ -239,7 +239,7 @@ mod decode_unit_tests {
let size = Size::Word;
let expected = 0x1234;
port.write_beu16(INIT_ADDR, expected as u16).unwrap();
port.write_beu16(ClockTime::START, INIT_ADDR, expected as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b100, Some(size)).unwrap();
assert_eq!(target, Target::Immediate(expected));
@ -249,7 +249,7 @@ mod decode_unit_tests {
#[cfg(test)]
mod execute_unit_tests {
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, wrap_transmutable};
use moa_core::{System, MemoryBlock, BusPort, ClockTime, Frequency, Address, Addressable, Steppable, wrap_transmutable};
use crate::{M68k, M68kType};
use crate::execute::Used;
@ -265,17 +265,17 @@ mod execute_unit_tests {
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(mem)).unwrap();
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
system.get_bus().write_beu32(system.clock, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(system.clock, 4, INIT_ADDR as u32).unwrap();
let port = if cputype <= M68kType::MC68010 {
BusPort::new(0, 24, 16, system.bus.clone())
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
cpu.step(&system).unwrap();
cpu.decoder.init(cpu.state.pc);
cpu.decoder.init(system.clock, cpu.state.pc);
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
@ -319,7 +319,7 @@ mod execute_unit_tests {
let size = Size::Long;
let expected = 0x12345678;
let target = Target::IndirectAReg(2);
cpu.port.write_beu32(INIT_ADDR, expected).unwrap();
cpu.port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
cpu.state.a_reg[2] = INIT_ADDR as u32;
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
@ -333,7 +333,7 @@ mod execute_unit_tests {
let size = Size::Long;
let expected = 0x12345678;
let target = Target::IndirectARegInc(2);
cpu.port.write_beu32(INIT_ADDR, expected).unwrap();
cpu.port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
cpu.state.a_reg[2] = INIT_ADDR as u32;
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
@ -348,7 +348,7 @@ mod execute_unit_tests {
let size = Size::Long;
let expected = 0x12345678;
let target = Target::IndirectARegDec(2);
cpu.port.write_beu32(INIT_ADDR, expected).unwrap();
cpu.port.write_beu32(ClockTime::START, INIT_ADDR, expected).unwrap();
cpu.state.a_reg[2] = (INIT_ADDR as u32) + 4;
let result = cpu.get_target_value(target, size, Used::Once).unwrap();

View File

@ -1,5 +1,5 @@
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_core::{System, MemoryBlock, BusPort, ClockTime, Frequency, Address, Addressable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction, ShiftDirection};
@ -68,8 +68,8 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(mem)).unwrap();
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap();
// Initialize the CPU and make sure it's in the expected state
let port = if cputype <= M68kType::MC68010 {
@ -77,12 +77,12 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
cpu.init().unwrap();
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
cpu.decoder.init(INIT_ADDR as u32);
cpu.decoder.init(ClockTime::START, INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(cpu, system)
@ -91,7 +91,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
fn load_memory(system: &System, data: &[u16]) {
let mut addr = INIT_ADDR;
for word in data {
system.get_bus().write_beu16(addr, *word).unwrap();
system.get_bus().write_beu16(system.clock, addr, *word).unwrap();
addr += 2;
}
}

View File

@ -1,5 +1,5 @@
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, wrap_transmutable};
use moa_core::{System, MemoryBlock, BusPort, ClockTime, Frequency, Address, Addressable, Steppable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::state::M68kState;
@ -39,17 +39,17 @@ fn init_execute_test(cputype: M68kType) -> (M68k, System) {
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(mem)).unwrap();
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap();
let port = if cputype <= M68kType::MC68010 {
BusPort::new(0, 24, 16, system.bus.clone())
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
cpu.step(&system).unwrap();
cpu.decoder.init(cpu.state.pc);
cpu.decoder.init(system.clock, cpu.state.pc);
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
@ -71,7 +71,7 @@ fn build_state(state: &TestState) -> M68kState {
fn load_memory(system: &System, data: &[u16]) {
for i in 0..data.len() {
system.get_bus().write_beu16((i << 1) as Address, data[i]).unwrap();
system.get_bus().write_beu16(system.clock, (i << 1) as Address, data[i]).unwrap();
}
}
@ -80,7 +80,7 @@ fn run_test(case: &TestCase) {
let init_state = build_state(&case.init);
let mut expected_state = build_state(&case.fini);
system.get_bus().write_beu32(MEM_ADDR as Address, case.init.mem).unwrap();
system.get_bus().write_beu32(system.clock, MEM_ADDR as Address, case.init.mem).unwrap();
load_memory(&system, case.data);
cpu.state = init_state;
@ -92,7 +92,7 @@ fn run_test(case: &TestCase) {
expected_state.request = cpu.state.request.clone();
assert_eq!(cpu.state, expected_state);
let mem = system.get_bus().read_beu32(MEM_ADDR as Address).unwrap();
let mem = system.get_bus().read_beu32(system.clock, MEM_ADDR as Address).unwrap();
assert_eq!(mem, case.fini.mem);
}

View File

@ -1,5 +1,5 @@
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_core::{System, Error, MemoryBlock, BusPort, ClockTime, Frequency, Address, Addressable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::instructions::{Instruction, Target, Size, Sign, Condition, XRegister, BaseRegister, IndexRegister, Direction, ShiftDirection};
@ -16,8 +16,8 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(mem)).unwrap();
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap();
// Initialize the CPU and make sure it's in the expected state
let port = if cputype <= M68kType::MC68010 {
@ -25,12 +25,12 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
cpu.init().unwrap();
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
cpu.decoder.init(INIT_ADDR as u32);
cpu.decoder.init(ClockTime::START, INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(cpu, system)
@ -39,7 +39,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
fn load_memory(system: &System, data: &[u16]) {
let mut addr = INIT_ADDR;
for word in data {
system.get_bus().write_beu16(addr, *word).unwrap();
system.get_bus().write_beu16(system.clock, addr, *word).unwrap();
addr += 2;
}
}

View File

@ -1,5 +1,5 @@
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_core::{System, Error, MemoryBlock, BusPort, ClockTime, Frequency, Address, Addressable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::instructions::{Instruction, Target, Size};
@ -28,8 +28,8 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(mem)).unwrap();
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(ClockTime::START, 4, INIT_ADDR as u32).unwrap();
// Initialize the CPU and make sure it's in the expected state
let port = if cputype <= M68kType::MC68010 {
@ -37,12 +37,12 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
cpu.init().unwrap();
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
cpu.decoder.init(INIT_ADDR as u32);
cpu.decoder.init(ClockTime::START, INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(cpu, system)
@ -51,7 +51,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
fn load_memory(system: &System, data: &[u16]) {
let mut addr = INIT_ADDR;
for word in data {
system.get_bus().write_beu16(addr, *word).unwrap();
system.get_bus().write_beu16(system.clock, addr, *word).unwrap();
addr += 2;
}
}

View File

@ -1,5 +1,5 @@
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_core::{System, MemoryBlock, BusPort, Frequency, Address, Addressable, wrap_transmutable};
use moa_z80::{Z80, Z80Type};
use moa_z80::state::Register;
@ -14,7 +14,7 @@ fn init_decode_test() -> (Z80, System) {
system.add_addressable_device(0x0000, wrap_transmutable(mem)).unwrap();
// Initialize the CPU and make sure it's in the expected state
let mut cpu = Z80::new(Z80Type::Z80, 4_000_000, BusPort::new(0, 16, 8, system.bus.clone()));
let mut cpu = Z80::new(Z80Type::Z80, Frequency::from_mhz(4), BusPort::new(0, 16, 8, system.bus.clone()));
cpu.init().unwrap();
(cpu, system)
@ -22,7 +22,7 @@ fn init_decode_test() -> (Z80, System) {
fn load_memory(system: &System, data: &[u8]) {
for i in 0..data.len() {
system.get_bus().write_u8(i as Address, data[i]).unwrap();
system.get_bus().write_u8(system.clock, i as Address, data[i]).unwrap();
}
}

View File

@ -1,5 +1,5 @@
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_core::{System, MemoryBlock, BusPort, Frequency, Address, Addressable, wrap_transmutable};
use moa_z80::{Z80, Z80Type};
use moa_z80::state::{Z80State, Register};
@ -489,7 +489,7 @@ fn init_execute_test() -> (Z80, System) {
system.add_addressable_device(0x0000, wrap_transmutable(mem)).unwrap();
// Initialize the CPU and make sure it's in the expected state
let mut cpu = Z80::new(Z80Type::Z80, 4_000_000, BusPort::new(0, 16, 8, system.bus.clone()));
let mut cpu = Z80::new(Z80Type::Z80, Frequency::from_mhz(4), BusPort::new(0, 16, 8, system.bus.clone()));
cpu.init().unwrap();
(cpu, system)
@ -514,7 +514,7 @@ fn build_state(state: &TestState) -> Z80State {
fn load_memory(system: &System, data: &[u8]) {
for i in 0..data.len() {
system.get_bus().write_u8(i as Address, data[i]).unwrap();
system.get_bus().write_u8(system.clock, i as Address, data[i]).unwrap();
}
}

View File

@ -75,7 +75,7 @@ impl AudioMixer {
AudioMixer(Arc::new(Mutex::new(AudioMixerInner {
sample_rate,
sources: vec![],
output: AudioOutput::new(),
output: AudioOutput::default(),
})))
}
@ -173,13 +173,15 @@ pub struct AudioOutput {
queue: ClockedQueue<AudioFrame>,
}
impl AudioOutput {
pub fn new() -> Self {
impl Default for AudioOutput {
fn default() -> Self {
Self {
queue: ClockedQueue::new(5000),
}
}
}
impl AudioOutput {
pub fn add_frame(&self, clock: ClockTime, frame: AudioFrame) {
self.queue.push(clock, frame);
}

View File

@ -2,17 +2,15 @@
use std::thread;
use std::time::Duration;
use moa_core::{System, Error, MemoryBlock, BusPort, wrap_transmutable};
use moa_core::{System, Frequency, MemoryBlock, BusPort, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_peripherals_generic::AtaDevice;
use moa_peripherals_motorola::MC68681;
use moa_systems_computie::build_computie;
fn main() {
thread::spawn(|| {
let mut system = System::new();
let mut system = System::default();
let monitor = MemoryBlock::load("binaries/computie/monitor.bin").unwrap();
system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap();
@ -21,15 +19,15 @@ fn main() {
ram.load_at(0, "binaries/computie/kernel.bin").unwrap();
system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap();
let mut ata = AtaDevice::new();
let mut ata = AtaDevice::default();
ata.load("binaries/computie/disk-with-partition-table.img").unwrap();
system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap();
let mut serial = MC68681::new();
let serial = MC68681::default();
system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap();
let mut cpu = M68k::new(M68kType::MC68010, 8_000_000, BusPort::new(0, 24, 16, system.bus.clone()));
let cpu = M68k::new(M68kType::MC68010, Frequency::from_mhz(8), BusPort::new(0, 24, 16, system.bus.clone()));
//cpu.enable_tracing();
//cpu.add_breakpoint(0x10781a);

View File

@ -86,7 +86,6 @@ impl NoiseGenerator {
pub struct Sn76489 {
clock_frequency: Frequency,
first_byte: Option<u8>,
source: Box<dyn Audio>,
tones: Vec<ToneGenerator>,
@ -94,12 +93,11 @@ pub struct Sn76489 {
}
impl Sn76489 {
pub fn new<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
pub fn new<H: Host>(host: &mut H, _clock_frequency: Frequency) -> Result<Self, Error> {
let source = host.add_audio_source()?;
let sample_rate = source.samples_per_second();
Ok(Self {
clock_frequency,
first_byte: None,
source,
tones: vec![ToneGenerator::new(sample_rate); 3],

View File

@ -300,7 +300,7 @@ impl EnvelopeGenerator {
EnvelopeState::Sustain |
EnvelopeState::Release => {
// Convert it to a fixed point decimal number of 4 bit : 8 bits, which will be the output
self.envelope = self.envelope + (increment << 2);
self.envelope += increment << 2;
if self.envelope > MAX_ENVELOPE || self.envelope_state == EnvelopeState::Release && self.envelope >= ENVELOPE_CENTER {
self.envelope = MAX_ENVELOPE;
}
@ -680,14 +680,6 @@ impl Channel {
}
}
fn sign_extend_u16(value: u16, size: usize) -> i16 {
if value & (1 << (size + 1)) == 0 {
value as i16
} else {
(value | 0xFFFF << (size + 1)) as i16
}
}
struct Dac {
enabled: bool,
@ -726,7 +718,6 @@ pub struct Ym2612 {
selected_reg_0: Option<NonZeroU8>,
selected_reg_1: Option<NonZeroU8>,
clock_frequency: Frequency,
fm_clock_period: ClockDuration,
next_fm_clock: FmClock,
envelope_clock: EnvelopeClock,
@ -758,7 +749,6 @@ impl Ym2612 {
selected_reg_0: None,
selected_reg_1: None,
clock_frequency,
fm_clock_period,
next_fm_clock: 0,
envelope_clock: 0,

View File

@ -1,7 +1,7 @@
use moa_core::{warn, info};
use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{self, Host, HostData, ControllerDevice, ControllerInput, ControllerEvent, EventReceiver};
use moa_core::{System, Error, ClockTime, ClockDuration, Signal, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{self, Host, ControllerDevice, ControllerInput, ControllerEvent, EventReceiver};
const REG_VERSION: Address = 0x01;
@ -91,7 +91,7 @@ pub struct GenesisControllers {
port_1: GenesisControllerPort,
port_2: GenesisControllerPort,
expansion: GenesisControllerPort,
interrupt: HostData<bool>,
interrupt: Signal<bool>,
reset_timer: ClockDuration,
}
@ -105,12 +105,12 @@ impl GenesisControllers {
port_1: GenesisControllerPort::default(),
port_2: GenesisControllerPort::default(),
expansion: GenesisControllerPort::default(),
interrupt: HostData::new(false),
interrupt: Signal::new(false),
reset_timer: ClockDuration::ZERO,
})
}
pub fn get_interrupt_signal(&self) -> HostData<bool> {
pub fn get_interrupt_signal(&self) -> Signal<bool> {
self.interrupt.clone()
}

View File

@ -1,7 +1,7 @@
use moa_core::{debug, warn, error};
use moa_core::{System, Error, EdgeSignal, ClockTime, ClockDuration, Frequency, Address, Addressable, Steppable, Inspectable, Transmutable, TransmutableBox, read_beu16, dump_slice};
use moa_core::host::{self, Host, Pixel, PixelEncoding, Frame, FrameSender, HostData};
use moa_core::{System, Error, EdgeSignal, ClockTime, ClockDuration, Frequency, Signal, Address, Addressable, Steppable, Inspectable, Transmutable, TransmutableBox, read_beu16, dump_slice};
use moa_core::host::{self, Host, Pixel, PixelEncoding, Frame, FrameSender};
const REG_MODE_SET_1: usize = 0x00;
@ -685,12 +685,12 @@ pub struct Ym7101 {
state: Ym7101State,
sn_sound: TransmutableBox,
pub external_interrupt: HostData<bool>,
pub external_interrupt: Signal<bool>,
pub frame_complete: EdgeSignal,
}
impl Ym7101 {
pub fn new<H: Host>(host: &mut H, external_interrupt: HostData<bool>, sn_sound: TransmutableBox) -> Ym7101 {
pub fn new<H: Host>(host: &mut H, external_interrupt: Signal<bool>, sn_sound: TransmutableBox) -> Ym7101 {
let (sender, receiver) = host::frame_queue(320, 224);
host.add_video_source(receiver).unwrap();

View File

@ -0,0 +1,129 @@
Last run on 2022-09-18 at commit 94d3e1d3894e6588ff6daa55f0ba82473b1e74c7
ABCD.json completed: 7993 passed, 72 FAILED
ADD.b.json completed, all passed!
ADD.l.json completed: 7736 passed, 329 FAILED
ADD.w.json completed: 7712 passed, 353 FAILED
ADDA.l.json completed, all passed!
ADDA.w.json completed, all passed!
ADDX.b.json completed, all passed!
ADDX.l.json completed: 5472 passed, 2593 FAILED
ADDX.w.json completed, all passed!
AND.b.json completed, all passed!
AND.l.json completed: 7779 passed, 286 FAILED
AND.w.json completed: 7764 passed, 301 FAILED
ANDItoCCR.json completed, all passed!
ANDItoSR.json completed, all passed!
ASL.b.json completed: 7238 passed, 827 FAILED
ASL.l.json completed: 6471 passed, 1594 FAILED
ASL.w.json completed: 7053 passed, 1012 FAILED
ASR.b.json completed: 7547 passed, 518 FAILED
ASR.l.json completed: 7092 passed, 973 FAILED
ASR.w.json completed: 7513 passed, 552 FAILED
BCHG.json completed, all passed!
BCLR.json completed, all passed!
BSET.json completed, all passed!
BSR.json completed, all passed!
BTST.json completed: 8052 passed, 13 FAILED
Bcc.json completed, all passed!
CHK.json completed: 7744 passed, 321 FAILED
CLR.b.json completed, all passed!
CLR.l.json completed: 7472 passed, 593 FAILED
CLR.w.json completed: 7465 passed, 600 FAILED
CMP.b.json completed, all passed!
CMP.l.json completed, all passed!
CMP.w.json completed, all passed!
CMPA.l.json completed, all passed!
CMPA.w.json completed, all passed!
DBcc.json completed, all passed!
DIVS.json completed, all passed!
DIVU.json completed: 8064 passed, 1 FAILED
EOR.b.json completed, all passed!
EOR.l.json completed: 7519 passed, 546 FAILED
EOR.w.json completed: 7525 passed, 540 FAILED
EORItoCCR.json completed, all passed!
EORItoSR.json completed, all passed!
EXG.json completed, all passed!
EXT.l.json completed, all passed!
EXT.w.json completed, all passed!
JMP.json completed, all passed!
JSR.json completed, all passed!
LEA.json completed, all passed!
LINK.json completed, all passed!
LSL.b.json completed: 7809 passed, 256 FAILED
LSL.l.json completed: 7056 passed, 1009 FAILED
LSL.w.json completed: 7523 passed, 542 FAILED
LSR.b.json completed: 7817 passed, 248 FAILED
LSR.l.json completed: 7072 passed, 993 FAILED
LSR.w.json completed: 7541 passed, 524 FAILED
MOVE.b.json completed, all passed!
MOVE.l.json completed: 5827 passed, 2238 FAILED
MOVE.q.json completed, all passed!
MOVE.w.json completed: 5855 passed, 2210 FAILED
MOVEA.l.json completed, all passed!
MOVEA.w.json completed, all passed!
MOVEM.l.json completed: 6035 passed, 2030 FAILED
MOVEM.w.json completed: 6431 passed, 1634 FAILED
MOVEP.l.json completed: 4036 passed, 4029 FAILED
MOVEP.w.json completed: 4046 passed, 4019 FAILED
MOVEfromSR.json completed: 6896 passed, 1169 FAILED
MOVEfromUSP.json completed, all passed!
MOVEtoCCR.json completed, all passed!
MOVEtoSR.json completed, all passed!
MOVEtoUSP.json completed, all passed!
MULS.json completed, all passed!
MULU.json completed, all passed!
NBCD.json completed: 8037 passed, 28 FAILED
NEG.b.json completed, all passed!
NEG.l.json completed: 7552 passed, 513 FAILED
NEG.w.json completed: 7531 passed, 534 FAILED
NEGX.b.json completed, all passed!
NEGX.l.json completed: 7520 passed, 545 FAILED
NEGX.w.json completed: 7510 passed, 555 FAILED
NOP.json completed, all passed!
NOT.b.json completed, all passed!
NOT.l.json completed: 7512 passed, 553 FAILED
NOT.w.json completed: 7530 passed, 535 FAILED
OR.b.json completed, all passed!
OR.l.json completed: 7756 passed, 309 FAILED
OR.w.json completed: 7765 passed, 300 FAILED
ORItoCCR.json completed, all passed!
ORItoSR.json completed, all passed!
PEA.json completed, all passed!
RESET.json completed, all passed!
ROL.b.json completed, all passed!
ROL.l.json completed, all passed!
ROL.w.json completed: 7882 passed, 183 FAILED
ROR.b.json completed, all passed!
ROR.l.json completed, all passed!
ROR.w.json completed: 7907 passed, 158 FAILED
ROXL.b.json completed: 8039 passed, 26 FAILED
ROXL.l.json completed: 8029 passed, 36 FAILED
ROXL.w.json completed: 7892 passed, 173 FAILED
ROXR.b.json completed: 8037 passed, 28 FAILED
ROXR.l.json completed: 8022 passed, 43 FAILED
ROXR.w.json completed: 7880 passed, 185 FAILED
RTE.json completed, all passed!
RTR.json completed, all passed!
RTS.json completed, all passed!
SBCD.json completed: 6809 passed, 1256 FAILED
SUB.b.json completed, all passed!
SUB.l.json completed: 7747 passed, 318 FAILED
SUB.w.json completed: 7716 passed, 349 FAILED
SUBA.l.json completed, all passed!
SUBA.w.json completed, all passed!
SUBX.b.json completed, all passed!
SUBX.l.json completed: 5481 passed, 2584 FAILED
SUBX.w.json completed, all passed!
SWAP.json completed, all passed!
Scc.json completed, all passed!
TAS.json completed, all passed!
TRAP.json completed, all passed!
TRAPV.json completed, all passed!
TST.b.json completed, all passed!
TST.l.json completed, all passed!
TST.w.json completed, all passed!
UNLINK.json completed, all passed!
passed: 957924, failed: 42136, total 96%
completed in 24m 47s

View File

@ -11,7 +11,7 @@ use clap::{Parser, ArgEnum};
use flate2::read::GzDecoder;
use serde_derive::Deserialize;
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Steppable, wrap_transmutable};
use moa_core::{System, Error, MemoryBlock, BusPort, Frequency, Address, Addressable, Steppable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::state::Status;
@ -149,7 +149,7 @@ fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, Syst
} else {
BusPort::new(0, 32, 32, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
cpu.state.status = Status::Running;
load_state(&mut cpu, &mut system, state)?;
@ -189,12 +189,12 @@ fn load_state(cpu: &mut M68k, system: &mut System, initial: &TestState) -> Resul
// Load instructions into memory
for (i, ins) in initial.prefetch.iter().enumerate() {
system.get_bus().write_beu16((initial.pc + (i as u32 * 2)) as u64, *ins)?;
system.get_bus().write_beu16(system.clock, (initial.pc + (i as u32 * 2)) as u64, *ins)?;
}
// Load data bytes into memory
for (addr, byte) in initial.ram.iter() {
system.get_bus().write_u8(*addr as u64, *byte)?;
system.get_bus().write_u8(system.clock, *addr as u64, *byte)?;
}
Ok(())
@ -227,13 +227,13 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(),
// Load instructions into memory
for (i, ins) in expected.prefetch.iter().enumerate() {
let addr = expected.pc + (i as u32 * 2);
let actual = system.get_bus().read_beu16(addr as Address & addr_mask)?;
let actual = system.get_bus().read_beu16(system.clock, addr as Address & addr_mask)?;
assert_value(actual, *ins, &format!("prefetch at {:x}", addr))?;
}
// Load data bytes into memory
for (addr, byte) in expected.ram.iter() {
let actual = system.get_bus().read_u8(*addr as Address & addr_mask)?;
let actual = system.get_bus().read_u8(system.clock, *addr as Address & addr_mask)?;
assert_value(actual, *byte, &format!("ram at {:x}", addr))?;
}
@ -242,7 +242,7 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(),
fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_timing: bool) -> Result<(), Error> {
let clock_elapsed = cpu.step(&system)?;
let cycles = clock_elapsed / (1_000_000_000 / cpu.frequency as u64);
let cycles = clock_elapsed / cpu.frequency.period_duration();
assert_state(&cpu, &system, &case.final_state)?;
@ -265,8 +265,8 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
if args.debug {
case.dump();
println!("");
initial_cpu.dump_state();
cpu.dump_state();
initial_cpu.dump_state(system.clock);
cpu.dump_state(system.clock);
}
println!("FAILED: {}", err.msg);
}

144
todo.txt
View File

@ -1,112 +1,65 @@
* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used
* sound doesn't work on a lot of games... is it a problem with the Z80 accessing the YM2612, or the lack of YM timers? or something else?
* make the ym generate audio in sync so the DAC timings can be more accurate
* add stereo output to ym2612
* you need to scale the output sample to be +/- 1.0 instead of 0-1.0
* fix ym2612 sound generation (no drums/bass, no LFO, etc)
* what if, to allow a device to have multiple steppable functions, you pass the system in, or otherwise provide some mechanism for
each device to create sub devices which are scheduled independently
* for some unknown reason, the js-based updater works much better than the rust based one, but the rust based one just goes back to
a fixed time per loop instead of trying to speed up
* need to remove HostData and replace the interrupt with Signal
* make Signal directional, by making SignalDriver and SignalInput or SignalReceiver
* should you combine the input updaters into one thing and have a queue for communicating? Even if you have 3 input channels, you can
make them all use the same generic type for the input queue
* you need to refactor the audio mixer stuff to reject data quicker and stay in sync, but how to deal with sim time-dilation
* make the pixels frontend use an rc refcell object, or rc object to directly control the frontend object while also making it accessible
to the run loop
* add support for the controller inputs in the pixels web frontend
* clean up pixels frontend
* make the ym generate audio in sync so the DAC timings can be more accurate
* change the host things to use queues instead
* add rust runtime checks for math to look for overflow errors
* I think the overflowing add and subs return the original number and not the overflowed result. I might have already checked that
in the m68k impl but I should check again
* you need to scale the output sample to be +/- 1.0 instead of 0-1.0
* AudioFrame (and possibly the mixer and source) should be moved to the core, it should probably have the sample rate
* need to be able to support stereo output eventually
* can you make the frontend more adaptive to the input that the devices are using
* change the name of the functions that take Host to be `with_host` or `register` or something
* need to re-add a mechanism for audio frame dialation, either based on speed, or somehow automatic, use clocks and make them aligned
* maybe I should make ClockDuration use picos as the base instead, and use u64 since that gives like 212 days or something instead of 5h
and should prevent split nanoseconds which is the main concern
* the audio needs to not run if nothing is using it or there's constant buffer underruns
* fix ym2612 sound generation
* sound doesn't work on a lot of games... is it a problem with the Z80 accessing the YM2612, or the lack of YM timers? or something else?
* add opentelemetry if it can be wasm compatible, or some kind of timing for giving an average framerate
* add doc strings everywhere
* get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion
* the interrupt controller stuff is really not good. It should be more like busport, and connected to a device at startup (eg. create
interrupt controller, then create objects that use that controller and pass in values, maybe an option so that the controller doesn't
have to be hooked up, meaning hardware interrupts would not be used.
* along with the interrupt stuff, I'm kind of thinking of packaging things a bit differently, like using a tuple struct for the rc refcell
transmutable abstraction, so that you can avoid the need for explicit borrows
* improve performance
* should it be possible to reschedule multiple events at different intervals to reduce the times a given step function is called? Some have
multiple clocks, or multiple things at different clocks, and making them each an event would mean they could be smaller and faster, but at
the cost of having more events on the queue when re-scheduling. There needs to be a mechanism to avoid the event queue ballooning due to
an error
* can you somehow make devices have two step functions for running things at different times? (I'm thinking ym2612 audio gen vs timers)
* for some unknown reason, the js-based updater works much better than the rust based one, but the rust based one just goes back to
a fixed time per loop instead of trying to speed up
* can you refactor the update timeout to put it in rust? Would that make it faster? (the tricky part is the closure)
* make Signal directional, by making SignalDriver and SignalInput or SignalReceiver
* clean up pixels frontend
* modify cpal code to skip audio until caught up
* AudioFrame (and possibly the mixer and source) should be moved to the core, it should probably have the sample rate
* split AudioOutput into a sender and receiver
* can you eliminate the source-to-mixer queues?
* should you rename devices.rs traits.rs?
* the interrupt controller stuff is really not good. It should be more like busport, and connected to a device at startup (eg. create
interrupt controller, then create objects that use that controller and pass in values, maybe an option so that the controller doesn't
have to be hooked up, meaning hardware interrupts would not be used.
* I'm kind of thinking of packaging things a bit differently, like using a tuple struct for the rc refcell
transmutable abstraction, so that you can avoid the need for explicit borrows
* add rust runtime checks for math to look for overflow errors
* I think the overflowing add and subs return the original number and not the overflowed result. I might have already checked that
in the m68k impl but I should check again
* double check the functioning of the banked areas and register settings for Z80 coprocessor
* test the Z80 more, add tests
* add opentelemetry if it can be wasm compatible, or some kind of timing for giving an average framerate
* improve performance
* can you make the frontend more adaptive to the input that the devices are using
* maybe I should make ClockDuration use picos as the base instead, and use u64 since that gives like 212 days or something instead of 5h
and should prevent split nanoseconds which is the main concern
* make the keys easier to config...
* add doc strings everywhere
* get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion
* add ability to serialize/deserialize state into something, so it can be restored... (maybe not worth it though)
* can you refactor the update timeout to put it in rust? Would that make it faster? (the tricky part is the closure)
* re-enable sound on webassembly, see if it works (it does not. Very lagged and jittery with what sounds like repeated frames)
* can you somehow speed up the memory accessing through the sim? The dyn Addressable is causing a fair amount of overhead
* can you somehow make devices have two step functions for running things at different times? (I'm thinking ym2612 audio gen vs timers)
* should you rename devices.rs traits.rs?
* the pixel format idea didn't work because of window resizing and the fact that the frame needs to be adjusted in size because the window can't always be resized...
* add mouse support to synth app
* test the Z80 more, add tests
* double check the functioning of the banked areas and register settings for Z80 coprocessor
* make the keys easier to config...
* can you make the debugger more accessible, so a web interface could access the data and display it, in light of the fact that println isn't available in wasm
Web Assembly:
* can you make the web interface nicer with like... a picture of a genesis or something
* would a different pixel format help at all?
* can you limit the size of the window that pixels generates?
* can you automatically adjust the speed based on the calculated framerate (if you moved that to Rust)
* enable sound in web assembly
* add ability to disable one or the other audio chips in the genesis
* make it possible to disable audio in browser
* make it possible to compile without audio support (minifb frontend requires it atm)
* should you have a separate attenuation value for each input in the mixer so that you can make one chip quieter (the sn76489 is pretty loud, and I added a fixed offset to the attenuation for now)
Audio:
* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used
* should you represent audio as frequencies rather than amplitude so that time dilation is more accurate? Would possible require less
accurate simulation of the audio
* Removing at a sample-level granularity would compress or lengthen the waveforms, so it would be better to mix/drop a whole chunk at
once (either predetermined by the audio system or determined by each device by the amount of samples it writes at once). The chunk
size could either be specified by the device in microseconds or something, or can be inferred by the sample_rate and the size of the
chunk.
* you could make the sound device be an object that is passed back to the simulation section like SimplePty. You need to either register
a callback with the frontend sound system that is called when it needs data, or you write to a shared buffer which is passed back to the
frontend when it needs it, or it has a copy it can use directly
System/Traits:
@ -140,9 +93,6 @@ Genesis/Mega Drive:
* there is an issue with Mortal Kombat 2 where it will crash randomly at the start of a fight. The code is actually swapping
stacks a bunch of times, and at some point, the stack is corrupted or something and it `rts`s to the wrong address...
* implement sn76489 and ym2612 for audio
* there's a bug when Sonic 2 goes to the demo screen, it's all corrupted (could it be a dma copy error)
* the 68000/Z80 bank switching is probably buggy
* the H/V counters are not accurate because it seems to count at different speeds in the blanking period (time vs return value numbers don't divide properly)
* make the ym7101 set/reset the v_int occurred flag based on the interrupt controller
@ -167,9 +117,13 @@ Macintosh:
Z80:
* add instruction timings to Z80
* unimplemented: CPD, CPDR, CPI, CPIR, DAA, IND, INDR, INI, INIR, INic, INx, OTDR, OTIR, OUTD, OUTI, OUTic, OUTx, RETI, RETN, RLD, RRD
Synth:
* add mouse support to synth app
* can you eventually make the system connections all configurable via a config file?