Added clock argument to addressable operations

This commit is contained in:
transistor 2023-04-23 18:49:40 -07:00
parent cd5336bc23
commit 86eb73f78a
28 changed files with 257 additions and 228 deletions

View File

@ -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}; use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};

View File

@ -116,7 +116,7 @@ impl Debugger {
if args.len() > 1 { if args.len() > 1 {
let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; 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 }; 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 { } else {
//self.port.dump_memory(self.state.ssp as Address, 0x40 as Address); //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 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"))?; let data = u32::from_str_radix(args[2], 16).map_err(|_| Error::new("Unable to parse data"))?;
match args[0] { match args[0] {
"setb" => system.get_bus().write_u8(addr, data as u8)?, "setb" => system.get_bus().write_u8(system.clock, addr, data as u8)?,
"setw" => system.get_bus().write_beu16(addr, data as u16)?, "setw" => system.get_bus().write_beu16(system.clock, addr, data as u16)?,
"setl" => system.get_bus().write_beu32(addr, data)?, "setl" => system.get_bus().write_beu32(system.clock, addr, data)?,
_ => panic!("Unimplemented: {:?}", args[0]), _ => panic!("Unimplemented: {:?}", args[0]),
} }
} }

View File

@ -4,7 +4,7 @@ use std::cell::RefCell;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::clock::ClockDuration; use crate::clock::{ClockTime, ClockDuration};
/// A universal memory address used by the Addressable trait /// A universal memory address used by the Addressable trait
@ -30,66 +30,66 @@ pub trait Interruptable {
#[allow(clippy::len_without_is_empty)] #[allow(clippy::len_without_is_empty)]
pub trait Addressable { pub trait Addressable {
fn len(&self) -> usize; fn len(&self) -> 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>;
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error>; fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error>;
fn read_u8(&mut self, addr: Address) -> Result<u8, Error> { fn read_u8(&mut self, clock: ClockTime, addr: Address) -> Result<u8, Error> {
let mut data = [0; 1]; let mut data = [0; 1];
self.read(addr, &mut data)?; self.read(clock, addr, &mut data)?;
Ok(data[0]) Ok(data[0])
} }
fn read_beu16(&mut self, addr: Address) -> Result<u16, Error> { fn read_beu16(&mut self, clock: ClockTime, addr: Address) -> Result<u16, Error> {
let mut data = [0; 2]; let mut data = [0; 2];
self.read(addr, &mut data)?; self.read(clock, addr, &mut data)?;
Ok(read_beu16(&data)) Ok(read_beu16(&data))
} }
fn read_leu16(&mut self, addr: Address) -> Result<u16, Error> { fn read_leu16(&mut self, clock: ClockTime, addr: Address) -> Result<u16, Error> {
let mut data = [0; 2]; let mut data = [0; 2];
self.read(addr, &mut data)?; self.read(clock, addr, &mut data)?;
Ok(read_leu16(&data)) Ok(read_leu16(&data))
} }
fn read_beu32(&mut self, addr: Address) -> Result<u32, Error> { fn read_beu32(&mut self, clock: ClockTime, addr: Address) -> Result<u32, Error> {
let mut data = [0; 4]; let mut data = [0; 4];
self.read(addr, &mut data)?; self.read(clock, addr, &mut data)?;
Ok(read_beu32(&data)) Ok(read_beu32(&data))
} }
fn read_leu32(&mut self, addr: Address) -> Result<u32, Error> { fn read_leu32(&mut self, clock: ClockTime, addr: Address) -> Result<u32, Error> {
let mut data = [0; 4]; let mut data = [0; 4];
self.read(addr, &mut data)?; self.read(clock, addr, &mut data)?;
Ok(read_leu32(&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]; 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]; let mut data = [0; 2];
write_beu16(&mut data, value); 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]; let mut data = [0; 2];
write_leu16(&mut data, value); 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]; let mut data = [0; 4];
write_beu32(&mut data, value); 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]; let mut data = [0; 4];
write_leu32(&mut data, value); write_leu32(&mut data, value);
self.write(addr, &data) self.write(clock, addr, &data)
} }
} }

View File

@ -32,11 +32,11 @@ impl Pixel {
match encoding { match encoding {
PixelEncoding::RGBA => 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 => 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 => PixelEncoding::ABGR =>
((a as u32) << 24) | ((b as u32) << 16) | ((g as u32) << 8) | (r as u32), (a << 24) | (b << 16) | (g << 8) | r,
} }
} }
} }

View File

