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};

View File

@ -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]),
}
}

View File

@ -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<u8, Error> {
fn read_u8(&mut self, clock: ClockTime, addr: Address) -> Result<u8, Error> {
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<u16, Error> {
fn read_beu16(&mut self, clock: ClockTime, addr: Address) -> Result<u16, Error> {
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<u16, Error> {
fn read_leu16(&mut self, clock: ClockTime, addr: Address) -> Result<u16, Error> {
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<u32, Error> {
fn read_beu32(&mut self, clock: ClockTime, addr: Address) -> Result<u32, Error> {
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<u32, Error> {
fn read_leu32(&mut self, clock: ClockTime, addr: Address) -> Result<u32, Error> {
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)
}
}

View File

@ -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,
}
}
}

View File

@ -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(())
}

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::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<bool, Error> {
fn execute_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
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" => {

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::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<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;
Ok(word)
}
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;
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<String, Error> =
(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);
}

View File

@ -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<ClockDuration, Error> {
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<ClockDuration, Error> {
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<u32, Error> {
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<u16, Error> {
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<u32, Error> {
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)

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 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!();
}
}

View File

@ -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(())
}

View File

@ -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<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.execution_time += 4;
Ok(byte)
}
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.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;

View File

@ -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<u16, Error> {
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<u16, Error> {
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"),
}

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::debugger::Z80Debugger;
@ -113,6 +113,7 @@ pub struct Z80 {
pub port: BusPort,
pub reset: Signal<bool>,
pub bus_request: Signal<bool>,
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!();
}
}

View File

@ -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<KeyEvent>);
@ -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(())
}

View File

@ -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; },

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;
@ -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(); },

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;
@ -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 => {

View File

@ -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(());

View File

@ -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<Operator>,
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]);
}
},
_ => {

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";
@ -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(())

View File

@ -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]);

View File

@ -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)
}
}

View File

@ -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); },

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;
@ -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]);

View File

@ -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(())
}

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());
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);
}
}

View File

@ -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];

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
* 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