diff --git a/emulator/core/src/clock.rs b/emulator/core/src/clock.rs index 88c4fcc..17b1bdf 100644 --- a/emulator/core/src/clock.rs +++ b/emulator/core/src/clock.rs @@ -1,5 +1,5 @@ -/// Clock time and duration types for simulation with femtosecond accurancy -/// +//! Clock time and duration types for simulation with femtosecond accurancy +//! use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign}; diff --git a/emulator/core/src/debugger.rs b/emulator/core/src/debugger.rs index 54e0ed2..8280e8d 100644 --- a/emulator/core/src/debugger.rs +++ b/emulator/core/src/debugger.rs @@ -116,7 +116,7 @@ impl Debugger { if args.len() > 1 { let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; let len = if args.len() > 2 { u32::from_str_radix(args[2], 16).map_err(|_| Error::new("Unable to parse length"))? } else { 0x20 }; - system.get_bus().dump_memory(addr as Address, len as Address); + system.get_bus().dump_memory(system.clock, addr as Address, len as Address); } else { //self.port.dump_memory(self.state.ssp as Address, 0x40 as Address); } @@ -167,9 +167,9 @@ impl Debugger { let addr = u64::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse set address"))?; let data = u32::from_str_radix(args[2], 16).map_err(|_| Error::new("Unable to parse data"))?; match args[0] { - "setb" => system.get_bus().write_u8(addr, data as u8)?, - "setw" => system.get_bus().write_beu16(addr, data as u16)?, - "setl" => system.get_bus().write_beu32(addr, data)?, + "setb" => system.get_bus().write_u8(system.clock, addr, data as u8)?, + "setw" => system.get_bus().write_beu16(system.clock, addr, data as u16)?, + "setl" => system.get_bus().write_beu32(system.clock, addr, data)?, _ => panic!("Unimplemented: {:?}", args[0]), } } diff --git a/emulator/core/src/devices.rs b/emulator/core/src/devices.rs index b2c1e58..036db21 100644 --- a/emulator/core/src/devices.rs +++ b/emulator/core/src/devices.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use crate::error::Error; use crate::system::System; -use crate::clock::ClockDuration; +use crate::clock::{ClockTime, ClockDuration}; /// A universal memory address used by the Addressable trait @@ -30,66 +30,66 @@ pub trait Interruptable { #[allow(clippy::len_without_is_empty)] pub trait Addressable { fn len(&self) -> usize; - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error>; - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error>; + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error>; + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error>; - fn read_u8(&mut self, addr: Address) -> Result { + fn read_u8(&mut self, clock: ClockTime, addr: Address) -> Result { let mut data = [0; 1]; - self.read(addr, &mut data)?; + self.read(clock, addr, &mut data)?; Ok(data[0]) } - fn read_beu16(&mut self, addr: Address) -> Result { + fn read_beu16(&mut self, clock: ClockTime, addr: Address) -> Result { let mut data = [0; 2]; - self.read(addr, &mut data)?; + self.read(clock, addr, &mut data)?; Ok(read_beu16(&data)) } - fn read_leu16(&mut self, addr: Address) -> Result { + fn read_leu16(&mut self, clock: ClockTime, addr: Address) -> Result { let mut data = [0; 2]; - self.read(addr, &mut data)?; + self.read(clock, addr, &mut data)?; Ok(read_leu16(&data)) } - fn read_beu32(&mut self, addr: Address) -> Result { + fn read_beu32(&mut self, clock: ClockTime, addr: Address) -> Result { let mut data = [0; 4]; - self.read(addr, &mut data)?; + self.read(clock, addr, &mut data)?; Ok(read_beu32(&data)) } - fn read_leu32(&mut self, addr: Address) -> Result { + fn read_leu32(&mut self, clock: ClockTime, addr: Address) -> Result { let mut data = [0; 4]; - self.read(addr, &mut data)?; + self.read(clock, addr, &mut data)?; Ok(read_leu32(&data)) } - fn write_u8(&mut self, addr: Address, value: u8) -> Result<(), Error> { + fn write_u8(&mut self, clock: ClockTime, addr: Address, value: u8) -> Result<(), Error> { let data = [value]; - self.write(addr, &data) + self.write(clock, addr, &data) } - fn write_beu16(&mut self, addr: Address, value: u16) -> Result<(), Error> { + fn write_beu16(&mut self, clock: ClockTime, addr: Address, value: u16) -> Result<(), Error> { let mut data = [0; 2]; write_beu16(&mut data, value); - self.write(addr, &data) + self.write(clock, addr, &data) } - fn write_leu16(&mut self, addr: Address, value: u16) -> Result<(), Error> { + fn write_leu16(&mut self, clock: ClockTime, addr: Address, value: u16) -> Result<(), Error> { let mut data = [0; 2]; write_leu16(&mut data, value); - self.write(addr, &data) + self.write(clock, addr, &data) } - fn write_beu32(&mut self, addr: Address, value: u32) -> Result<(), Error> { + fn write_beu32(&mut self, clock: ClockTime, addr: Address, value: u32) -> Result<(), Error> { let mut data = [0; 4]; write_beu32(&mut data, value); - self.write(addr, &data) + self.write(clock, addr, &data) } - fn write_leu32(&mut self, addr: Address, value: u32) -> Result<(), Error> { + fn write_leu32(&mut self, clock: ClockTime, addr: Address, value: u32) -> Result<(), Error> { let mut data = [0; 4]; write_leu32(&mut data, value); - self.write(addr, &data) + self.write(clock, addr, &data) } } diff --git a/emulator/core/src/host/gfx.rs b/emulator/core/src/host/gfx.rs index 1bc44e4..a3e92b0 100644 --- a/emulator/core/src/host/gfx.rs +++ b/emulator/core/src/host/gfx.rs @@ -32,11 +32,11 @@ impl Pixel { match encoding { PixelEncoding::RGBA => - ((r as u32) << 24) | ((g as u32) << 16) | ((b as u32) << 8) | (a as u32), + (r << 24) | (g << 16) | (b << 8) | a, PixelEncoding::ARGB => - ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32), + (a << 24) | (r << 16) | (g << 8) | b, PixelEncoding::ABGR => - ((a as u32) << 24) | ((b as u32) << 16) | ((g as u32) << 8) | (r as u32), + (a << 24) | (b << 16) | (g << 8) | r, } } } diff --git a/emulator/core/src/memory.rs b/emulator/core/src/memory.rs index 49dbe3f..47e092a 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -6,6 +6,7 @@ use std::fmt::Write; use crate::info; use crate::error::Error; +use crate::clock::ClockTime; use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_beu16}; @@ -53,12 +54,12 @@ impl Addressable for MemoryBlock { self.contents.len() } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { data.copy_from_slice(&self.contents[(addr as usize)..(addr as usize) + data.len()]); Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { if self.read_only { return Err(Error::breakpoint(&format!("Attempt to write to read-only memory at {:x} with data {:?}", addr, data))); } @@ -95,12 +96,12 @@ impl Addressable for AddressRightShifter { len << self.shift } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { - self.subdevice.borrow_mut().as_addressable().unwrap().read(addr >> self.shift, data) + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { + self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, addr >> self.shift, data) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { - self.subdevice.borrow_mut().as_addressable().unwrap().write(addr >> self.shift, data) + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { + self.subdevice.borrow_mut().as_addressable().unwrap().write(clock, addr >> self.shift, data) } } @@ -130,14 +131,14 @@ impl Addressable for AddressRepeater { self.range as usize } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { let len = self.subdevice.borrow_mut().as_addressable().unwrap().len() as Address; - self.subdevice.borrow_mut().as_addressable().unwrap().read(addr % len, data) + self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, addr % len, data) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { let len = self.subdevice.borrow_mut().as_addressable().unwrap().len() as Address; - self.subdevice.borrow_mut().as_addressable().unwrap().write(addr % len, data) + self.subdevice.borrow_mut().as_addressable().unwrap().write(clock, addr % len, data) } } @@ -193,13 +194,13 @@ impl Bus { Err(Error::new(&format!("No segment found at {:#010x}", addr))) } - pub fn dump_memory(&mut self, mut addr: Address, mut count: Address) { + pub fn dump_memory(&mut self, clock: ClockTime, mut addr: Address, mut count: Address) { while count > 0 { let mut line = format!("{:#010x}: ", addr); let to = if count < 16 { count / 2 } else { 8 }; for _ in 0..to { - let word = self.read_beu16(addr); + let word = self.read_beu16(clock, addr); if word.is_err() { println!("{}", line); return; @@ -236,7 +237,7 @@ impl Addressable for Bus { (block.base as usize) + block.length } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { let (dev, relative_addr) = match self.get_device_at(addr, data.len()) { Ok(result) => result, Err(err) if self.ignore_unmapped => { @@ -245,11 +246,11 @@ impl Addressable for Bus { }, Err(err) => return Err(err), }; - let result = dev.borrow_mut().as_addressable().unwrap().read(relative_addr, data); + let result = dev.borrow_mut().as_addressable().unwrap().read(clock, relative_addr, data); result } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { if self.watchers.iter().any(|a| *a == addr) { println!("watch: writing to address {:#06x} with {:?}", addr, data); self.watcher_modified = true; @@ -263,7 +264,7 @@ impl Addressable for Bus { }, Err(err) => return Err(err), }; - let result = dev.borrow_mut().as_addressable().unwrap().write(relative_addr, data); + let result = dev.borrow_mut().as_addressable().unwrap().write(clock, relative_addr, data); result } } @@ -291,8 +292,8 @@ impl BusPort { } } - pub fn dump_memory(&mut self, addr: Address, count: Address) { - self.subdevice.borrow_mut().dump_memory(self.offset + (addr & self.address_mask), count) + pub fn dump_memory(&mut self, clock: ClockTime, addr: Address, count: Address) { + self.subdevice.borrow_mut().dump_memory(clock, self.offset + (addr & self.address_mask), count) } pub fn address_mask(&self) -> Address { @@ -309,22 +310,22 @@ impl Addressable for BusPort { self.subdevice.borrow().len() } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { let addr = self.offset + (addr & self.address_mask); let mut subdevice = self.subdevice.borrow_mut(); for i in (0..data.len()).step_by(self.data_width as usize) { let end = std::cmp::min(i + self.data_width as usize, data.len()); - subdevice.read(addr + i as Address, &mut data[i..end])?; + subdevice.read(clock, addr + i as Address, &mut data[i..end])?; } Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { let addr = self.offset + (addr & self.address_mask); let mut subdevice = self.subdevice.borrow_mut(); for i in (0..data.len()).step_by(self.data_width as usize) { let end = std::cmp::min(i + self.data_width as usize, data.len()); - subdevice.write(addr + i as Address, &data[i..end])?; + subdevice.write(clock, addr + i as Address, &data[i..end])?; } Ok(()) } diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index f71d4f2..77d5fb5 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, Address, Addressable, Debuggable}; +use moa_core::{System, Error, ClockTime, Address, Addressable, Debuggable}; use super::state::M68k; use super::decode::M68kDecoder; @@ -50,24 +50,24 @@ impl Debuggable for M68k { } } - fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { - self.decoder.decode_at(&mut self.port, self.state.pc)?; + fn print_current_step(&mut self, system: &System) -> Result<(), Error> { + self.decoder.decode_at(&mut self.port, system.clock, self.state.pc)?; self.decoder.dump_decoded(&mut self.port); - self.dump_state(); + self.dump_state(system.clock); Ok(()) } fn print_disassembly(&mut self, addr: Address, count: usize) { - let mut decoder = M68kDecoder::new(self.cputype, 0); + let mut decoder = M68kDecoder::new(self.cputype, ClockTime::START, 0); decoder.dump_disassembly(&mut self.port, addr as u32, count as u32); } - fn execute_command(&mut self, _system: &System, args: &[&str]) -> Result { + fn execute_command(&mut self, system: &System, args: &[&str]) -> Result { match args[0] { "ds" | "stack" | "dumpstack" => { println!("Stack:"); for addr in &self.debugger.stack_tracer.calls { - println!(" {:08x}", self.port.read_beu32(*addr as Address)?); + println!(" {:08x}", self.port.read_beu32(system.clock, *addr as Address)?); } }, "so" | "stepout" => { diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index c59ac9c..bd8a94b 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -1,5 +1,5 @@ -use moa_core::{Error, Address, Addressable}; +use moa_core::{Error, ClockTime, Address, Addressable}; use super::state::{M68kType, Exceptions}; use super::instructions::{ @@ -40,6 +40,7 @@ const OPCG_FLINE: u8 = 0xF; #[derive(Clone)] pub struct M68kDecoder { pub cputype: M68kType, + pub clock: ClockTime, pub start: u32, pub end: u32, pub instruction_word: u16, @@ -47,9 +48,10 @@ pub struct M68kDecoder { } impl M68kDecoder { - pub fn new(cputype: M68kType, start: u32) -> M68kDecoder { + pub fn new(cputype: M68kType, clock: ClockTime, start: u32) -> M68kDecoder { M68kDecoder { cputype, + clock, start, end: start, instruction_word: 0, @@ -58,13 +60,14 @@ impl M68kDecoder { } #[inline(always)] - pub fn init(&mut self, start: u32) { + pub fn init(&mut self, clock: ClockTime, start: u32) { + self.clock = clock; self.start = start; self.end = start; } - pub fn decode_at(&mut self, memory: &mut dyn Addressable, start: u32) -> Result<(), Error> { - self.init(start); + pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: ClockTime, start: u32) -> Result<(), Error> { + self.init(clock, start); self.instruction = self.decode_one(memory)?; Ok(()) } @@ -645,13 +648,13 @@ impl M68kDecoder { } fn read_instruction_word(&mut self, memory: &mut dyn Addressable) -> Result { - let word = memory.read_beu16(self.end as Address)?; + let word = memory.read_beu16(self.clock, self.end as Address)?; self.end += 2; Ok(word) } fn read_instruction_long(&mut self, memory: &mut dyn Addressable) -> Result { - let word = memory.read_beu32(self.end as Address)?; + let word = memory.read_beu32(self.clock, self.end as Address)?; self.end += 4; Ok(word) } @@ -781,7 +784,7 @@ impl M68kDecoder { pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u32, length: u32) { let mut next = start; while next < (start + length) { - match self.decode_at(memory, next) { + match self.decode_at(memory, self.clock, next) { Ok(()) => { self.dump_decoded(memory); next = self.end; @@ -790,7 +793,7 @@ impl M68kDecoder { println!("{:?}", err); match err { Error { native, .. } if native == Exceptions::IllegalInstruction as u32 => { - println!(" at {:08x}: {:04x}", self.start, memory.read_beu16(self.start as Address).unwrap()); + println!(" at {:08x}: {:04x}", self.start, memory.read_beu16(self.clock, self.start as Address).unwrap()); }, _ => { }, } @@ -803,7 +806,7 @@ impl M68kDecoder { pub fn dump_decoded(&mut self, memory: &mut dyn Addressable) { let ins_data: Result = (0..((self.end - self.start) / 2)).map(|offset| - Ok(format!("{:04x} ", memory.read_beu16((self.start + (offset * 2)) as Address).unwrap())) + Ok(format!("{:04x} ", memory.read_beu16(self.clock, (self.start + (offset * 2)) as Address).unwrap())) ).collect(); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); } diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index ebbc95e..1340128 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -34,8 +34,8 @@ impl Steppable for M68k { self.step_internal(system) } - fn on_error(&mut self, _system: &System) { - self.dump_state(); + fn on_error(&mut self, system: &System) { + self.dump_state(system.clock); } } @@ -63,6 +63,7 @@ impl M68k { } pub fn step_internal(&mut self, system: &System) -> Result { + self.current_clock = system.clock; match self.state.status { Status::Init => self.init(), Status::Stopped => Err(Error::new("CPU stopped")), @@ -82,8 +83,8 @@ impl M68k { } pub fn init(&mut self) -> Result { - self.state.ssp = self.port.read_beu32(0)?; - self.state.pc = self.port.read_beu32(4)?; + self.state.ssp = self.port.read_beu32(self.current_clock, 0)?; + self.state.pc = self.port.read_beu32(self.current_clock, 4)?; self.state.status = Status::Running; Ok(self.frequency.period_duration() * 16) } @@ -169,7 +170,7 @@ impl M68k { self.push_word((ins_word & 0xFFF0) | extra_code)?; let vector = self.state.vbr + offset as u32; - let addr = self.port.read_beu32(vector as Address)?; + let addr = self.port.read_beu32(self.current_clock, vector as Address)?; self.set_pc(addr)?; Ok(()) @@ -194,7 +195,7 @@ impl M68k { self.push_word(sr)?; let vector = self.state.vbr + offset as u32; - let addr = self.port.read_beu32(vector as Address)?; + let addr = self.port.read_beu32(self.current_clock, vector as Address)?; self.set_pc(addr)?; Ok(()) @@ -205,7 +206,7 @@ impl M68k { self.timer.decode.start(); self.start_instruction_request(self.state.pc)?; - self.decoder.decode_at(&mut self.port, self.state.pc)?; + self.decoder.decode_at(&mut self.port, self.current_clock, self.state.pc)?; self.timer.decode.end(); self.timing.add_instruction(&self.decoder.instruction); @@ -1011,7 +1012,7 @@ impl M68k { let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address; while shift >= 0 { let byte = (self.state.d_reg[dreg as usize] >> shift) as u8; - self.port.write_u8(addr, byte)?; + self.port.write_u8(self.current_clock, addr, byte)?; addr += 2; shift -= 8; } @@ -1020,7 +1021,7 @@ impl M68k { let mut shift = (size.in_bits() as i32) - 8; let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address; while shift >= 0 { - let byte = self.port.read_u8(addr)?; + let byte = self.port.read_u8(self.current_clock, addr)?; self.state.d_reg[dreg as usize] |= (byte as u32) << shift; addr += 2; shift -= 8; @@ -1542,18 +1543,18 @@ impl M68k { fn get_address_sized(&mut self, addr: Address, size: Size) -> Result { self.start_request(addr as u32, size, MemAccess::Read, MemType::Data, false)?; match size { - Size::Byte => self.port.read_u8(addr).map(|value| value as u32), - Size::Word => self.port.read_beu16(addr).map(|value| value as u32), - Size::Long => self.port.read_beu32(addr), + Size::Byte => self.port.read_u8(self.current_clock, addr).map(|value| value as u32), + Size::Word => self.port.read_beu16(self.current_clock, addr).map(|value| value as u32), + Size::Long => self.port.read_beu32(self.current_clock, addr), } } fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), Error> { self.start_request(addr as u32, size, MemAccess::Write, MemType::Data, false)?; match size { - Size::Byte => self.port.write_u8(addr, value as u8), - Size::Word => self.port.write_beu16(addr, value as u16), - Size::Long => self.port.write_beu32(addr, value), + Size::Byte => self.port.write_u8(self.current_clock, addr, value as u8), + Size::Word => self.port.write_beu16(self.current_clock, addr, value as u16), + Size::Long => self.port.write_beu32(self.current_clock, addr, value), } } @@ -1587,12 +1588,12 @@ impl M68k { *self.get_stack_pointer_mut() -= 2; let addr = *self.get_stack_pointer_mut(); self.start_request(addr, Size::Word, MemAccess::Write, MemType::Data, false)?; - self.port.write_beu16(addr as Address, value) + self.port.write_beu16(self.current_clock, addr as Address, value) } fn pop_word(&mut self) -> Result { let addr = *self.get_stack_pointer_mut(); - let value = self.port.read_beu16(addr as Address)?; + let value = self.port.read_beu16(self.current_clock, addr as Address)?; self.start_request(addr, Size::Word, MemAccess::Read, MemType::Data, false)?; *self.get_stack_pointer_mut() += 2; Ok(value) @@ -1602,12 +1603,12 @@ impl M68k { *self.get_stack_pointer_mut() -= 4; let addr = *self.get_stack_pointer_mut(); self.start_request(addr, Size::Long, MemAccess::Write, MemType::Data, false)?; - self.port.write_beu32(addr as Address, value) + self.port.write_beu32(self.current_clock, addr as Address, value) } fn pop_long(&mut self) -> Result { let addr = *self.get_stack_pointer_mut(); - let value = self.port.read_beu32(addr as Address)?; + let value = self.port.read_beu32(self.current_clock, addr as Address)?; self.start_request(addr, Size::Long, MemAccess::Read, MemType::Data, false)?; *self.get_stack_pointer_mut() += 4; Ok(value) diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index ebc7122..29a3562 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -1,5 +1,5 @@ -use moa_core::{Address, BusPort, Frequency}; +use moa_core::{ClockTime, Address, BusPort, Frequency}; use moa_core::timers::CpuTimer; use crate::instructions::Size; @@ -132,6 +132,7 @@ pub struct M68k { pub debugger: M68kDebugger, pub port: BusPort, pub timer: CpuTimer, + pub current_clock: ClockTime, } impl Default for M68kState { @@ -160,23 +161,24 @@ impl M68k { cputype, frequency, state: M68kState::default(), - decoder: M68kDecoder::new(cputype, 0), + decoder: M68kDecoder::new(cputype, ClockTime::START, 0), timing: M68kInstructionTiming::new(cputype, port.data_width()), debugger: M68kDebugger::default(), port, timer: CpuTimer::default(), + current_clock: ClockTime::START, } } #[allow(dead_code)] pub fn reset(&mut self) { self.state = M68kState::default(); - self.decoder = M68kDecoder::new(self.cputype, 0); + self.decoder = M68kDecoder::new(self.cputype, ClockTime::START, 0); self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width()); self.debugger = M68kDebugger::default(); } - pub fn dump_state(&mut self) { + pub fn dump_state(&mut self, clock: ClockTime) { println!("Status: {:?}", self.state.status); println!("PC: {:#010x}", self.state.pc); println!("SR: {:#06x}", self.state.sr); @@ -188,7 +190,7 @@ impl M68k { println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction); println!(); - self.port.dump_memory(self.state.ssp as Address, 0x40); + self.port.dump_memory(clock, self.state.ssp as Address, 0x40); println!(); } } diff --git a/emulator/cpus/z80/src/debugger.rs b/emulator/cpus/z80/src/debugger.rs index 272669b..4e45a74 100644 --- a/emulator/cpus/z80/src/debugger.rs +++ b/emulator/cpus/z80/src/debugger.rs @@ -32,10 +32,10 @@ impl Debuggable for Z80 { } } - fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { - self.decoder.decode_at(&mut self.port, self.state.pc)?; + fn print_current_step(&mut self, system: &System) -> Result<(), Error> { + self.decoder.decode_at(&mut self.port, system.clock, self.state.pc)?; self.decoder.dump_decoded(&mut self.port); - self.dump_state(); + self.dump_state(system.clock); Ok(()) } diff --git a/emulator/cpus/z80/src/decode.rs b/emulator/cpus/z80/src/decode.rs index 52b288f..65cf528 100644 --- a/emulator/cpus/z80/src/decode.rs +++ b/emulator/cpus/z80/src/decode.rs @@ -1,5 +1,5 @@ -use moa_core::{Error, Address, Addressable}; +use moa_core::{Error, ClockTime, Address, Addressable}; use crate::state::{Register, InterruptMode}; @@ -173,6 +173,7 @@ pub enum Instruction { } pub struct Z80Decoder { + pub clock: ClockTime, pub start: u16, pub end: u16, pub instruction: Instruction, @@ -182,6 +183,7 @@ pub struct Z80Decoder { impl Default for Z80Decoder { fn default() -> Self { Self { + clock: ClockTime::START, start: 0, end: 0, instruction: Instruction::NOP, @@ -191,7 +193,8 @@ impl Default for Z80Decoder { } impl Z80Decoder { - pub fn decode_at(&mut self, memory: &mut dyn Addressable, start: u16) -> Result<(), Error> { + pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: ClockTime, start: u16) -> Result<(), Error> { + self.clock = clock; self.start = start; self.end = start; self.execution_time = 0; @@ -674,14 +677,14 @@ impl Z80Decoder { fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result { - let byte = device.read_u8(self.end as Address)?; + let byte = device.read_u8(self.clock, self.end as Address)?; self.end += 1; self.execution_time += 4; Ok(byte) } fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result { - let word = device.read_leu16(self.end as Address)?; + let word = device.read_leu16(self.clock, self.end as Address)?; self.end += 2; self.execution_time += 8; Ok(word) @@ -690,7 +693,7 @@ impl Z80Decoder { pub fn format_instruction_bytes(&mut self, memory: &mut dyn Addressable) -> String { let ins_data: String = (0..(self.end - self.start)).map(|offset| - format!("{:02x} ", memory.read_u8((self.start + offset) as Address).unwrap()) + format!("{:02x} ", memory.read_u8(self.clock, (self.start + offset) as Address).unwrap()) ).collect(); ins_data } @@ -703,7 +706,7 @@ impl Z80Decoder { pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u16, length: u16) { let mut next = start; while next < (start + length) { - match self.decode_at(memory, next) { + match self.decode_at(memory, self.clock, next) { Ok(()) => { self.dump_decoded(memory); next = self.end; diff --git a/emulator/cpus/z80/src/execute.rs b/emulator/cpus/z80/src/execute.rs index 11cab13..3adea7e 100644 --- a/emulator/cpus/z80/src/execute.rs +++ b/emulator/cpus/z80/src/execute.rs @@ -31,8 +31,8 @@ impl Steppable for Z80 { Ok(self.frequency.period_duration() * clocks as u64) } - fn on_error(&mut self, _system: &System) { - self.dump_state(); + fn on_error(&mut self, system: &System) { + self.dump_state(system.clock); } } @@ -56,6 +56,7 @@ impl Transmutable for Z80 { impl Z80 { pub fn step_internal(&mut self, system: &System) -> Result { + self.current_clock = system.clock; match self.state.status { Status::Init => self.init(), Status::Halted => Err(Error::new("CPU stopped")), @@ -92,7 +93,7 @@ impl Z80 { } pub fn decode_next(&mut self) -> Result<(), Error> { - self.decoder.decode_at(&mut self.port, self.state.pc)?; + self.decoder.decode_at(&mut self.port, self.current_clock, self.state.pc)?; self.state.pc = self.decoder.end; Ok(()) } @@ -244,9 +245,9 @@ impl Z80 { Instruction::EXsp(regpair) => { let reg_value = self.get_register_pair_value(regpair); let sp = self.get_register_pair_value(RegisterPair::SP); - let sp_value = self.port.read_leu16(sp as Address)?; + let sp_value = self.port.read_leu16(self.current_clock, sp as Address)?; self.set_register_pair_value(regpair, sp_value); - self.port.write_leu16(sp as Address, reg_value)?; + self.port.write_leu16(self.current_clock, sp as Address, reg_value)?; }, Instruction::HALT => { self.state.status = Status::Halted; @@ -616,17 +617,17 @@ impl Z80 { fn push_word(&mut self, value: u16) -> Result<(), Error> { self.state.sp = self.state.sp.wrapping_sub(1); - self.port.write_u8(self.state.sp as Address, (value >> 8) as u8)?; + self.port.write_u8(self.current_clock, self.state.sp as Address, (value >> 8) as u8)?; self.state.sp = self.state.sp.wrapping_sub(1); - self.port.write_u8(self.state.sp as Address, (value & 0x00FF) as u8)?; + self.port.write_u8(self.current_clock, self.state.sp as Address, (value & 0x00FF) as u8)?; Ok(()) } fn pop_word(&mut self) -> Result { let mut value; - value = self.port.read_u8(self.state.sp as Address)? as u16; + value = self.port.read_u8(self.current_clock, self.state.sp as Address)? as u16; self.state.sp = self.state.sp.wrapping_add(1); - value |= (self.port.read_u8(self.state.sp as Address)? as u16) << 8; + value |= (self.port.read_u8(self.current_clock, self.state.sp as Address)? as u16) << 8; self.state.sp = self.state.sp.wrapping_add(1); Ok(value) } @@ -638,21 +639,21 @@ impl Z80 { LoadTarget::DirectRegWord(regpair) => self.get_register_pair_value(regpair), LoadTarget::IndirectRegByte(regpair) => { let addr = self.get_register_pair_value(regpair); - self.port.read_u8(addr as Address)? as u16 + self.port.read_u8(self.current_clock, addr as Address)? as u16 }, LoadTarget::IndirectOffsetByte(index_reg, offset) => { let addr = self.get_index_register_value(index_reg); - self.port.read_u8(((addr as i16).wrapping_add(offset as i16)) as Address)? as u16 + self.port.read_u8(self.current_clock, ((addr as i16).wrapping_add(offset as i16)) as Address)? as u16 }, LoadTarget::IndirectRegWord(regpair) => { let addr = self.get_register_pair_value(regpair); - self.port.read_leu16(addr as Address)? + self.port.read_leu16(self.current_clock, addr as Address)? }, LoadTarget::IndirectByte(addr) => { - self.port.read_u8(addr as Address)? as u16 + self.port.read_u8(self.current_clock, addr as Address)? as u16 }, LoadTarget::IndirectWord(addr) => { - self.port.read_leu16(addr as Address)? + self.port.read_leu16(self.current_clock, addr as Address)? }, LoadTarget::ImmediateByte(data) => data as u16, LoadTarget::ImmediateWord(data) => data, @@ -668,21 +669,21 @@ impl Z80 { LoadTarget::DirectRegWord(regpair) => self.set_register_pair_value(regpair, value), LoadTarget::IndirectRegByte(regpair) => { let addr = self.get_register_pair_value(regpair); - self.port.write_u8(addr as Address, value as u8)?; + self.port.write_u8(self.current_clock, addr as Address, value as u8)?; }, LoadTarget::IndirectOffsetByte(index_reg, offset) => { let addr = self.get_index_register_value(index_reg); - self.port.write_u8(((addr as i16).wrapping_add(offset as i16)) as Address, value as u8)?; + self.port.write_u8(self.current_clock, ((addr as i16).wrapping_add(offset as i16)) as Address, value as u8)?; }, LoadTarget::IndirectRegWord(regpair) => { let addr = self.get_register_pair_value(regpair); - self.port.write_leu16(addr as Address, value)?; + self.port.write_leu16(self.current_clock, addr as Address, value)?; }, LoadTarget::IndirectByte(addr) => { - self.port.write_u8(addr as Address, value as u8)?; + self.port.write_u8(self.current_clock, addr as Address, value as u8)?; }, LoadTarget::IndirectWord(addr) => { - self.port.write_leu16(addr as Address, value)?; + self.port.write_leu16(self.current_clock, addr as Address, value)?; }, _ => panic!("Unsupported LoadTarget for set: {:?}", target), } @@ -695,11 +696,11 @@ impl Z80 { Target::DirectRegHalf(reg) => Ok(self.get_index_register_half_value(reg)), Target::IndirectReg(regpair) => { let addr = self.get_register_pair_value(regpair); - Ok(self.port.read_u8(addr as Address)?) + Ok(self.port.read_u8(self.current_clock, addr as Address)?) }, Target::IndirectOffset(reg, offset) => { let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); - Ok(self.port.read_u8(addr as Address)?) + Ok(self.port.read_u8(self.current_clock, addr as Address)?) }, Target::Immediate(data) => Ok(data), } @@ -711,11 +712,11 @@ impl Z80 { Target::DirectRegHalf(reg) => self.set_index_register_half_value(reg, value), Target::IndirectReg(regpair) => { let addr = self.get_register_pair_value(regpair); - self.port.write_u8(addr as Address, value)?; + self.port.write_u8(self.current_clock, addr as Address, value)?; }, Target::IndirectOffset(reg, offset) => { let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); - self.port.write_u8(addr as Address, value)?; + self.port.write_u8(self.current_clock, addr as Address, value)?; }, _ => panic!("Unsupported LoadTarget for set"), } diff --git a/emulator/cpus/z80/src/state.rs b/emulator/cpus/z80/src/state.rs index 8039300..98bd300 100644 --- a/emulator/cpus/z80/src/state.rs +++ b/emulator/cpus/z80/src/state.rs @@ -1,5 +1,5 @@ -use moa_core::{Address, BusPort, Signal, Frequency}; +use moa_core::{ClockTime, Address, BusPort, Signal, Frequency}; use crate::decode::Z80Decoder; use crate::debugger::Z80Debugger; @@ -113,6 +113,7 @@ pub struct Z80 { pub port: BusPort, pub reset: Signal, pub bus_request: Signal, + pub current_clock: ClockTime, } impl Z80 { @@ -126,6 +127,7 @@ impl Z80 { port, reset: Signal::new(false), bus_request: Signal::new(false), + current_clock: ClockTime::START, } } @@ -136,7 +138,7 @@ impl Z80 { self.debugger = Z80Debugger::default(); } - pub fn dump_state(&mut self) { + pub fn dump_state(&mut self, clock: ClockTime) { println!("Status: {:?}", self.state.status); println!("PC: {:#06x}", self.state.pc); println!("SP: {:#06x}", self.state.sp); @@ -150,7 +152,7 @@ impl Z80 { println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction); println!(); - self.port.dump_memory(self.state.sp as Address, 0x40); + self.port.dump_memory(clock, self.state.sp as Address, 0x40); println!(); } } diff --git a/emulator/frontends/minifb/src/bin/moa-synth.rs b/emulator/frontends/minifb/src/bin/moa-synth.rs index 5cf2a34..5b0947c 100644 --- a/emulator/frontends/minifb/src/bin/moa-synth.rs +++ b/emulator/frontends/minifb/src/bin/moa-synth.rs @@ -5,7 +5,7 @@ use moa_peripherals_yamaha::{Ym2612, Sn76489}; use moa_core::host::gfx::{Frame, FrameQueue, PixelEncoding}; use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key, KeyEvent /*, MouseUpdater, MouseState, MouseEvent*/}; -use moa_core::{System, Error, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable}; +use moa_core::{System, Error, ClockTime, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable}; pub struct SynthControlsUpdater(mpsc::Sender); @@ -42,14 +42,14 @@ impl Steppable for SynthControl { match event.key { Key::Enter => { - system.get_bus().write_u8(0x00, 0x28)?; - system.get_bus().write_u8(0x01, if event.state { 0xF0 } else { 0x00 })?; + system.get_bus().write_u8(system.clock, 0x00, 0x28)?; + system.get_bus().write_u8(system.clock, 0x01, if event.state { 0xF0 } else { 0x00 })?; }, Key::A => { - system.get_bus().write_u8(0x10, 0x84)?; - system.get_bus().write_u8(0x10, 0x0F)?; - system.get_bus().write_u8(0x10, if event.state { 0x90 } else { 0x9F })?; + system.get_bus().write_u8(system.clock, 0x10, 0x84)?; + system.get_bus().write_u8(system.clock, 0x10, 0x0F)?; + system.get_bus().write_u8(system.clock, 0x10, if event.state { 0x90 } else { 0x9F })?; }, _ => { }, @@ -72,8 +72,8 @@ impl Transmutable for SynthControl { fn set_register(device: &mut dyn Addressable, bank: u8, reg: u8, data: u8) -> Result<(), Error> { let addr = (bank as Address) * 2; - device.write_u8(addr, reg)?; - device.write_u8(addr + 1, data)?; + device.write_u8(ClockTime::START, addr, reg)?; + device.write_u8(ClockTime::START, addr + 1, data)?; Ok(()) } diff --git a/emulator/peripherals/generic/src/ata.rs b/emulator/peripherals/generic/src/ata.rs index 2a515e3..0acf780 100644 --- a/emulator/peripherals/generic/src/ata.rs +++ b/emulator/peripherals/generic/src/ata.rs @@ -1,7 +1,7 @@ use std::fs; -use moa_core::{Error, Address, Addressable, Transmutable, debug}; +use moa_core::{Error, ClockTime, Address, Addressable, Transmutable, debug}; const ATA_REG_DATA_WORD: Address = 0x20; @@ -57,7 +57,7 @@ impl Addressable for AtaDevice { 0x30 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { ATA_REG_DATA_WORD => { self.selected_count -= 2; @@ -90,7 +90,7 @@ impl Addressable for AtaDevice { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { ATA_REG_DRIVE_HEAD => { self.selected_sector |= ((data[0] & 0x1F) as u32) << 24; }, diff --git a/emulator/peripherals/mos/src/mos6522.rs b/emulator/peripherals/mos/src/mos6522.rs index d2f0229..f1c178e 100644 --- a/emulator/peripherals/mos/src/mos6522.rs +++ b/emulator/peripherals/mos/src/mos6522.rs @@ -1,5 +1,5 @@ -use moa_core::{Error, System, ClockDuration, Address, Addressable, Steppable, Transmutable, Signal, ObservableSignal, Observable, debug, warn}; +use moa_core::{Error, System, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable, Signal, ObservableSignal, Observable, debug, warn}; const REG_OUTPUT_B: Address = 0x00; @@ -57,7 +57,7 @@ impl Addressable for Mos6522 { 0x10 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { REG_OUTPUT_B => { data[0] = self.port_b.borrow_mut().data; }, REG_OUTPUT_A => { data[0] = self.port_a.borrow_mut().data; }, @@ -73,7 +73,7 @@ impl Addressable for Mos6522 { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { REG_OUTPUT_B => { self.port_b.borrow_mut().data = data[0]; self.port_b.notify(); }, diff --git a/emulator/peripherals/motorola/src/mc68681.rs b/emulator/peripherals/motorola/src/mc68681.rs index 1cb019e..d640832 100644 --- a/emulator/peripherals/motorola/src/mc68681.rs +++ b/emulator/peripherals/motorola/src/mc68681.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, ClockDuration, Frequency, Address, Steppable, Addressable, Transmutable, debug}; +use moa_core::{System, Error, ClockTime, ClockDuration, Frequency, Address, Steppable, Addressable, Transmutable, debug}; use moa_core::host::Tty; @@ -250,7 +250,7 @@ impl Addressable for MC68681 { 0x30 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { REG_SRA_RD => { data[0] = self.port_a.status @@ -302,7 +302,7 @@ impl Addressable for MC68681 { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { debug!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); match addr { REG_MR1A_MR2A | REG_MR1B_MR2B | REG_CSRA_WR | REG_CSRB_WR => { diff --git a/emulator/peripherals/yamaha/src/sn76489.rs b/emulator/peripherals/yamaha/src/sn76489.rs index 5e22052..18cfb22 100644 --- a/emulator/peripherals/yamaha/src/sn76489.rs +++ b/emulator/peripherals/yamaha/src/sn76489.rs @@ -1,6 +1,6 @@ use moa_core::{info, warn, debug}; -use moa_core::{System, Error, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable}; +use moa_core::{System, Error, ClockTime, ClockDuration, Frequency, Address, Addressable, Steppable, Transmutable}; use moa_core::host::{Host, Audio}; use moa_core::host::audio::{SquareWave}; @@ -146,12 +146,12 @@ impl Addressable for Sn76489 { 0x01 } - fn read(&mut self, _addr: Address, _data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, _addr: Address, _data: &mut [u8]) -> Result<(), Error> { warn!("{}: !!! device can't be read", DEV_NAME); Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { if addr != 0 { warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); return Ok(()); diff --git a/emulator/peripherals/yamaha/src/ym2612.rs b/emulator/peripherals/yamaha/src/ym2612.rs index 3178e74..c507869 100644 --- a/emulator/peripherals/yamaha/src/ym2612.rs +++ b/emulator/peripherals/yamaha/src/ym2612.rs @@ -1,12 +1,12 @@ -/// Emulate the YM2612 FM Sound Synthesizer (used by the Sega Genesis) -/// -/// This implementation is mostly based on online references to the YM2612's registers and their -/// function, forum posts that describe the details of operation of the chip, and looking at -/// source code that emulates the chip. It is still very much a work in progress -/// -/// Resources: -/// - Registers: https://www.smspower.org/maxim/Documents/YM2612 -/// - Envelope and rates: http://gendev.spritesmind.net/forum/viewtopic.php?p=5716#5716 +//! Emulate the YM2612 FM Sound Synthesizer (used by the Sega Genesis) +//! +//! This implementation is mostly based on online references to the YM2612's registers and their +//! function, forum posts that describe the details of operation of the chip, and looking at +//! source code that emulates the chip. It is still very much a work in progress +//! +//! Resources: +//! - Registers: https://www.smspower.org/maxim/Documents/YM2612 +//! - Envelope and rates: http://gendev.spritesmind.net/forum/viewtopic.php?p=5716#5716 use std::num::NonZeroU8; use std::collections::VecDeque; @@ -140,7 +140,6 @@ struct EnvelopeGenerator { rates: [usize; 4], envelope_state: EnvelopeState, - last_state_change: ClockTime, next_envelope_clock: EnvelopeClock, envelope: u16, } @@ -154,7 +153,6 @@ impl EnvelopeGenerator { rates: [0; 4], envelope_state: EnvelopeState::Attack, - last_state_change: ClockTime::START, next_envelope_clock: 0, envelope: 0, } @@ -172,8 +170,7 @@ impl EnvelopeGenerator { self.rates[etype as usize] = rate; } - fn notify_state_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { - //self.last_state_change = envelope_clock; + fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { if state { self.next_envelope_clock = envelope_clock; self.envelope_state = EnvelopeState::Attack; @@ -265,6 +262,10 @@ impl Operator { } } + fn reset(&mut self) { + self.wave.reset(); + } + fn set_frequency(&mut self, frequency: f32) { self.frequency = frequency; } @@ -285,8 +286,8 @@ impl Operator { self.envelope.set_rate(etype, rate) } - fn notify_state_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { - self.envelope.notify_state_change(state, envelope_clock); + fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { + self.envelope.notify_key_change(state, envelope_clock); } fn get_sample(&mut self, modulator: f32, envelope_clock: EnvelopeClock) -> f32 { @@ -306,8 +307,9 @@ struct Channel { #[allow(dead_code)] debug_name: String, operators: Vec, - on_state: u8, - next_on_state: u8, + key_state: u8, + next_key_clock: ClockTime, + next_key_state: u8, base_frequency: f32, algorithm: OperatorAlgorithm, } @@ -317,8 +319,9 @@ impl Channel { Self { debug_name: debug_name.clone(), operators: (0..OPERATORS).map(|i| Operator::new(format!("{}, op {}", debug_name, i), sample_rate)).collect(), - on_state: 0, - next_on_state: 0, + key_state: 0, + next_key_clock: ClockTime::START, + next_key_state: 0, base_frequency: 0.0, algorithm: OperatorAlgorithm::A0, } @@ -331,15 +334,25 @@ impl Channel { } } - fn get_sample(&mut self, envelope_clock: EnvelopeClock) -> f32 { - if self.on_state != self.next_on_state { - self.on_state = self.next_on_state; + fn change_key_state(&mut self, clock: ClockTime, key: u8) { + self.next_key_clock = clock; + self.next_key_state = key; + } + + fn check_key_change(&mut self, clock: ClockTime, envelope_clock: EnvelopeClock) { + if self.key_state != self.next_key_state && clock >= self.next_key_clock { + self.key_state = self.next_key_state; for (i, operator) in self.operators.iter_mut().enumerate() { - operator.notify_state_change(((self.on_state >> i) & 0x01) != 0, envelope_clock); + operator.notify_key_change(((self.key_state >> i) & 0x01) != 0, envelope_clock); + operator.reset(); } } + } - if self.on_state != 0 { + fn get_sample(&mut self, clock: ClockTime, envelope_clock: EnvelopeClock) -> f32 { + self.check_key_change(clock, envelope_clock); + + if self.key_state != 0 { self.get_algorithm_sample(envelope_clock) } else { 0.0 @@ -492,17 +505,18 @@ impl Steppable for Ym2612 { //if self.source.space_available() >= samples { let mut buffer = vec![0.0; samples]; for (i, buffered_sample) in buffer.iter_mut().enumerate().take(samples) { - let envelope_clock = (system.clock.as_duration() + (sample_duration * i as u64)) / self.envelope_clock_period; + let sample_clock = system.clock + (sample_duration * i as u64); + let envelope_clock = sample_clock.as_duration() / self.envelope_clock_period; let mut sample = 0.0; for ch in 0..(CHANNELS - 1) { - sample += self.channels[ch].get_sample(envelope_clock); + sample += self.channels[ch].get_sample(sample_clock, envelope_clock); } if self.dac.enabled { sample += self.dac.get_sample(); } else { - sample += self.channels[CHANNELS - 1].get_sample(envelope_clock); + sample += self.channels[CHANNELS - 1].get_sample(sample_clock, envelope_clock); } *buffered_sample = sample.clamp(-1.0, 1.0); @@ -515,7 +529,7 @@ impl Steppable for Ym2612 { } impl Ym2612 { - pub fn set_register(&mut self, bank: u8, reg: u8, data: u8) { + pub fn set_register(&mut self, clock: ClockTime, bank: u8, reg: u8, data: u8) { // Keep a copy for debugging purposes, and if the original values are needed self.registers[bank as usize * 256 + reg as usize] = data; @@ -545,7 +559,7 @@ impl Ym2612 { return; }, }; - self.channels[ch].next_on_state = data >> 4; + self.channels[ch].change_key_state(clock, data >> 4); }, 0x2a => { @@ -695,7 +709,7 @@ impl Addressable for Ym2612 { 0x04 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { 0 | 1 | 2 | 3 => { // Read the status byte (busy/overflow) @@ -709,7 +723,7 @@ impl Addressable for Ym2612 { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { 0 => { @@ -717,7 +731,7 @@ impl Addressable for Ym2612 { }, 1 => { if let Some(reg) = self.selected_reg_0 { - self.set_register(0, reg.get(), data[0]); + self.set_register(clock, 0, reg.get(), data[0]); } }, 2 => { @@ -725,7 +739,7 @@ impl Addressable for Ym2612 { }, 3 => { if let Some(reg) = self.selected_reg_1 { - self.set_register(1, reg.get(), data[0]); + self.set_register(clock, 1, reg.get(), data[0]); } }, _ => { diff --git a/emulator/peripherals/zilog/src/z8530.rs b/emulator/peripherals/zilog/src/z8530.rs index d104394..3e222a8 100644 --- a/emulator/peripherals/zilog/src/z8530.rs +++ b/emulator/peripherals/zilog/src/z8530.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, warn, debug}; +use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable, warn, debug}; const DEV_NAME: &str = "z8530"; @@ -13,13 +13,13 @@ impl Addressable for Z8530 { 0x10 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr); debug!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data); Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); Ok(()) diff --git a/emulator/systems/genesis/src/peripherals/controllers.rs b/emulator/systems/genesis/src/peripherals/controllers.rs index 1d282f5..e3b8a09 100644 --- a/emulator/systems/genesis/src/peripherals/controllers.rs +++ b/emulator/systems/genesis/src/peripherals/controllers.rs @@ -1,6 +1,6 @@ use moa_core::{warn, info}; -use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable}; +use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable}; use moa_core::host::{Host, ControllerUpdater, HostData, ControllerDevice, ControllerEvent}; @@ -154,7 +154,7 @@ impl Addressable for GenesisControllers { 0x30 } - fn read(&mut self, mut addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, mut addr: Address, data: &mut [u8]) -> Result<(), Error> { // If the address is even, only the second byte (odd byte) will be meaningful let mut i = 0; if (addr % 2) == 0 { @@ -179,7 +179,7 @@ impl Addressable for GenesisControllers { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { self.reset_timer = ClockDuration::ZERO; info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); diff --git a/emulator/systems/genesis/src/peripherals/coprocessor.rs b/emulator/systems/genesis/src/peripherals/coprocessor.rs index ce6adce..d4da7f3 100644 --- a/emulator/systems/genesis/src/peripherals/coprocessor.rs +++ b/emulator/systems/genesis/src/peripherals/coprocessor.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use std::cell::RefCell; use moa_core::{warn, info}; -use moa_core::{Bus, Signal, Error, Address, Addressable, Transmutable}; +use moa_core::{Bus, Signal, Error, ClockTime, Address, Addressable, Transmutable}; const DEV_NAME: &str = "coprocessor"; @@ -28,7 +28,7 @@ impl Addressable for CoprocessorCoordinator { 0x4000 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { 0x100 => { data[0] = if self.bus_request.get() && self.reset.get() { 0x01 } else { 0x00 }; @@ -39,7 +39,7 @@ impl Addressable for CoprocessorCoordinator { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); match addr { 0x000 => { /* ROM vs DRAM mode */ }, @@ -79,11 +79,11 @@ impl Addressable for CoprocessorBankRegister { 0x01 } - fn read(&mut self, _addr: Address, _data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, _addr: Address, _data: &mut [u8]) -> Result<(), Error> { Ok(()) } - fn write(&mut self, _addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, _addr: Address, data: &[u8]) -> Result<(), Error> { let value = ((self.base.get() >> 1) | ((data[0] as Address) << 23)) & 0xFF8000; //let value = ((self.base.get() << 1) | ((data[0] as Address) << 15)) & 0xFF8000; println!("New base is {:x}", value); @@ -118,12 +118,12 @@ impl Addressable for CoprocessorBankArea { 0x8000 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { - self.bus.borrow_mut().read(self.base.get() + addr, data) + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { + self.bus.borrow_mut().read(clock, self.base.get() + addr, data) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { - self.bus.borrow_mut().write(self.base.get() + addr, data) + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { + self.bus.borrow_mut().write(clock, self.base.get() + addr, data) } } diff --git a/emulator/systems/genesis/src/peripherals/ym7101.rs b/emulator/systems/genesis/src/peripherals/ym7101.rs index fdeaa8a..78825de 100644 --- a/emulator/systems/genesis/src/peripherals/ym7101.rs +++ b/emulator/systems/genesis/src/peripherals/ym7101.rs @@ -229,7 +229,7 @@ impl Ym7101Memory { while self.transfer_remain > 0 { let mut data = [0; 2]; - bus.read(self.transfer_src_addr as Address, &mut data)?; + bus.read(system.clock, self.transfer_src_addr as Address, &mut data)?; let addr = self.transfer_dest_addr as usize; let target = self.get_transfer_target_mut(); @@ -783,7 +783,7 @@ impl Addressable for Ym7101 { 0x20 } - fn read(&mut self, mut addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, mut addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { // Read from Data Port 0x00 | 0x02 => self.state.memory.read_data_port(addr, data)?, @@ -814,7 +814,7 @@ impl Addressable for Ym7101 { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { match addr { // Write to Data Port 0x00 | 0x02 => self.state.memory.write_data_port(data)?, @@ -840,7 +840,7 @@ impl Addressable for Ym7101 { }, 0x11 | 0x12 => { - self.sn_sound.borrow_mut().as_addressable().unwrap().write(0, data)?; + self.sn_sound.borrow_mut().as_addressable().unwrap().write(clock, 0, data)?; }, _ => { warn!("{}: !!! unhandled write to {:x} with {:?}", DEV_NAME, addr, data); }, diff --git a/emulator/systems/macintosh/src/peripherals/iwm.rs b/emulator/systems/macintosh/src/peripherals/iwm.rs index 50f3ab5..b3fc41b 100644 --- a/emulator/systems/macintosh/src/peripherals/iwm.rs +++ b/emulator/systems/macintosh/src/peripherals/iwm.rs @@ -1,5 +1,5 @@ -use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, info, warn}; +use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable, info, warn}; //const CA0: u8 = 0x01; @@ -38,7 +38,7 @@ impl Addressable for IWM { 0x10 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { self.flip_switches(addr); if (addr & 0x01) != 0 { @@ -71,7 +71,7 @@ impl Addressable for IWM { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { self.flip_switches(addr); info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); diff --git a/emulator/systems/macintosh/src/peripherals/mainboard.rs b/emulator/systems/macintosh/src/peripherals/mainboard.rs index 943222e..af3929b 100644 --- a/emulator/systems/macintosh/src/peripherals/mainboard.rs +++ b/emulator/systems/macintosh/src/peripherals/mainboard.rs @@ -69,19 +69,19 @@ impl Addressable for Mainboard { 0x01000000 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { if addr < 0x800000 { - self.lower_bus.borrow_mut().read(addr, data) + self.lower_bus.borrow_mut().read(clock, addr, data) } else if (0x900000..0xA00000).contains(&addr) { - self.scc1.read((addr >> 9) & 0x0F, data) + self.scc1.read(clock, (addr >> 9) & 0x0F, data) } else if (0xB00000..0xC00000).contains(&addr) { - self.scc2.read((addr >> 9) & 0x0F, data) + self.scc2.read(clock, (addr >> 9) & 0x0F, data) } else if (0xD00000..0xE00000).contains(&addr) { - self.iwm.read((addr >> 9) & 0x0F, data) + self.iwm.read(clock, (addr >> 9) & 0x0F, data) } else if (0xE80000..0xF00000).contains(&addr) { - self.via.read((addr >> 9) & 0x0F, data) + self.via.read(clock, (addr >> 9) & 0x0F, data) } else if (0xF00000..0xF80000).contains(&addr) { - self.phase_read.read(addr, data) + self.phase_read.read(clock, addr, data) } else if (0xF80000..0xF80010).contains(&addr) { // Debugger Ok(()) @@ -90,19 +90,19 @@ impl Addressable for Mainboard { } } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { if addr < 0x800000 { - self.lower_bus.borrow_mut().write(addr, data) + self.lower_bus.borrow_mut().write(clock, addr, data) } else if (0x900000..0xA00000).contains(&addr) { - self.scc1.write((addr >> 9) & 0x0F, data) + self.scc1.write(clock, (addr >> 9) & 0x0F, data) } else if (0xB00000..0xC00000).contains(&addr) { - self.scc2.write((addr >> 9) & 0x0F, data) + self.scc2.write(clock, (addr >> 9) & 0x0F, data) } else if (0xD00000..0xE00000).contains(&addr) { - self.iwm.write((addr >> 9) & 0x0F, data) + self.iwm.write(clock, (addr >> 9) & 0x0F, data) } else if (0xE80000..0xF00000).contains(&addr) { - self.via.write((addr >> 9) & 0x0F, data) + self.via.write(clock, (addr >> 9) & 0x0F, data) } else if (0xF00000..0xF80000).contains(&addr) { - self.phase_read.write(addr, data) + self.phase_read.write(clock, addr, data) } else { Err(Error::new(&format!("Error writing address {:#010x}", addr))) } @@ -146,13 +146,13 @@ impl Addressable for PhaseRead { 0x80000 } - fn read(&mut self, _addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, _addr: Address, data: &mut [u8]) -> Result<(), Error> { // TODO I'm not sure how this is supposed to work data[0] = 0x00; Ok(()) } - fn write(&mut self, _addr: Address, _data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, _addr: Address, _data: &[u8]) -> Result<(), Error> { // TODO I'm not sure how this is supposed to work Ok(()) } diff --git a/emulator/systems/macintosh/src/peripherals/video.rs b/emulator/systems/macintosh/src/peripherals/video.rs index de0607e..3ba1ad2 100644 --- a/emulator/systems/macintosh/src/peripherals/video.rs +++ b/emulator/systems/macintosh/src/peripherals/video.rs @@ -62,7 +62,7 @@ impl Steppable for MacVideo { let mut frame = Frame::new(SCRN_SIZE.0, SCRN_SIZE.1, self.frame_queue.encoding()); for y in 0..SCRN_SIZE.1 { for x in 0..(SCRN_SIZE.0 / 16) { - let word = memory.read_beu16((SCRN_BASE + (x * 2) + (y * (SCRN_SIZE.0 / 8))) as Address)?; + let word = memory.read_beu16(system.clock, (SCRN_BASE + (x * 2) + (y * (SCRN_SIZE.0 / 8))) as Address)?; frame.blit(x * 16, y, BitIter::new(word), 16, 1); } } diff --git a/emulator/systems/trs80/src/peripherals/model1.rs b/emulator/systems/trs80/src/peripherals/model1.rs index 1f09f9c..a0b8ff0 100644 --- a/emulator/systems/trs80/src/peripherals/model1.rs +++ b/emulator/systems/trs80/src/peripherals/model1.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex}; -use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable, debug, warn}; +use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable, debug, warn}; use moa_core::host::gfx::{Frame, FrameQueue}; use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, KeyEvent}; @@ -64,7 +64,7 @@ impl Addressable for Model1Peripherals { 0x820 } - fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, _clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { if (0x20..=0xA0).contains(&addr) { let offset = addr - 0x20; data[0] = 0; @@ -86,7 +86,7 @@ impl Addressable for Model1Peripherals { Ok(()) } - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, _clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); if (0x420..0x820).contains(&addr) { self.video_mem[addr as usize - 0x420] = data[0]; diff --git a/todo.txt b/todo.txt index e168d68..ec5915e 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,11 @@ +* remove the old timer stuff and replace with opentelemetry if it can be wasm compatible + +* 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 -* add a Duration-like clock type that records femto seconds -* move parser to utils/ of some kind, or lib/ - * add doc strings everywhere * get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion