Added clock argument to addressable operations
This commit is contained in:
parent
cd5336bc23
commit
86eb73f78a
|
@ -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};
|
||||
|
||||
|
|
|
@ -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]),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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" => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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; },
|
||||
|
|
|
@ -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(); },
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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(());
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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); },
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
8
todo.txt
8
todo.txt
|
@ -1,9 +1,11 @@
|
|||
|
||||
* remove the old timer stuff and replace with opentelemetry if it can be wasm compatible
|
||||
|
||||
* maybe I should make ClockDuration use picos as the base instead, and use u64 since that gives like 212 days or something instead of 5h
|
||||
and should prevent split nanoseconds which is the main concern
|
||||
|
||||
* the audio needs to not run if nothing is using it or there's constant buffer underruns
|
||||
|
||||
* add a Duration-like clock type that records femto seconds
|
||||
* move parser to utils/ of some kind, or lib/
|
||||
|
||||
* add doc strings everywhere
|
||||
* get rustfmt, rustdoc, and clippy working in some kind of semi-automatic fashion
|
||||
|
||||
|
|
Loading…
Reference in New Issue