@ -6,6 +6,7 @@ use std::fmt::Write;
use crate::info; use crate::info;
use crate::error::Error; use crate::error::Error;
use crate::clock::ClockTime;
use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_beu16}; use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_beu16};
@ -53,12 +54,12 @@ impl Addressable for MemoryBlock {
self.contents.len() 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()]); data.copy_from_slice(&self.contents[(addr as usize)..(addr as usize) + data.len()]);
Ok(()) 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 { if self.read_only {
return Err(Error::breakpoint(&format!("Attempt to write to read-only memory at {:x} with data {:?}", addr, data))); 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 len << self.shift
} }
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.subdevice.borrow_mut().as_addressable().unwrap().read(addr >> self.shift, data) self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, addr >> self.shift, data)
} }
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> {
self.subdevice.borrow_mut().as_addressable().unwrap().write(addr >> self.shift, data) 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 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; 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; 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))) 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 { while count > 0 {
let mut line = format!("{:#010x}: ", addr); let mut line = format!("{:#010x}: ", addr);
let to = if count < 16 { count / 2 } else { 8 }; let to = if count < 16 { count / 2 } else { 8 };
for _ in 0..to { for _ in 0..to {
let word = self.read_beu16(addr); let word = self.read_beu16(clock, addr);
if word.is_err() { if word.is_err() {
println!("{}", line); println!("{}", line);
return; return;
@ -236,7 +237,7 @@ impl Addressable for Bus {
(block.base as usize) + block.length (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()) { let (dev, relative_addr) = match self.get_device_at(addr, data.len()) {
Ok(result) => result, Ok(result) => result,
Err(err) if self.ignore_unmapped => { Err(err) if self.ignore_unmapped => {
@ -245,11 +246,11 @@ impl Addressable for Bus {
}, },
Err(err) => return Err(err), 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 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) { if self.watchers.iter().any(|a| *a == addr) {
println!("watch: writing to address {:#06x} with {:?}", addr, data); println!("watch: writing to address {:#06x} with {:?}", addr, data);
self.watcher_modified = true; self.watcher_modified = true;
@ -263,7 +264,7 @@ impl Addressable for Bus {
}, },
Err(err) => return Err(err), 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 result
} }
} }
@ -291,8 +292,8 @@ impl BusPort {
} }
} }
pub fn dump_memory(&mut self, addr: Address, count: Address) { pub fn dump_memory(&mut self, clock: ClockTime, addr: Address, count: Address) {
self.subdevice.borrow_mut().dump_memory(self.offset + (addr & self.address_mask), count) self.subdevice.borrow_mut().dump_memory(clock, self.offset + (addr & self.address_mask), count)
} }
pub fn address_mask(&self) -> Address { pub fn address_mask(&self) -> Address {
@ -309,22 +310,22 @@ impl Addressable for BusPort {
self.subdevice.borrow().len() 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 addr = self.offset + (addr & self.address_mask);
let mut subdevice = self.subdevice.borrow_mut(); let mut subdevice = self.subdevice.borrow_mut();
for i in (0..data.len()).step_by(self.data_width as usize) { 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()); 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(()) 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 addr = self.offset + (addr & self.address_mask);
let mut subdevice = self.subdevice.borrow_mut(); let mut subdevice = self.subdevice.borrow_mut();
for i in (0..data.len()).step_by(self.data_width as usize) { 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()); 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(()) Ok(())
} }

View File

@ -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::state::M68k;
use super::decode::M68kDecoder; use super::decode::M68kDecoder;
@ -50,24 +50,24 @@ impl Debuggable for M68k {
} }
} }
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
self.decoder.decode_at(&mut self.port, self.state.pc)?; self.decoder.decode_at(&mut self.port, system.clock, self.state.pc)?;
self.decoder.dump_decoded(&mut self.port); self.decoder.dump_decoded(&mut self.port);
self.dump_state(); self.dump_state(system.clock);
Ok(()) Ok(())
} }
fn print_disassembly(&mut self, addr: Address, count: usize) { 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); decoder.dump_disassembly(&mut self.port, addr as u32, count as u32);
} }
fn execute_command(&mut self, _system: &System, args: &[&str]) -> Result<bool, Error> { fn execute_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
match args[0] { match args[0] {
"ds" | "stack" | "dumpstack" => { "ds" | "stack" | "dumpstack" => {
println!("Stack:"); println!("Stack:");
for addr in &self.debugger.stack_tracer.calls { 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" => { "so" | "stepout" => {

View File

@ -1,5 +1,5 @@
use moa_core::{Error, Address, Addressable}; use moa_core::{Error, ClockTime, Address, Addressable};
use super::state::{M68kType, Exceptions}; use super::state::{M68kType, Exceptions};
use super::instructions::{ use super::instructions::{
@ -40,6 +40,7 @@ const OPCG_FLINE: u8 = 0xF;
#[derive(Clone)] #[derive(Clone)]
pub struct M68kDecoder { pub struct M68kDecoder {
pub cputype: M68kType, pub cputype: M68kType,
pub clock: ClockTime,
pub start: u32, pub start: u32,
pub end: u32, pub end: u32,
pub instruction_word: u16, pub instruction_word: u16,
@ -47,9 +48,10 @@ pub struct M68kDecoder {
} }
impl M68kDecoder { impl M68kDecoder {
pub fn new(cputype: M68kType, start: u32) -> M68kDecoder { pub fn new(cputype: M68kType, clock: ClockTime, start: u32) -> M68kDecoder {
M68kDecoder { M68kDecoder {
cputype, cputype,
clock,
start, start,
end: start, end: start,
instruction_word: 0, instruction_word: 0,
@ -58,13 +60,14 @@ impl M68kDecoder {
} }
#[inline(always)] #[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.start = start;
self.end = start; self.end = start;
} }
pub fn decode_at(&mut self, memory: &mut dyn Addressable, start: u32) -> Result<(), Error> { pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: ClockTime, start: u32) -> Result<(), Error> {
self.init(start); self.init(clock, start);
self.instruction = self.decode_one(memory)?; self.instruction = self.decode_one(memory)?;
Ok(()) Ok(())
} }
@ -645,13 +648,13 @@ impl M68kDecoder {
} }
fn read_instruction_word(&mut self, memory: &mut dyn Addressable) -> Result<u16, Error> { fn read_instruction_word(&mut self, memory: &mut dyn Addressable) -> Result<u16, Error> {
let word = memory.read_beu16(self.end as Address)?; let word = memory.read_beu16(self.clock, self.end as Address)?;
self.end += 2; self.end += 2;
Ok(word) Ok(word)
} }
fn read_instruction_long(&mut self, memory: &mut dyn Addressable) -> Result<u32, Error> { fn read_instruction_long(&mut self, memory: &mut dyn Addressable) -> Result<u32, Error> {
let word = memory.read_beu32(self.end as Address)?; let word = memory.read_beu32(self.clock, self.end as Address)?;
self.end += 4; self.end += 4;
Ok(word) Ok(word)
} }
@ -781,7 +784,7 @@ impl M68kDecoder {
pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u32, length: u32) { pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u32, length: u32) {
let mut next = start; let mut next = start;
while next < (start + length) { while next < (start + length) {
match self.decode_at(memory, next) { match self.decode_at(memory, self.clock, next) {
Ok(()) => { Ok(()) => {
self.dump_decoded(memory); self.dump_decoded(memory);
next = self.end; next = self.end;
@ -790,7 +793,7 @@ impl M68kDecoder {
println!("{:?}", err); println!("{:?}", err);
match err { match err {
Error { native, .. } if native == Exceptions::IllegalInstruction as u32 => { 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) { pub fn dump_decoded(&mut self, memory: &mut dyn Addressable) {
let ins_data: Result<String, Error> = let ins_data: Result<String, Error> =
(0..((self.end - self.start) / 2)).map(|offset| (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(); ).collect();
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
} }

View File

@ -34,8 +34,8 @@ impl Steppable for M68k {
self.step_internal(system) self.step_internal(system)
} }
fn on_error(&mut self, _system: &System) { fn on_error(&mut self, system: &System) {
self.dump_state(); self.dump_state(system.clock);
} }
} }
@ -63,6 +63,7 @@ impl M68k {
} }
pub fn step_internal(&mut self, system: &System) -> Result<ClockDuration, Error> { pub fn step_internal(&mut self, system: &System) -> Result<ClockDuration, Error> {
self.current_clock = system.clock;
match self.state.status { match self.state.status {
Status::Init => self.init(), Status::Init => self.init(),
Status::Stopped => Err(Error::new("CPU stopped")), Status::Stopped => Err(Error::new("CPU stopped")),
@ -82,8 +83,8 @@ impl M68k {
} }
pub fn init(&mut self) -> Result<ClockDuration, Error> { pub fn init(&mut self) -> Result<ClockDuration, Error> {
self.state.ssp = self.port.read_beu32(0)?; self.state.ssp = self.port.read_beu32(self.current_clock, 0)?;
self.state.pc = self.port.read_beu32(4)?; self.state.pc = self.port.read_beu32(self.current_clock, 4)?;
self.state.status = Status::Running; self.state.status = Status::Running;
Ok(self.frequency.period_duration() * 16) Ok(self.frequency.period_duration() * 16)
} }
@ -169,7 +170,7 @@ impl M68k {
self.push_word((ins_word & 0xFFF0) | extra_code)?; self.push_word((ins_word & 0xFFF0) | extra_code)?;
let vector = self.state.vbr + offset as u32; 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)?; self.set_pc(addr)?;
Ok(()) Ok(())
@ -194,7 +195,7 @@ impl M68k {
self.push_word(sr)?; self.push_word(sr)?;
let vector = self.state.vbr + offset as u32; 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)?; self.set_pc(addr)?;
Ok(()) Ok(())
@ -205,7 +206,7 @@ impl M68k {
self.timer.decode.start(); self.timer.decode.start();
self.start_instruction_request(self.state.pc)?; 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.timer.decode.end();
self.timing.add_instruction(&self.decoder.instruction); 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; let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address;
while shift >= 0 { while shift >= 0 {
let byte = (self.state.d_reg[dreg as usize] >> shift) as u8; 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; addr += 2;
shift -= 8; shift -= 8;
} }
@ -1020,7 +1021,7 @@ impl M68k {
let mut shift = (size.in_bits() as i32) - 8; 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; let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address;
while shift >= 0 { 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; self.state.d_reg[dreg as usize] |= (byte as u32) << shift;
addr += 2; addr += 2;
shift -= 8; shift -= 8;
@ -1542,18 +1543,18 @@ impl M68k {
fn get_address_sized(&mut self, addr: Address, size: Size) -> Result<u32, Error> { fn get_address_sized(&mut self, addr: Address, size: Size) -> Result<u32, Error> {
self.start_request(addr as u32, size, MemAccess::Read, MemType::Data, false)?; self.start_request(addr as u32, size, MemAccess::Read, MemType::Data, false)?;
match size { match size {
Size::Byte => self.port.read_u8(addr).map(|value| value as u32), Size::Byte => self.port.read_u8(self.current_clock, addr).map(|value| value as u32),
Size::Word => self.port.read_beu16(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(addr), Size::Long => self.port.read_beu32(self.current_clock, addr),
} }
} }
fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), Error> { 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)?; self.start_request(addr as u32, size, MemAccess::Write, MemType::Data, false)?;
match size { match size {
Size::Byte => self.port.write_u8(addr, value as u8), Size::Byte => self.port.write_u8(self.current_clock, addr, value as u8),
Size::Word => self.port.write_beu16(addr, value as u16), Size::Word => self.port.write_beu16(self.current_clock, addr, value as u16),
Size::Long => self.port.write_beu32(addr, value), Size::Long => self.port.write_beu32(self.current_clock, addr, value),
} }
} }
@ -1587,12 +1588,12 @@ impl M68k {
*self.get_stack_pointer_mut() -= 2; *self.get_stack_pointer_mut() -= 2;
let addr = *self.get_stack_pointer_mut(); let addr = *self.get_stack_pointer_mut();
self.start_request(addr, Size::Word, MemAccess::Write, MemType::Data, false)?; 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<u16, Error> { fn pop_word(&mut self) -> Result<u16, Error> {
let addr = *self.get_stack_pointer_mut(); 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.start_request(addr, Size::Word, MemAccess::Read, MemType::Data, false)?;
*self.get_stack_pointer_mut() += 2; *self.get_stack_pointer_mut() += 2;
Ok(value) Ok(value)
@ -1602,12 +1603,12 @@ impl M68k {
*self.get_stack_pointer_mut() -= 4; *self.get_stack_pointer_mut() -= 4;
let addr = *self.get_stack_pointer_mut(); let addr = *self.get_stack_pointer_mut();
self.start_request(addr, Size::Long, MemAccess::Write, MemType::Data, false)?; 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<u32, Error> { fn pop_long(&mut self) -> Result<u32, Error> {
let addr = *self.get_stack_pointer_mut(); 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.start_request(addr, Size::Long, MemAccess::Read, MemType::Data, false)?;
*self.get_stack_pointer_mut() += 4; *self.get_stack_pointer_mut() += 4;
Ok(value) Ok(value)

View File

@ -1,5 +1,5 @@
use moa_core::{Address, BusPort, Frequency}; use moa_core::{ClockTime, Address, BusPort, Frequency};
use moa_core::timers::CpuTimer; use moa_core::timers::CpuTimer;
use crate::instructions::Size; use crate::instructions::Size;
@ -132,6 +132,7 @@ pub struct M68k {
pub debugger: M68kDebugger, pub debugger: M68kDebugger,
pub port: BusPort, pub port: BusPort,
pub timer: CpuTimer, pub timer: CpuTimer,
pub current_clock: ClockTime,
} }
impl Default for M68kState { impl Default for M68kState {
@ -160,23 +161,24 @@ impl M68k {
cputype, cputype,
frequency, frequency,
state: M68kState::default(), state: M68kState::default(),
decoder: M68kDecoder::new(cputype, 0), decoder: M68kDecoder::new(cputype, ClockTime::START, 0),
timing: M68kInstructionTiming::new(cputype, port.data_width()), timing: M68kInstructionTiming::new(cputype, port.data_width()),
debugger: M68kDebugger::default(), debugger: M68kDebugger::default(),
port, port,
timer: CpuTimer::default(), timer: CpuTimer::default(),
current_clock: ClockTime::START,
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.state = M68kState::default(); 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.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
self.debugger = M68kDebugger::default(); self.debugger = M68kDebugger::default();
} }
pub fn dump_state(&mut self) { pub fn dump_state(&mut self, clock: ClockTime) {
println!("Status: {:?}", self.state.status); println!("Status: {:?}", self.state.status);
println!("PC: {:#010x}", self.state.pc); println!("PC: {:#010x}", self.state.pc);
println!("SR: {:#06x}", self.state.sr); println!("SR: {:#06x}", self.state.sr);
@ -188,7 +190,7 @@ impl M68k {
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction); println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
println!(); println!();
self.port.dump_memory(self.state.ssp as Address, 0x40); self.port.dump_memory(clock, self.state.ssp as Address, 0x40);
println!(); println!();
} }
} }

View File

@ -32,10 +32,10 @@ impl Debuggable for Z80 {
} }
} }
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
self.decoder.decode_at(&mut self.port, self.state.pc)?; self.decoder.decode_at(&mut self.port, system.clock, self.state.pc)?;
self.decoder.dump_decoded(&mut self.port); self.decoder.dump_decoded(&mut self.port);
self.dump_state(); self.dump_state(system.clock);
Ok(()) Ok(())
} }

View File

@ -1,5 +1,5 @@
use moa_core::{Error, Address, Addressable}; use moa_core::{Error, ClockTime, Address, Addressable};
use crate::state::{Register, InterruptMode}; use crate::state::{Register, InterruptMode};
@ -173,6 +173,7 @@ pub enum Instruction {
} }
pub struct Z80Decoder { pub struct Z80Decoder {
pub clock: ClockTime,
pub start: u16, pub start: u16,
pub end: u16, pub end: u16,
pub instruction: Instruction, pub instruction: Instruction,
@ -182,6 +183,7 @@ pub struct Z80Decoder {
impl Default for Z80Decoder { impl Default for Z80Decoder {
fn default() -> Self { fn default() -> Self {
Self { Self {
clock: ClockTime::START,
start: 0, start: 0,
end: 0, end: 0,
instruction: Instruction::NOP, instruction: Instruction::NOP,
@ -191,7 +193,8 @@ impl Default for Z80Decoder {
} }
impl 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.start = start;
self.end = start; self.end = start;
self.execution_time = 0; self.execution_time = 0;
@ -674,14 +677,14 @@ impl Z80Decoder {
fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Error> { fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Error> {
let byte = device.read_u8(self.end as Address)?; let byte = device.read_u8(self.clock, self.end as Address)?;
self.end += 1; self.end += 1;
self.execution_time += 4; self.execution_time += 4;
Ok(byte) Ok(byte)
} }
fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Error> { fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result<u16, Error> {
let word = device.read_leu16(self.end as Address)?; let word = device.read_leu16(self.clock, self.end as Address)?;
self.end += 2; self.end += 2;
self.execution_time += 8; self.execution_time += 8;
Ok(word) Ok(word)
@ -690,7 +693,7 @@ impl Z80Decoder {
pub fn format_instruction_bytes(&mut self, memory: &mut dyn Addressable) -> String { pub fn format_instruction_bytes(&mut self, memory: &mut dyn Addressable) -> String {
let ins_data: String = let ins_data: String =
(0..(self.end - self.start)).map(|offset| (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(); ).collect();
ins_data ins_data
} }
@ -703,7 +706,7 @@ impl Z80Decoder {
pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u16, length: u16) { pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u16, length: u16) {
let mut next = start; let mut next = start;
while next < (start + length) { while next < (start + length) {
match self.decode_at(memory, next) { match self.decode_at(memory, self.clock, next) {
Ok(()) => { Ok(()) => {
self.dump_decoded(memory); self.dump_decoded(memory);
next = self.end; next = self.end;

View File

@ -31,8 +31,8 @@ impl Steppable for Z80 {
Ok(self.frequency.period_duration() * clocks as u64) Ok(self.frequency.period_duration() * clocks as u64)
} }
fn on_error(&mut self, _system: &System) { fn on_error(&mut self, system: &System) {
self.dump_state(); self.dump_state(system.clock);
} }
} }
@ -56,6 +56,7 @@ impl Transmutable for Z80 {
impl Z80 { impl Z80 {
pub fn step_internal(&mut self, system: &System) -> Result<u16, Error> { pub fn step_internal(&mut self, system: &System) -> Result<u16, Error> {
self.current_clock = system.clock;
match self.state.status { match self.state.status {
Status::Init => self.init(), Status::Init => self.init(),
Status::Halted => Err(Error::new("CPU stopped")), Status::Halted => Err(Error::new("CPU stopped")),
@ -92,7 +93,7 @@ impl Z80 {
} }
pub fn decode_next(&mut self) -> Result<(), Error> { 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; self.state.pc = self.decoder.end;
Ok(()) Ok(())
} }
@ -244,9 +245,9 @@ impl Z80 {
Instruction::EXsp(regpair) => { Instruction::EXsp(regpair) => {
let reg_value = self.get_register_pair_value(regpair); let reg_value = self.get_register_pair_value(regpair);
let sp = self.get_register_pair_value(RegisterPair::SP); 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.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 => { Instruction::HALT => {
self.state.status = Status::Halted; self.state.status = Status::Halted;
@ -616,17 +617,17 @@ impl Z80 {
fn push_word(&mut self, value: u16) -> Result<(), Error> { fn push_word(&mut self, value: u16) -> Result<(), Error> {
self.state.sp = self.state.sp.wrapping_sub(1); 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.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(()) Ok(())
} }
fn pop_word(&mut self) -> Result<u16, Error> { fn pop_word(&mut self) -> Result<u16, Error> {
let mut value; 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); 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); self.state.sp = self.state.sp.wrapping_add(1);
Ok(value) Ok(value)
} }
@ -638,21 +639,21 @@ impl Z80 {
LoadTarget::DirectRegWord(regpair) => self.get_register_pair_value(regpair), LoadTarget::DirectRegWord(regpair) => self.get_register_pair_value(regpair),
LoadTarget::IndirectRegByte(regpair) => { LoadTarget::IndirectRegByte(regpair) => {
let addr = self.get_register_pair_value(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) => { LoadTarget::IndirectOffsetByte(index_reg, offset) => {
let addr = self.get_index_register_value(index_reg); 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) => { LoadTarget::IndirectRegWord(regpair) => {
let addr = self.get_register_pair_value(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) => { 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) => { 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::ImmediateByte(data) => data as u16,
LoadTarget::ImmediateWord(data) => data, LoadTarget::ImmediateWord(data) => data,
@ -668,21 +669,21 @@ impl Z80 {
LoadTarget::DirectRegWord(regpair) => self.set_register_pair_value(regpair, value), LoadTarget::DirectRegWord(regpair) => self.set_register_pair_value(regpair, value),
LoadTarget::IndirectRegByte(regpair) => { LoadTarget::IndirectRegByte(regpair) => {
let addr = self.get_register_pair_value(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) => { LoadTarget::IndirectOffsetByte(index_reg, offset) => {
let addr = self.get_index_register_value(index_reg); 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) => { LoadTarget::IndirectRegWord(regpair) => {
let addr = self.get_register_pair_value(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) => { 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) => { 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), _ => panic!("Unsupported LoadTarget for set: {:?}", target),
} }
@ -695,11 +696,11 @@ impl Z80 {
Target::DirectRegHalf(reg) => Ok(self.get_index_register_half_value(reg)), Target::DirectRegHalf(reg) => Ok(self.get_index_register_half_value(reg)),
Target::IndirectReg(regpair) => { Target::IndirectReg(regpair) => {
let addr = self.get_register_pair_value(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) => { Target::IndirectOffset(reg, offset) => {
let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); 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), Target::Immediate(data) => Ok(data),
} }
@ -711,11 +712,11 @@ impl Z80 {
Target::DirectRegHalf(reg) => self.set_index_register_half_value(reg, value), Target::DirectRegHalf(reg) => self.set_index_register_half_value(reg, value),
Target::IndirectReg(regpair) => { Target::IndirectReg(regpair) => {
let addr = self.get_register_pair_value(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) => { Target::IndirectOffset(reg, offset) => {
let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); 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"), _ => panic!("Unsupported LoadTarget for set"),
} }

View File

@ -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::decode::Z80Decoder;
use crate::debugger::Z80Debugger; use crate::debugger::Z80Debugger;
@ -113,6 +113,7 @@ pub struct Z80 {
pub port: BusPort, pub port: BusPort,
pub reset: Signal<bool>, pub reset: Signal<bool>,
pub bus_request: Signal<bool>, pub bus_request: Signal<bool>,
pub current_clock: ClockTime,
} }
impl Z80 { impl Z80 {
@ -126,6 +127,7 @@ impl Z80 {
port, port,
reset: Signal::new(false), reset: Signal::new(false),
bus_request: Signal::new(false), bus_request: Signal::new(false),
current_clock: ClockTime::START,
} }
} }
@ -136,7 +138,7 @@ impl Z80 {
self.debugger = Z80Debugger::default(); self.debugger = Z80Debugger::default();
} }
pub fn dump_state(&mut self) { pub fn dump_state(&mut self, clock: ClockTime) {
println!("Status: {:?}", self.state.status); println!("Status: {:?}", self.state.status);
println!("PC: {:#06x}", self.state.pc); println!("PC: {:#06x}", self.state.pc);
println!("SP: {:#06x}", self.state.sp); 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!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction);
println!(); println!();
self.port.dump_memory(self.state.sp as Address, 0x40); self.port.dump_memory(clock, self.state.sp as Address, 0x40);
println!(); println!();
} }
} }

View File

@ -5,7 +5,7 @@ use moa_peripherals_yamaha::{Ym2612, Sn76489};
use moa_core::host::gfx::{Frame, FrameQueue, PixelEncoding}; use moa_core::host::gfx::{Frame, FrameQueue, PixelEncoding};
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key, KeyEvent /*, MouseUpdater, MouseState, MouseEvent*/}; 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<KeyEvent>); pub struct SynthControlsUpdater(mpsc::Sender<KeyEvent>);
@ -42,14 +42,14 @@ impl Steppable for SynthControl {
match event.key { match event.key {
Key::Enter => { Key::Enter => {
system.get_bus().write_u8(0x00, 0x28)?; system.get_bus().write_u8(system.clock, 0x00, 0x28)?;
system.get_bus().write_u8(0x01, if event.state { 0xF0 } else { 0x00 })?; system.get_bus().write_u8(system.clock, 0x01, if event.state { 0xF0 } else { 0x00 })?;
}, },
Key::A => { Key::A => {
system.get_bus().write_u8(0x10, 0x84)?; system.get_bus().write_u8(system.clock, 0x10, 0x84)?;
system.get_bus().write_u8(0x10, 0x0F)?; system.get_bus().write_u8(system.clock, 0x10, 0x0F)?;
system.get_bus().write_u8(0x10, if event.state { 0x90 } else { 0x9F })?; 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> { fn set_register(device: &mut dyn Addressable, bank: u8, reg: u8, data: u8) -> Result<(), Error> {
let addr = (bank as Address) * 2; let addr = (bank as Address) * 2;
device.write_u8(addr, reg)?; device.write_u8(ClockTime::START, addr, reg)?;
device.write_u8(addr + 1, data)?; device.write_u8(ClockTime::START, addr + 1, data)?;
Ok(()) Ok(())
} }

View File

@ -1,7 +1,7 @@
use std::fs; 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; const ATA_REG_DATA_WORD: Address = 0x20;
@ -57,7 +57,7 @@ impl Addressable for AtaDevice {
0x30 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 { match addr {
ATA_REG_DATA_WORD => { ATA_REG_DATA_WORD => {
self.selected_count -= 2; self.selected_count -= 2;
@ -90,7 +90,7 @@ impl Addressable for AtaDevice {
Ok(()) 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]); debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
match addr { match addr {
ATA_REG_DRIVE_HEAD => { self.selected_sector |= ((data[0] & 0x1F) as u32) << 24; }, ATA_REG_DRIVE_HEAD => { self.selected_sector |= ((data[0] & 0x1F) as u32) << 24; },

View File

@ -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; const REG_OUTPUT_B: Address = 0x00;
@ -57,7 +57,7 @@ impl Addressable for Mos6522 {
0x10 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 { match addr {
REG_OUTPUT_B => { data[0] = self.port_b.borrow_mut().data; }, REG_OUTPUT_B => { data[0] = self.port_b.borrow_mut().data; },
REG_OUTPUT_A => { data[0] = self.port_a.borrow_mut().data; }, REG_OUTPUT_A => { data[0] = self.port_a.borrow_mut().data; },
@ -73,7 +73,7 @@ impl Addressable for Mos6522 {
Ok(()) 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]); debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
match addr { match addr {
REG_OUTPUT_B => { self.port_b.borrow_mut().data = data[0]; self.port_b.notify(); }, REG_OUTPUT_B => { self.port_b.borrow_mut().data = data[0]; self.port_b.notify(); },

View File

@ -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; use moa_core::host::Tty;
@ -250,7 +250,7 @@ impl Addressable for MC68681 {
0x30 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 { match addr {
REG_SRA_RD => { REG_SRA_RD => {
data[0] = self.port_a.status data[0] = self.port_a.status
@ -302,7 +302,7 @@ impl Addressable for MC68681 {
Ok(()) 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); debug!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr);
match addr { match addr {
REG_MR1A_MR2A | REG_MR1B_MR2B | REG_CSRA_WR | REG_CSRB_WR => { REG_MR1A_MR2A | REG_MR1B_MR2B | REG_CSRA_WR | REG_CSRB_WR => {

View File

@ -1,6 +1,6 @@
use moa_core::{info, warn, debug}; 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::{Host, Audio};
use moa_core::host::audio::{SquareWave}; use moa_core::host::audio::{SquareWave};
@ -146,12 +146,12 @@ impl Addressable for Sn76489 {
0x01 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); warn!("{}: !!! device can't be read", DEV_NAME);
Ok(()) 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 { if addr != 0 {
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
return Ok(()); return Ok(());

View File

@ -1,12 +1,12 @@
/// Emulate the YM2612 FM Sound Synthesizer (used by the Sega Genesis) //! 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 //! 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 //! 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 //! source code that emulates the chip. It is still very much a work in progress
/// //!
/// Resources: //! Resources:
/// - Registers: https://www.smspower.org/maxim/Documents/YM2612 //! - Registers: https://www.smspower.org/maxim/Documents/YM2612
/// - Envelope and rates: http://gendev.spritesmind.net/forum/viewtopic.php?p=5716#5716 //! - Envelope and rates: http://gendev.spritesmind.net/forum/viewtopic.php?p=5716#5716
use std::num::NonZeroU8; use std::num::NonZeroU8;
use std::collections::VecDeque; use std::collections::VecDeque;
@ -140,7 +140,6 @@ struct EnvelopeGenerator {
rates: [usize; 4], rates: [usize; 4],
envelope_state: EnvelopeState, envelope_state: EnvelopeState,
last_state_change: ClockTime,
next_envelope_clock: EnvelopeClock, next_envelope_clock: EnvelopeClock,
envelope: u16, envelope: u16,
} }
@ -154,7 +153,6 @@ impl EnvelopeGenerator {
rates: [0; 4], rates: [0; 4],
envelope_state: EnvelopeState::Attack, envelope_state: EnvelopeState::Attack,
last_state_change: ClockTime::START,
next_envelope_clock: 0, next_envelope_clock: 0,
envelope: 0, envelope: 0,
} }
@ -172,8 +170,7 @@ impl EnvelopeGenerator {
self.rates[etype as usize] = rate; self.rates[etype as usize] = rate;
} }
fn notify_state_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) {
//self.last_state_change = envelope_clock;
if state { if state {
self.next_envelope_clock = envelope_clock; self.next_envelope_clock = envelope_clock;
self.envelope_state = EnvelopeState::Attack; 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) { fn set_frequency(&mut self, frequency: f32) {
self.frequency = frequency; self.frequency = frequency;
} }
@ -285,8 +286,8 @@ impl Operator {
self.envelope.set_rate(etype, rate) self.envelope.set_rate(etype, rate)
} }
fn notify_state_change(&mut self, state: bool, envelope_clock: EnvelopeClock) { fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) {
self.envelope.notify_state_change(state, envelope_clock); self.envelope.notify_key_change(state, envelope_clock);
} }
fn get_sample(&mut self, modulator: f32, envelope_clock: EnvelopeClock) -> f32 { fn get_sample(&mut self, modulator: f32, envelope_clock: EnvelopeClock) -> f32 {
@ -306,8 +307,9 @@ struct Channel {
#[allow(dead_code)] #[allow(dead_code)]
debug_name: String, debug_name: String,
operators: Vec<Operator>, operators: Vec<Operator>,
on_state: u8, key_state: u8,
next_on_state: u8, next_key_clock: ClockTime,
next_key_state: u8,
base_frequency: f32, base_frequency: f32,
algorithm: OperatorAlgorithm, algorithm: OperatorAlgorithm,
} }
@ -317,8 +319,9 @@ impl Channel {
Self { Self {
debug_name: debug_name.clone(), debug_name: debug_name.clone(),
operators: (0..OPERATORS).map(|i| Operator::new(format!("{}, op {}", debug_name, i), sample_rate)).collect(), operators: (0..OPERATORS).map(|i| Operator::new(format!("{}, op {}", debug_name, i), sample_rate)).collect(),
on_state: 0, key_state: 0,
next_on_state: 0, next_key_clock: ClockTime::START,
next_key_state: 0,
base_frequency: 0.0, base_frequency: 0.0,
algorithm: OperatorAlgorithm::A0, algorithm: OperatorAlgorithm::A0,
} }
@ -331,15 +334,25 @@ impl Channel {
} }
} }
fn get_sample(&mut self, envelope_clock: EnvelopeClock) -> f32 { fn change_key_state(&mut self, clock: ClockTime, key: u8) {
if self.on_state != self.next_on_state { self.next_key_clock = clock;
self.on_state = self.next_on_state; 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() { 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) self.get_algorithm_sample(envelope_clock)
} else { } else {
0.0 0.0
@ -492,17 +505,18 @@ impl Steppable for Ym2612 {
//if self.source.space_available() >= samples { //if self.source.space_available() >= samples {
let mut buffer = vec![0.0; samples]; let mut buffer = vec![0.0; samples];
for (i, buffered_sample) in buffer.iter_mut().enumerate().take(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; let mut sample = 0.0;
for ch in 0..(CHANNELS - 1) { 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 { if self.dac.enabled {
sample += self.dac.get_sample(); sample += self.dac.get_sample();
} else { } 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); *buffered_sample = sample.clamp(-1.0, 1.0);
@ -515,7 +529,7 @@ impl Steppable for Ym2612 {
} }
impl 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 // Keep a copy for debugging purposes, and if the original values are needed
self.registers[bank as usize * 256 + reg as usize] = data; self.registers[bank as usize * 256 + reg as usize] = data;
@ -545,7 +559,7 @@ impl Ym2612 {
return; return;
}, },
}; };
self.channels[ch].next_on_state = data >> 4; self.channels[ch].change_key_state(clock, data >> 4);
}, },
0x2a => { 0x2a => {
@ -695,7 +709,7 @@ impl Addressable for Ym2612 {
0x04 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 { match addr {
0 | 1 | 2 | 3 => { 0 | 1 | 2 | 3 => {
// Read the status byte (busy/overflow) // Read the status byte (busy/overflow)
@ -709,7 +723,7 @@ impl Addressable for Ym2612 {
Ok(()) 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]); debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
match addr { match addr {
0 => { 0 => {
@ -717,7 +731,7 @@ impl Addressable for Ym2612 {
}, },
1 => { 1 => {
if let Some(reg) = self.selected_reg_0 { 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 => { 2 => {
@ -725,7 +739,7 @@ impl Addressable for Ym2612 {
}, },
3 => { 3 => {
if let Some(reg) = self.selected_reg_1 { 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]);
} }
}, },
_ => { _ => {

View File

@ -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"; const DEV_NAME: &str = "z8530";
@ -13,13 +13,13 @@ impl Addressable for Z8530 {
0x10 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); warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
debug!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data); debug!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data);
Ok(()) 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]); debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
Ok(()) Ok(())

View File

@ -1,6 +1,6 @@
use moa_core::{warn, info}; 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}; use moa_core::host::{Host, ControllerUpdater, HostData, ControllerDevice, ControllerEvent};
@ -154,7 +154,7 @@ impl Addressable for GenesisControllers {
0x30 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 // If the address is even, only the second byte (odd byte) will be meaningful
let mut i = 0; let mut i = 0;
if (addr % 2) == 0 { if (addr % 2) == 0 {
@ -179,7 +179,7 @@ impl Addressable for GenesisControllers {
Ok(()) 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; self.reset_timer = ClockDuration::ZERO;
info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use moa_core::{warn, info}; 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"; const DEV_NAME: &str = "coprocessor";
@ -28,7 +28,7 @@ impl Addressable for CoprocessorCoordinator {
0x4000 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 { match addr {
0x100 => { 0x100 => {
data[0] = if self.bus_request.get() && self.reset.get() { 0x01 } else { 0x00 }; data[0] = if self.bus_request.get() && self.reset.get() { 0x01 } else { 0x00 };
@ -39,7 +39,7 @@ impl Addressable for CoprocessorCoordinator {
Ok(()) 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]); info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
match addr { match addr {
0x000 => { /* ROM vs DRAM mode */ }, 0x000 => { /* ROM vs DRAM mode */ },
@ -79,11 +79,11 @@ impl Addressable for CoprocessorBankRegister {
0x01 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(()) 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) << 23)) & 0xFF8000;
//let value = ((self.base.get() << 1) | ((data[0] as Address) << 15)) & 0xFF8000; //let value = ((self.base.get() << 1) | ((data[0] as Address) << 15)) & 0xFF8000;
println!("New base is {:x}", value); println!("New base is {:x}", value);
@ -118,12 +118,12 @@ impl Addressable for CoprocessorBankArea {
0x8000 0x8000
} }
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.bus.borrow_mut().read(self.base.get() + addr, data) self.bus.borrow_mut().read(clock, self.base.get() + addr, data)
} }
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> {
self.bus.borrow_mut().write(self.base.get() + addr, data) self.bus.borrow_mut().write(clock, self.base.get() + addr, data)
} }
} }

View File

@ -229,7 +229,7 @@ impl Ym7101Memory {
while self.transfer_remain > 0 { while self.transfer_remain > 0 {
let mut data = [0; 2]; 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 addr = self.transfer_dest_addr as usize;
let target = self.get_transfer_target_mut(); let target = self.get_transfer_target_mut();
@ -783,7 +783,7 @@ impl Addressable for Ym7101 {
0x20 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 { match addr {
// Read from Data Port // Read from Data Port
0x00 | 0x02 => self.state.memory.read_data_port(addr, data)?, 0x00 | 0x02 => self.state.memory.read_data_port(addr, data)?,
@ -814,7 +814,7 @@ impl Addressable for Ym7101 {
Ok(()) 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 { match addr {
// Write to Data Port // Write to Data Port
0x00 | 0x02 => self.state.memory.write_data_port(data)?, 0x00 | 0x02 => self.state.memory.write_data_port(data)?,
@ -840,7 +840,7 @@ impl Addressable for Ym7101 {
}, },
0x11 | 0x12 => { 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); }, _ => { warn!("{}: !!! unhandled write to {:x} with {:?}", DEV_NAME, addr, data); },

View File

@ -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; //const CA0: u8 = 0x01;
@ -38,7 +38,7 @@ impl Addressable for IWM {
0x10 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); self.flip_switches(addr);
if (addr & 0x01) != 0 { if (addr & 0x01) != 0 {
@ -71,7 +71,7 @@ impl Addressable for IWM {
Ok(()) 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); self.flip_switches(addr);
info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); info!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);

View File

@ -69,19 +69,19 @@ impl Addressable for Mainboard {
0x01000000 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 { 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) { } 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) { } 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) { } 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) { } 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) { } 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) { } else if (0xF80000..0xF80010).contains(&addr) {
// Debugger // Debugger
Ok(()) 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 { 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) { } 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) { } 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) { } 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) { } 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) { } else if (0xF00000..0xF80000).contains(&addr) {
self.phase_read.write(addr, data) self.phase_read.write(clock, addr, data)
} else { } else {
Err(Error::new(&format!("Error writing address {:#010x}", addr))) Err(Error::new(&format!("Error writing address {:#010x}", addr)))
} }
@ -146,13 +146,13 @@ impl Addressable for PhaseRead {
0x80000 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 // TODO I'm not sure how this is supposed to work
data[0] = 0x00; data[0] = 0x00;
Ok(()) 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 // TODO I'm not sure how this is supposed to work
Ok(()) Ok(())
} }

View File

@ -62,7 +62,7 @@ impl Steppable for MacVideo {
let mut frame = Frame::new(SCRN_SIZE.0, SCRN_SIZE.1, self.frame_queue.encoding()); let mut frame = Frame::new(SCRN_SIZE.0, SCRN_SIZE.1, self.frame_queue.encoding());
for y in 0..SCRN_SIZE.1 { for y in 0..SCRN_SIZE.1 {
for x in 0..(SCRN_SIZE.0 / 16) { 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); frame.blit(x * 16, y, BitIter::new(word), 16, 1);
} }
} }

View File

@ -1,7 +1,7 @@
use std::sync::{Arc, Mutex}; 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::gfx::{Frame, FrameQueue};
use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, KeyEvent}; use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, KeyEvent};
@ -64,7 +64,7 @@ impl Addressable for Model1Peripherals {
0x820 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) { if (0x20..=0xA0).contains(&addr) {
let offset = addr - 0x20; let offset = addr - 0x20;
data[0] = 0; data[0] = 0;
@ -86,7 +86,7 @@ impl Addressable for Model1Peripherals {
Ok(()) 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]); debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
if (0x420..0x820).contains(&addr) { if (0x420..0x820).contains(&addr) {
self.video_mem[addr as usize - 0x420] = data[0]; self.video_mem[addr as usize - 0x420] = data[0];

View File

@ -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 * 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 * add doc strings everywhere
* get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion * get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion