Compare commits

...

4 Commits

Author SHA1 Message Date
transistor fet 4bc1794d0f
Merge 471695aff5 into 6e7e315808 2024-04-08 03:17:25 +00:00
transistor 471695aff5 Fixed timing tests and added no io tests option 2024-04-07 20:16:55 -07:00
transistor 1c5ad3999a Minor fixes 2024-04-07 19:52:10 -07:00
transistor 59199533eb Added a hacky Signalable trait to replace the Z80 signals 2024-04-07 10:38:41 -07:00
19 changed files with 274 additions and 179 deletions

3
Cargo.lock generated
View File

@ -1247,9 +1247,10 @@ name = "rad-tests"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap 3.2.25", "clap 3.2.25",
"emulator-hal",
"emulator-hal-memory",
"femtos", "femtos",
"flate2", "flate2",
"moa-core",
"moa-z80", "moa-z80",
"serde", "serde",
"serde_derive", "serde_derive",

View File

@ -171,6 +171,16 @@ pub trait Inspectable {
fn inspect(&mut self, system: &System, args: &[&str]) -> Result<(), Error>; fn inspect(&mut self, system: &System, args: &[&str]) -> Result<(), Error>;
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Signal {
Reset,
BusRequest,
}
pub trait Signalable {
fn set_signal(&mut self, signal: Signal, flag: bool) -> Result<(), Error>;
fn signal(&mut self, signal: Signal) -> Option<bool>;
}
pub trait Transmutable { pub trait Transmutable {
#[inline] #[inline]
@ -197,6 +207,11 @@ pub trait Transmutable {
fn as_inspectable(&mut self) -> Option<&mut dyn Inspectable> { fn as_inspectable(&mut self) -> Option<&mut dyn Inspectable> {
None None
} }
#[inline]
fn as_signalable(&mut self) -> Option<&mut dyn Signalable> {
None
}
} }
pub type TransmutableBox = Rc<RefCell<Box<dyn Transmutable>>>; pub type TransmutableBox = Rc<RefCell<Box<dyn Transmutable>>>;

View File

@ -71,3 +71,9 @@ impl<E> From<HostError<E>> for Error {
Self::Other("other".to_string()) Self::Other("other".to_string())
} }
} }
impl From<fmt::Error> for Error {
fn from(err: fmt::Error) -> Self {
Self::Other(format!("{:?}", err))
}
}

View File

@ -7,7 +7,8 @@ mod memory;
mod system; mod system;
pub use crate::devices::{ pub use crate::devices::{
Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device, Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Signalable, Signal, Transmutable, TransmutableBox,
Device,
}; };
pub use crate::devices::{ pub use crate::devices::{
read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable, read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable,
@ -17,4 +18,4 @@ pub use crate::interrupts::InterruptController;
pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice, dump_memory}; pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice, dump_memory};
pub use crate::system::System; pub use crate::system::System;
pub use emulator_hal::bus::{BusAccess}; pub use emulator_hal::BusAccess;

View File

@ -4,6 +4,7 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt::Write; use std::fmt::Write;
use femtos::Instant; use femtos::Instant;
use emulator_hal::{self, BusAccess, Error as EmuError};
use crate::error::Error; use crate::error::Error;
use crate::devices::{Address, Addressable, Transmutable, Device, read_beu16}; use crate::devices::{Address, Addressable, Transmutable, Device, read_beu16};
@ -236,7 +237,7 @@ impl Bus {
let to = if count < 16 { count / 2 } else { 8 }; let to = if count < 16 { count / 2 } else { 8 };
for _ in 0..to { for _ in 0..to {
let word = self.read_beu16(clock, addr); let word = Addressable::read_beu16(self, clock, addr);
if word.is_err() { if word.is_err() {
println!("{}", line); println!("{}", line);
return; return;
@ -353,7 +354,7 @@ impl Addressable for BusPort {
for i in (0..data.len()).step_by(self.data_width as usize) { for i in (0..data.len()).step_by(self.data_width as usize) {
let addr_index = (addr + i as Address) & self.address_mask; let addr_index = (addr + i as Address) & self.address_mask;
let end = cmp::min(i + self.data_width as usize, data.len()); let end = cmp::min(i + self.data_width as usize, data.len());
subdevice.read(clock, addr_index, &mut data[i..end])?; Addressable::read(&mut *subdevice, clock, addr_index, &mut data[i..end])?;
} }
Ok(()) Ok(())
} }
@ -364,7 +365,7 @@ impl Addressable for BusPort {
for i in (0..data.len()).step_by(self.data_width as usize) { for i in (0..data.len()).step_by(self.data_width as usize) {
let addr_index = (addr + i as Address) & self.address_mask; let addr_index = (addr + i as Address) & self.address_mask;
let end = cmp::min(i + self.data_width as usize, data.len()); let end = cmp::min(i + self.data_width as usize, data.len());
subdevice.write(clock, addr_index, &data[i..end])?; Addressable::write(&mut *subdevice, clock, addr_index, &data[i..end])?;
} }
Ok(()) Ok(())
} }
@ -412,9 +413,7 @@ where
} }
} }
use emulator_hal::bus::{self, BusAccess}; impl EmuError for Error {}
impl bus::Error for Error {}
impl BusAccess<u64> for &mut dyn Addressable { impl BusAccess<u64> for &mut dyn Addressable {
type Instant = Instant; type Instant = Instant;
@ -430,3 +429,18 @@ impl BusAccess<u64> for &mut dyn Addressable {
Ok(data.len()) Ok(data.len())
} }
} }
impl BusAccess<u64> for Bus {
type Instant = Instant;
type Error = Error;
fn read(&mut self, now: Instant, addr: Address, data: &mut [u8]) -> Result<usize, Self::Error> {
Addressable::read(self, now, addr, data)?;
Ok(data.len())
}
fn write(&mut self, now: Instant, addr: Address, data: &[u8]) -> Result<usize, Self::Error> {
Addressable::write(self, now, addr, data)?;
Ok(data.len())
}
}

View File

@ -86,11 +86,18 @@ impl Debuggable for M68k<Instant> {
} }
} }
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
let mut bus = system.bus.borrow_mut();
let mut adapter: BusAdapter<u32, u64, &mut dyn Addressable, Error> =
BusAdapter::new(&mut *bus, |addr| addr as u64, |err| err);
// TODO this is called by the debugger, but should be called some other way // TODO this is called by the debugger, but should be called some other way
//let _ = self.decoder.decode_at(&mut self.bus, true, self.state.pc); let mut decoder = M68kDecoder::new(self.info.chip, true, self.state.pc);
//self.decoder.dump_decoded(&mut self.bus); decoder.decode_at(&mut adapter, &mut M68kBusPort::default(), true, self.state.pc)?;
//self.dump_state(); decoder.dump_decoded(system.clock, &mut adapter);
let mut writer = String::new();
self.dump_state(&mut writer)?;
println!("{}", writer);
Ok(()) Ok(())
} }

View File

@ -1,7 +1,7 @@
use core::fmt::Write; use core::fmt::Write;
use emulator_hal::{BusAccess, Instant as EmuInstant}; use emulator_hal::{BusAccess, Instant as EmuInstant};
use crate::state::{Z80Error, Z80Address} ; use crate::state::{Z80Error, Z80Address};
use crate::instructions::{ use crate::instructions::{
Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target,
LoadTarget, UndocumentedCopy, Instruction, LoadTarget, UndocumentedCopy, Instruction,
@ -55,27 +55,16 @@ impl Z80Decoder {
Ok(decoder.decoder) Ok(decoder.decoder)
} }
/* pub fn dump_disassembly<Bus>(bus: &mut Bus, start: Z80Address, length: Z80Address)
pub fn format_instruction_bytes(&mut self) -> String { where
let mut ins_data = String::new(); Bus: BusAccess<Z80Address>,
for offset in 0..self.decoder.end.saturating_sub(self.decoder.start) { {
write!(ins_data, "{:02x} ", self.bus.read_u8(self.clock, self.decoder.start + offset).unwrap()).unwrap()
}
ins_data
}
pub fn dump_decoded(&mut self) {
let ins_data = self.format_instruction_bytes();
println!("{:#06x}: {}\n\t{:?}\n", self.decoder.start, ins_data, self.decoder.instruction);
}
pub fn dump_disassembly(&mut self, start: Z80Address, length: Z80Address) {
let mut next = start; let mut next = start;
while next < (start + length) { while next < (start + length) {
match self.decode_at(self.clock, next) { match Z80Decoder::decode_at(bus, Bus::Instant::START, next) {
Ok(()) => { Ok(mut decoder) => {
self.dump_decoded(); decoder.dump_decoded(bus);
next = self.decoder.end; next = decoder.end;
}, },
Err(err) => { Err(err) => {
println!("{:?}", err); println!("{:?}", err);
@ -84,7 +73,25 @@ impl Z80Decoder {
} }
} }
} }
*/
pub fn dump_decoded<Bus>(&mut self, bus: &mut Bus)
where
Bus: BusAccess<Z80Address>,
{
let ins_data = self.format_instruction_bytes(bus);
println!("{:#06x}: {}\n\t{:?}\n", self.start, ins_data, self.instruction);
}
pub fn format_instruction_bytes<Bus>(&mut self, bus: &mut Bus) -> String
where
Bus: BusAccess<Z80Address>,
{
let mut ins_data = String::new();
for offset in 0..self.end.saturating_sub(self.start) {
write!(ins_data, "{:02x} ", bus.read_u8(Bus::Instant::START, self.start + offset).unwrap()).unwrap()
}
ins_data
}
} }
pub struct DecodeNext<'a, Bus, Instant> pub struct DecodeNext<'a, Bus, Instant>
@ -107,11 +114,7 @@ where
Ok(()) Ok(())
} }
pub fn decode_bare( pub fn decode_bare(&mut self, ins: u8, extra_instruction_bytes: u16) -> Result<Instruction, Z80Error> {
&mut self,
ins: u8,
extra_instruction_bytes: u16,
) -> Result<Instruction, Z80Error> {
self.decoder.extra_instruction_bytes = extra_instruction_bytes; self.decoder.extra_instruction_bytes = extra_instruction_bytes;
match get_ins_x(ins) { match get_ins_x(ins) {
0 => match get_ins_z(ins) { 0 => match get_ins_z(ins) {
@ -559,11 +562,7 @@ where
} }
} }
fn decode_index_target( fn decode_index_target(&mut self, index_reg: IndexRegister, z: u8) -> Result<Option<Target>, Z80Error> {
&mut self,
index_reg: IndexRegister,
z: u8,
) -> Result<Option<Target>, Z80Error> {
let result = match z { let result = match z {
4 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 0))), 4 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 0))),
5 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 1))), 5 => Some(Target::DirectRegHalf(get_index_register_half(index_reg, 1))),
@ -578,7 +577,9 @@ where
fn read_instruction_byte(&mut self) -> Result<u8, Z80Error> { fn read_instruction_byte(&mut self) -> Result<u8, Z80Error> {
let byte = self.bus.read_u8(self.clock, self.decoder.end) let byte = self
.bus
.read_u8(self.clock, self.decoder.end)
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?; .map_err(|err| Z80Error::BusError(format!("{:?}", err)))?;
self.decoder.end = self.decoder.end.wrapping_add(1); self.decoder.end = self.decoder.end.wrapping_add(1);
Ok(byte) Ok(byte)
@ -587,7 +588,9 @@ where
fn read_instruction_word(&mut self) -> Result<u16, Z80Error> { fn read_instruction_word(&mut self) -> Result<u16, Z80Error> {
let mut bytes = [0; 2]; let mut bytes = [0; 2];
for byte in bytes.iter_mut() { for byte in bytes.iter_mut() {
*byte = self.bus.read_u8(self.clock, self.decoder.end & 0xFFFF) *byte = self
.bus
.read_u8(self.clock, self.decoder.end & 0xFFFF)
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?; .map_err(|err| Z80Error::BusError(format!("{:?}", err)))?;
self.decoder.end = self.decoder.end.wrapping_add(1); self.decoder.end = self.decoder.end.wrapping_add(1);
} }

View File

@ -1,4 +1,3 @@
use emulator_hal::{BusAccess, Instant as EmuInstant, Error as EmuError, Step, Inspect, Debug, IntoAddress}; use emulator_hal::{BusAccess, Instant as EmuInstant, Error as EmuError, Step, Inspect, Debug, IntoAddress};
use crate::state::{Z80, Z80Error, Z80Address, Status}; use crate::state::{Z80, Z80Error, Z80Address, Status};
@ -23,10 +22,9 @@ where
fn step(&mut self, now: Self::Instant, bus: &mut Bus) -> Result<Self::Instant, Self::Error> { fn step(&mut self, now: Self::Instant, bus: &mut Bus) -> Result<Self::Instant, Self::Error> {
let mut executor = self.begin(now, bus)?; let mut executor = self.begin(now, bus)?;
executor.step_one()?; let clocks = executor.step_one()?;
self.previous_cycle = executor.end(); self.previous_cycle = executor.end();
// TODO fix this Ok(now + Instant::hertz_to_duration(self.frequency.as_hz() as u64) * clocks as u32)
Ok(now)
} }
} }
@ -51,11 +49,9 @@ where
fn step(&mut self, now: Self::Instant, bus: (&mut MemBus, &mut IoBus)) -> Result<Self::Instant, Self::Error> { fn step(&mut self, now: Self::Instant, bus: (&mut MemBus, &mut IoBus)) -> Result<Self::Instant, Self::Error> {
let executor = self.begin(now, bus)?; let executor = self.begin(now, bus)?;
executor.step_one()?; let clocks = executor.step_one()?;
self.previous_cycle = executor.end(); self.previous_cycle = executor.end();
// TODO fix this Ok(now + Instant::hertz_to_duration(self.frequency.as_hz() as u64) * clocks as u32)
Ok(now)
} }
} }
*/ */

View File

@ -5,7 +5,7 @@ use crate::instructions::{
Condition, Instruction, LoadTarget, Target, Register, InterruptMode, RegisterPair, IndexRegister, SpecialRegister, Condition, Instruction, LoadTarget, Target, Register, InterruptMode, RegisterPair, IndexRegister, SpecialRegister,
IndexRegisterHalf, Size, Direction, UndocumentedCopy, IndexRegisterHalf, Size, Direction, UndocumentedCopy,
}; };
use crate::state::{Z80, Z80Error, Z80State, Z80Address, Status, Flags}; use crate::state::{Z80, Z80Error, Z80State, Z80Signals, Z80Address, Status, Flags};
use crate::timing::Z80InstructionCycles; use crate::timing::Z80InstructionCycles;
use crate::debugger::Z80Debugger; use crate::debugger::Z80Debugger;
@ -41,12 +41,17 @@ impl<Instant> Z80<Instant>
where where
Instant: EmuInstant, Instant: EmuInstant,
{ {
pub(crate) fn begin<'a, Bus>(&'a mut self, clock: Instant, bus: &'a mut Bus) -> Result<ExecuteNext<'a, &mut Bus, Instant>, Z80Error> pub(crate) fn begin<'a, Bus>(
&'a mut self,
clock: Instant,
bus: &'a mut Bus,
) -> Result<ExecuteNext<'a, &'a mut Bus, Instant>, Z80Error>
where where
Bus: BusAccess<Z80Address, Instant = Instant>, Bus: BusAccess<Z80Address, Instant = Instant>,
{ {
let executor = ExecuteNext { let executor = ExecuteNext {
state: &mut self.state, state: &mut self.state,
signals: &mut self.signals,
debugger: &mut self.debugger, debugger: &mut self.debugger,
cycle: Z80Cycle::at_time(clock), cycle: Z80Cycle::at_time(clock),
bus, bus,
@ -61,6 +66,7 @@ where
Bus: BusAccess<Z80Address, Instant = Instant>, Bus: BusAccess<Z80Address, Instant = Instant>,
{ {
state: &'a mut Z80State, state: &'a mut Z80State,
signals: &'a mut Z80Signals,
debugger: &'a mut Z80Debugger, debugger: &'a mut Z80Debugger,
cycle: Z80Cycle<Instant>, cycle: Z80Cycle<Instant>,
bus: Bus, bus: Bus,
@ -71,28 +77,22 @@ where
Bus: BusAccess<Z80Address, Instant = Instant>, Bus: BusAccess<Z80Address, Instant = Instant>,
Instant: EmuInstant, Instant: EmuInstant,
{ {
pub(crate) fn end(mut self) -> Z80Cycle<Instant> { pub(crate) fn end(self) -> Z80Cycle<Instant> {
self.cycle self.cycle
} }
pub(crate) fn step_one(&mut self) -> Result<u16, Z80Error> { pub(crate) fn step_one(&mut self) -> Result<u16, Z80Error> {
// TODO restore the reset and bus request signals let clocks = if self.signals.reset {
//let clocks = if self.reset.get() { self.reset()?
// self.reset()? } else if self.signals.bus_request {
//} else if self.bus_request.get() { 4
// 4 } else {
//} else { self.step_internal()?
// self.step_internal(self.cycle.current_clock)? };
//};
//Ok(self.frequency.period_duration() * clocks as u64)
// TODO remove this when done
let clocks = self.step_internal(self.cycle.current_clock)?;
Ok(clocks) Ok(clocks)
} }
fn step_internal(&mut self, clock: Instant) -> Result<u16, Z80Error> { fn step_internal(&mut self) -> Result<u16, Z80Error> {
match self.state.status { match self.state.status {
Status::Init => self.init(), Status::Init => self.init(),
Status::Halted => Err(Z80Error::Halted), Status::Halted => Err(Z80Error::Halted),
@ -630,7 +630,9 @@ where
let parity = if count != 0 { Flags::Parity as u8 } else { 0 }; let parity = if count != 0 { Flags::Parity as u8 } else { 0 };
self.set_flags(mask, parity); self.set_flags(mask, parity);
if (self.cycle.decoder.instruction == Instruction::LDIR || self.cycle.decoder.instruction == Instruction::LDDR) && count != 0 { if (self.cycle.decoder.instruction == Instruction::LDIR || self.cycle.decoder.instruction == Instruction::LDDR)
&& count != 0
{
self.cycle.took_branch = true; self.cycle.took_branch = true;
self.state.pc -= 2; self.state.pc -= 2;
} }
@ -1126,13 +1128,17 @@ where
fn read_port_u8(&mut self, addr: u16) -> Result<u8, Z80Error> { fn read_port_u8(&mut self, addr: u16) -> Result<u8, Z80Error> {
self.increment_refresh(1); self.increment_refresh(1);
Ok(self.bus.read_u8(self.cycle.current_clock, addr as Z80Address) Ok(self
.bus
.read_u8(self.cycle.current_clock, addr as Z80Address)
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?) .map_err(|err| Z80Error::BusError(format!("{:?}", err)))?)
} }
fn write_port_u8(&mut self, addr: u16, value: u8) -> Result<(), Z80Error> { fn write_port_u8(&mut self, addr: u16, value: u8) -> Result<(), Z80Error> {
self.increment_refresh(1); self.increment_refresh(1);
Ok(self.bus.write_u8(self.cycle.current_clock, addr as Z80Address, value) Ok(self
.bus
.write_u8(self.cycle.current_clock, addr as Z80Address, value)
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?) .map_err(|err| Z80Error::BusError(format!("{:?}", err)))?)
} }
@ -1144,7 +1150,9 @@ where
let mut bytes = [0; 2]; let mut bytes = [0; 2];
for byte in bytes.iter_mut() { for byte in bytes.iter_mut() {
self.increment_refresh(1); self.increment_refresh(1);
*byte = self.bus.read_u8(self.cycle.current_clock, addr & 0xFFFF) *byte = self
.bus
.read_u8(self.cycle.current_clock, addr & 0xFFFF)
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?; .map_err(|err| Z80Error::BusError(format!("{:?}", err)))?;
addr = addr.wrapping_add(1); addr = addr.wrapping_add(1);
} }
@ -1159,7 +1167,8 @@ where
let mut bytes = value.to_le_bytes(); let mut bytes = value.to_le_bytes();
for byte in bytes.iter_mut() { for byte in bytes.iter_mut() {
self.increment_refresh(1); self.increment_refresh(1);
self.bus.write_u8(self.cycle.current_clock, addr & 0xFFFF, *byte) self.bus
.write_u8(self.cycle.current_clock, addr & 0xFFFF, *byte)
.map_err(|err| Z80Error::BusError(format!("{:?}", err)))?; .map_err(|err| Z80Error::BusError(format!("{:?}", err)))?;
addr = addr.wrapping_add(1); addr = addr.wrapping_add(1);
} }
@ -1172,7 +1181,7 @@ where
//if let Some(io) = self.ioport.as_mut() { //if let Some(io) = self.ioport.as_mut() {
// Ok(io.read_u8(self.cycle.current_clock, addr)?) // Ok(io.read_u8(self.cycle.current_clock, addr)?)
//} else { //} else {
Ok(0) Ok(0)
//} //}
} }

View File

@ -1,11 +1,11 @@
mod debugger; mod debugger;
mod decode; mod decode;
mod emuhal;
mod execute; mod execute;
mod instructions; mod instructions;
mod moa;
mod state; mod state;
mod timing; mod timing;
mod moa;
mod emuhal;
pub use crate::state::{Z80, Z80Type, Z80Error, Z80State, Status, Flags}; pub use crate::state::{Z80, Z80Type, Z80Error, Z80State, Status, Flags};
pub use crate::decode::Z80Decoder; pub use crate::decode::Z80Decoder;

View File

@ -1,8 +1,8 @@
use std::any::Any;
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use emulator_hal::{BusAdapter, Instant as EmuInstant}; use emulator_hal::{BusAdapter, Instant as EmuInstant};
use moa_core::{System, Error, Address, Steppable, Addressable, Interruptable, Debuggable, Transmutable}; use moa_core::{System, Error, Address, Steppable, Addressable, Interruptable, Signalable, Signal, Debuggable, Transmutable};
use crate::{Z80, Z80Error, Z80Decoder}; use crate::{Z80, Z80Error, Z80Decoder};
use crate::instructions::Register; use crate::instructions::Register;
@ -22,13 +22,32 @@ where
} }
fn on_error(&mut self, system: &System) { fn on_error(&mut self, system: &System) {
self.dump_state(system.clock); let bus = &mut *system.bus.borrow_mut();
let mut adapter = BusAdapter::new(bus, |addr| addr as u64, |err| Z80Error::BusError(format!("{:?}", err)));
self.dump_state(system.clock, &mut adapter);
} }
} }
impl Interruptable for Z80<Instant> {} impl Interruptable for Z80<Instant> {}
impl Signalable for Z80<Instant> {
fn set_signal(&mut self, signal: Signal, flag: bool) -> Result<(), Error> {
match signal {
Signal::Reset => self.signals.reset = flag,
Signal::BusRequest => self.signals.bus_request = flag,
}
Ok(())
}
fn signal(&mut self, signal: Signal) -> Option<bool> {
match signal {
Signal::Reset => Some(self.signals.reset),
Signal::BusRequest => Some(self.signals.bus_request),
}
}
}
impl Transmutable for Z80<Instant> { impl Transmutable for Z80<Instant> {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self) Some(self)
@ -41,6 +60,11 @@ impl Transmutable for Z80<Instant> {
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> { fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
Some(self) Some(self)
} }
#[inline]
fn as_signalable(&mut self) -> Option<&mut dyn Signalable> {
Some(self)
}
} }
impl From<Z80Error> for Error { impl From<Z80Error> for Error {
@ -80,16 +104,16 @@ impl Debuggable for Z80<Instant> {
let mut adapter = BusAdapter::new(bus, |addr| addr as u64, |err| Z80Error::BusError(format!("{:?}", err))); let mut adapter = BusAdapter::new(bus, |addr| addr as u64, |err| Z80Error::BusError(format!("{:?}", err)));
let decoder = Z80Decoder::decode_at(&mut adapter, system.clock, self.state.pc)?; let decoder = Z80Decoder::decode_at(&mut adapter, system.clock, self.state.pc)?;
// TODO disabled until decoder is fixed self.previous_cycle.decoder.dump_decoded(&mut adapter);
//self.decoder.dump_decoded(&mut self.port); self.dump_state(system.clock, &mut adapter);
self.dump_state(system.clock);
Ok(()) Ok(())
} }
fn print_disassembly(&mut self, _system: &System, addr: Address, count: usize) { fn print_disassembly(&mut self, system: &System, addr: Address, count: usize) {
// TODO disabled until decoder is fixed let bus = &mut *system.bus.borrow_mut();
//let mut decoder = Z80Decoder::default(); let mut adapter = BusAdapter::new(bus, |addr| addr as u64, |err| Z80Error::BusError(format!("{:?}", err)));
//decoder.dump_disassembly(&mut self.port, addr as u16, count as u16);
Z80Decoder::dump_disassembly(&mut adapter, addr as u16, count as u16);
} }
fn run_command(&mut self, _system: &System, args: &[&str]) -> Result<bool, Error> { fn run_command(&mut self, _system: &System, args: &[&str]) -> Result<bool, Error> {
@ -102,5 +126,3 @@ impl Debuggable for Z80<Instant> {
Ok(false) Ok(false)
} }
} }

View File

@ -1,7 +1,7 @@
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use emulator_hal::Instant as EmuInstant; use emulator_hal::{Instant as EmuInstant, BusAccess};
use moa_core::{Address, Bus, BusPort}; use moa_core::{Address, Bus, BusPort};
use moa_signals::Signal; use moa_signals::Signal;
@ -92,6 +92,12 @@ impl Z80State {
} }
} }
#[derive(Clone, Debug, Default)]
pub struct Z80Signals {
pub reset: bool,
pub bus_request: bool,
}
#[derive(Clone, Debug, thiserror::Error)] #[derive(Clone, Debug, thiserror::Error)]
pub enum Z80Error /* <B: fmt::Display> */ { pub enum Z80Error /* <B: fmt::Display> */ {
#[error("cpu halted")] #[error("cpu halted")]
@ -120,8 +126,7 @@ pub struct Z80<Instant> {
pub state: Z80State, pub state: Z80State,
pub debugger: Z80Debugger, pub debugger: Z80Debugger,
pub previous_cycle: Z80Cycle<Instant>, pub previous_cycle: Z80Cycle<Instant>,
//pub port: BusPort, pub signals: Z80Signals,
//pub ioport: Option<BusPort>,
// TODO activate later // TODO activate later
//pub reset: Signal<bool>, //pub reset: Signal<bool>,
//pub bus_request: Signal<bool>, //pub bus_request: Signal<bool>,
@ -131,34 +136,22 @@ impl<Instant> Z80<Instant>
where where
Instant: EmuInstant, Instant: EmuInstant,
{ {
pub fn new(cputype: Z80Type, frequency: Frequency /*, port: BusPort, ioport: Option<BusPort>*/) -> Self { pub fn new(cputype: Z80Type, frequency: Frequency) -> Self {
Self { Self {
cputype, cputype,
frequency, frequency,
state: Z80State::default(), state: Z80State::default(),
debugger: Z80Debugger::default(), debugger: Z80Debugger::default(),
previous_cycle: Z80Cycle::at_time(Instant::START), previous_cycle: Z80Cycle::at_time(Instant::START),
//port, signals: Z80Signals::default(),
//ioport,
//reset: Signal::new(false), //reset: Signal::new(false),
//bus_request: Signal::new(false), //bus_request: Signal::new(false),
} }
} }
pub fn from_type( pub fn from_type(cputype: Z80Type, frequency: Frequency) -> Self {
cputype: Z80Type,
frequency: Frequency,
bus: Rc<RefCell<Bus>>,
addr_offset: Address,
io_bus: Option<(Rc<RefCell<Bus>>, Address)>,
) -> Self {
match cputype { match cputype {
Z80Type::Z80 => Self::new( Z80Type::Z80 => Self::new(cputype, frequency),
cputype,
frequency,
//BusPort::new(addr_offset, 16, 8, bus),
//io_bus.map(|(io_bus, io_offset)| BusPort::new(io_offset, 16, 8, io_bus)),
),
} }
} }
@ -168,7 +161,10 @@ where
self.debugger = Z80Debugger::default(); self.debugger = Z80Debugger::default();
} }
pub fn dump_state(&mut self, clock: Instant) { pub fn dump_state<Bus>(&mut self, clock: Instant, bus: &mut Bus)
where
Bus: BusAccess<Z80Address, Instant = Instant>,
{
println!("Status: {:?}", self.state.status); println!("Status: {:?}", self.state.status);
println!("PC: {:#06x}", self.state.pc); println!("PC: {:#06x}", self.state.pc);
println!("SP: {:#06x}", self.state.sp); println!("SP: {:#06x}", self.state.sp);
@ -207,12 +203,11 @@ where
println!("I: {:#04x} R: {:#04x}", self.state.i, self.state.r); println!("I: {:#04x} R: {:#04x}", self.state.i, self.state.r);
println!("IM: {:?} IFF1: {:?} IFF2: {:?}", self.state.im, self.state.iff1, self.state.iff2); println!("IM: {:?} IFF1: {:?} IFF2: {:?}", self.state.im, self.state.iff1, self.state.iff2);
// TODO disabled until function is reimplemented println!(
//println!( "Current Instruction: {} {:?}",
// "Current Instruction: {} {:?}", self.previous_cycle.decoder.format_instruction_bytes(bus),
// self.decoder.format_instruction_bytes(&mut self.port), self.previous_cycle.decoder.instruction
// self.decoder.instruction );
//);
println!("Previous Instruction: {:?}", self.previous_cycle.decoder.instruction); println!("Previous Instruction: {:?}", self.previous_cycle.decoder.instruction);
println!(); println!();
// TODO disabled until function is reimplemented // TODO disabled until function is reimplemented

View File

@ -8,7 +8,7 @@ fn main() {
Arg::new("ROM") Arg::new("ROM")
.short('r') .short('r')
.long("rom") .long("rom")
.action(ArgAction::SetTrue) .action(ArgAction::Set)
.value_name("FILE") .value_name("FILE")
.help("ROM file to load at the start of memory"), .help("ROM file to load at the start of memory"),
) )

View File

@ -1,23 +1,27 @@
use std::rc::Rc; use std::rc::Rc;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::any::Any;
use femtos::Instant; use femtos::Instant;
use moa_core::{Bus, Error, Address, Addressable, Transmutable}; use moa_core::{Bus, Device, Error, Address, Addressable, Signal, Transmutable};
use moa_signals::Signal; //use moa_signals::Signal;
use moa_z80::Z80;
const DEV_NAME: &str = "coprocessor"; const DEV_NAME: &str = "coprocessor";
pub struct CoprocessorCoordinator { pub struct CoprocessorCoordinator {
bus_request: Signal<bool>, z80: Device,
reset: Signal<bool>, //bus_request: Signal<bool>,
//reset: Signal<bool>,
} }
impl CoprocessorCoordinator { impl CoprocessorCoordinator {
pub fn new(reset: Signal<bool>, bus_request: Signal<bool>) -> Self { pub fn new(z80: Device) -> Self {
Self { Self {
bus_request, z80,
reset, //bus_request,
//reset,
} }
} }
} }
@ -30,7 +34,9 @@ impl Addressable for CoprocessorCoordinator {
fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> {
match addr { match addr {
0x100 => { 0x100 => {
data[0] = if self.bus_request.get() && self.reset.get() { let mut device = self.z80.borrow_mut();
let z80 = device.as_signalable().unwrap();
data[0] = if z80.signal(Signal::BusRequest).unwrap_or(false) && z80.signal(Signal::Reset).unwrap_or(false) {
0x01 0x01
} else { } else {
0x00 0x00
@ -49,10 +55,14 @@ impl Addressable for CoprocessorCoordinator {
match addr { match addr {
0x000 => { /* ROM vs DRAM mode */ }, 0x000 => { /* ROM vs DRAM mode */ },
0x100 => { 0x100 => {
self.bus_request.set(data[0] != 0); let mut device = self.z80.borrow_mut();
let z80 = device.as_signalable().unwrap();
z80.set_signal(Signal::BusRequest, data[0] == 0)?;
}, },
0x200 => { 0x200 => {
self.reset.set(data[0] == 0); let mut device = self.z80.borrow_mut();
let z80 = device.as_signalable().unwrap();
z80.set_signal(Signal::Reset, data[0] == 0)?;
}, },
_ => { _ => {
log::warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr); log::warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);

View File

@ -2,7 +2,7 @@ use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use femtos::Frequency; use femtos::{Instant, Frequency};
use moa_core::{System, Error, MemoryBlock, Bus, Address, Addressable, Device}; use moa_core::{System, Error, MemoryBlock, Bus, Address, Addressable, Device};
use moa_host::Host; use moa_host::Host;
@ -68,11 +68,13 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
coproc_bus.borrow_mut().insert(0x6000, coproc_register.clone()); coproc_bus.borrow_mut().insert(0x6000, coproc_register.clone());
coproc_bus.borrow_mut().insert(0x7f11, coproc_sn_sound.clone()); coproc_bus.borrow_mut().insert(0x7f11, coproc_sn_sound.clone());
coproc_bus.borrow_mut().insert(0x8000, coproc_area); coproc_bus.borrow_mut().insert(0x8000, coproc_area);
let coproc = Z80::from_type(Z80Type::Z80, Frequency::from_hz(3_579_545), coproc_bus, 0, None); let coproc = Z80::from_type(Z80Type::Z80, Frequency::from_hz(3_579_545));
let mut reset = coproc.reset.clone(); //let mut reset = coproc.reset.clone();
let mut bus_request = coproc.bus_request.clone(); //let mut bus_request = coproc.bus_request.clone();
reset.set(true); //reset.set(true);
bus_request.set(true); //bus_request.set(true);
let coproc = Device::new(coproc);
// Add coprocessor devices to the system bus so the 68000 can access them too // Add coprocessor devices to the system bus so the 68000 can access them too
system.add_addressable_device(0x00a00000, coproc_ram)?; system.add_addressable_device(0x00a00000, coproc_ram)?;
@ -80,14 +82,14 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
system.add_addressable_device(0x00a06000, coproc_register)?; system.add_addressable_device(0x00a06000, coproc_register)?;
//system.add_addressable_device(0x00c00010, coproc_sn_sound)?; //system.add_addressable_device(0x00c00010, coproc_sn_sound)?;
system.add_device("sn_sound", coproc_sn_sound.clone())?; system.add_device("sn_sound", coproc_sn_sound.clone())?;
system.add_device("coproc", Device::new(coproc))?; system.add_device("coproc", coproc.clone())?;
let controllers = GenesisControllers::new(host)?; let controllers = GenesisControllers::new(host)?;
let interrupt = controllers.get_interrupt_signal(); let interrupt = controllers.get_interrupt_signal();
system.add_addressable_device(0x00a10000, Device::new(controllers))?; system.add_addressable_device(0x00a10000, Device::new(controllers))?;
let coproc = CoprocessorCoordinator::new(reset, bus_request); let coproc = CoprocessorCoordinator::new(coproc);
system.add_addressable_device(0x00a11000, Device::new(coproc))?; system.add_addressable_device(0x00a11000, Device::new(coproc))?;
let vdp = Ym7101::new(host, interrupt, coproc_sn_sound)?; let vdp = Ym7101::new(host, interrupt, coproc_sn_sound)?;

View File

@ -44,7 +44,7 @@ pub fn build_trs80<H: Host>(host: &mut H, options: Trs80Options) -> Result<Syste
system.add_addressable_device(0x37E0 + 0x420, Device::new(video)).unwrap(); system.add_addressable_device(0x37E0 + 0x420, Device::new(video)).unwrap();
// TODO the ioport needs to be hooked up // TODO the ioport needs to be hooked up
let cpu = Z80::from_type(Z80Type::Z80, options.frequency, system.bus.clone(), 0, None); let cpu = Z80::from_type(Z80Type::Z80, options.frequency);
system.add_interruptable_device("cpu", Device::new(cpu))?; system.add_interruptable_device("cpu", Device::new(cpu))?;

View File

@ -1,4 +1,4 @@
Last run on 2024-03-31 at commit 6e7e315808228e03eaf8ad2e8152c087710f1d28 with flags --check-undocumented --check-timings Last run on 2024-04-07 at commit 1c5ad3999afa5591ec8fcbcadf4797514c390031 with flags --check-undocumented --check-timings
00.json completed, all passed! 00.json completed, all passed!
01.json completed, all passed! 01.json completed, all passed!
@ -614,7 +614,7 @@ dd 82.json completed, all passed!
dd 83.json completed, all passed! dd 83.json completed, all passed!
dd 84.json completed, all passed! dd 84.json completed, all passed!
dd 85.json completed, all passed! dd 85.json completed, all passed!
dd 86.json completed, all passed! dd 86.json completed: 0 passed, 1000 FAILED
dd 87.json completed, all passed! dd 87.json completed, all passed!
dd 88.json completed, all passed! dd 88.json completed, all passed!
dd 89.json completed, all passed! dd 89.json completed, all passed!
@ -622,7 +622,7 @@ dd 8a.json completed, all passed!
dd 8b.json completed, all passed! dd 8b.json completed, all passed!
dd 8c.json completed, all passed! dd 8c.json completed, all passed!
dd 8d.json completed, all passed! dd 8d.json completed, all passed!
dd 8e.json completed, all passed! dd 8e.json completed: 0 passed, 1000 FAILED
dd 8f.json completed, all passed! dd 8f.json completed, all passed!
dd 90.json completed, all passed! dd 90.json completed, all passed!
dd 91.json completed, all passed! dd 91.json completed, all passed!
@ -630,7 +630,7 @@ dd 92.json completed, all passed!
dd 93.json completed, all passed! dd 93.json completed, all passed!
dd 94.json completed, all passed! dd 94.json completed, all passed!
dd 95.json completed, all passed! dd 95.json completed, all passed!
dd 96.json completed, all passed! dd 96.json completed: 0 passed, 1000 FAILED
dd 97.json completed, all passed! dd 97.json completed, all passed!
dd 98.json completed, all passed! dd 98.json completed, all passed!
dd 99.json completed, all passed! dd 99.json completed, all passed!
@ -638,7 +638,7 @@ dd 9a.json completed, all passed!
dd 9b.json completed, all passed! dd 9b.json completed, all passed!
dd 9c.json completed, all passed! dd 9c.json completed, all passed!
dd 9d.json completed, all passed! dd 9d.json completed, all passed!
dd 9e.json completed, all passed! dd 9e.json completed: 0 passed, 1000 FAILED
dd 9f.json completed, all passed! dd 9f.json completed, all passed!
dd a0.json completed, all passed! dd a0.json completed, all passed!
dd a1.json completed, all passed! dd a1.json completed, all passed!
@ -646,7 +646,7 @@ dd a2.json completed, all passed!
dd a3.json completed, all passed! dd a3.json completed, all passed!
dd a4.json completed, all passed! dd a4.json completed, all passed!
dd a5.json completed, all passed! dd a5.json completed, all passed!
dd a6.json completed, all passed! dd a6.json completed: 0 passed, 1000 FAILED
dd a7.json completed, all passed! dd a7.json completed, all passed!
dd a8.json completed, all passed! dd a8.json completed, all passed!
dd a9.json completed, all passed! dd a9.json completed, all passed!
@ -654,7 +654,7 @@ dd aa.json completed, all passed!
dd ab.json completed, all passed! dd ab.json completed, all passed!
dd ac.json completed, all passed! dd ac.json completed, all passed!
dd ad.json completed, all passed! dd ad.json completed, all passed!
dd ae.json completed, all passed! dd ae.json completed: 0 passed, 1000 FAILED
dd af.json completed, all passed! dd af.json completed, all passed!
dd b0.json completed, all passed! dd b0.json completed, all passed!
dd b1.json completed, all passed! dd b1.json completed, all passed!
@ -662,7 +662,7 @@ dd b2.json completed, all passed!
dd b3.json completed, all passed! dd b3.json completed, all passed!
dd b4.json completed, all passed! dd b4.json completed, all passed!
dd b5.json completed, all passed! dd b5.json completed, all passed!
dd b6.json completed, all passed! dd b6.json completed: 0 passed, 1000 FAILED
dd b7.json completed, all passed! dd b7.json completed, all passed!
dd b8.json completed, all passed! dd b8.json completed, all passed!
dd b9.json completed, all passed! dd b9.json completed, all passed!
@ -670,7 +670,7 @@ dd ba.json completed, all passed!
dd bb.json completed, all passed! dd bb.json completed, all passed!
dd bc.json completed, all passed! dd bc.json completed, all passed!
dd bd.json completed, all passed! dd bd.json completed, all passed!
dd be.json completed, all passed! dd be.json completed: 0 passed, 1000 FAILED
dd bf.json completed, all passed! dd bf.json completed, all passed!
dd c0.json completed, all passed! dd c0.json completed, all passed!
dd c1.json completed, all passed! dd c1.json completed, all passed!
@ -1038,7 +1038,7 @@ ed 5f.json completed, all passed!
ed 60.json completed: 2 passed, 998 FAILED ed 60.json completed: 2 passed, 998 FAILED
ed 61.json completed, all passed! ed 61.json completed, all passed!
ed 62.json completed, all passed! ed 62.json completed, all passed!
ed 63.json completed, all passed! ed 63.json completed: 0 passed, 1000 FAILED
ed 64.json completed, all passed! ed 64.json completed, all passed!
ed 65.json completed, all passed! ed 65.json completed, all passed!
ed 66.json completed, all passed! ed 66.json completed, all passed!
@ -1046,7 +1046,7 @@ ed 67.json completed, all passed!
ed 68.json completed: 4 passed, 996 FAILED ed 68.json completed: 4 passed, 996 FAILED
ed 69.json completed, all passed! ed 69.json completed, all passed!
ed 6a.json completed, all passed! ed 6a.json completed, all passed!
ed 6b.json completed, all passed! ed 6b.json completed: 0 passed, 1000 FAILED
ed 6c.json completed, all passed! ed 6c.json completed, all passed!
ed 6d.json completed, all passed! ed 6d.json completed, all passed!
ed 6e.json completed, all passed! ed 6e.json completed, all passed!
@ -1058,7 +1058,7 @@ ed 73.json completed, all passed!
ed 74.json completed, all passed! ed 74.json completed, all passed!
ed 75.json completed, all passed! ed 75.json completed, all passed!
ed 76.json completed, all passed! ed 76.json completed, all passed!
ed 77.json completed, all passed! ed 77.json completed: 0 passed, 1000 FAILED
ed 78.json completed: 7 passed, 993 FAILED ed 78.json completed: 7 passed, 993 FAILED
ed 79.json completed, all passed! ed 79.json completed, all passed!
ed 7a.json completed, all passed! ed 7a.json completed, all passed!
@ -1066,7 +1066,7 @@ ed 7b.json completed, all passed!
ed 7c.json completed, all passed! ed 7c.json completed, all passed!
ed 7d.json completed, all passed! ed 7d.json completed, all passed!
ed 7e.json completed, all passed! ed 7e.json completed, all passed!
ed 7f.json completed, all passed! ed 7f.json completed: 0 passed, 1000 FAILED
ed a0.json completed, all passed! ed a0.json completed, all passed!
ed a1.json completed: 0 passed, 1000 FAILED ed a1.json completed: 0 passed, 1000 FAILED
ed a2.json completed: 0 passed, 1000 FAILED ed a2.json completed: 0 passed, 1000 FAILED
@ -1234,7 +1234,7 @@ fd 82.json completed, all passed!
fd 83.json completed, all passed! fd 83.json completed, all passed!
fd 84.json completed, all passed! fd 84.json completed, all passed!
fd 85.json completed, all passed! fd 85.json completed, all passed!
fd 86.json completed, all passed! fd 86.json completed: 0 passed, 1000 FAILED
fd 87.json completed, all passed! fd 87.json completed, all passed!
fd 88.json completed, all passed! fd 88.json completed, all passed!
fd 89.json completed, all passed! fd 89.json completed, all passed!
@ -1242,7 +1242,7 @@ fd 8a.json completed, all passed!
fd 8b.json completed, all passed! fd 8b.json completed, all passed!
fd 8c.json completed, all passed! fd 8c.json completed, all passed!
fd 8d.json completed, all passed! fd 8d.json completed, all passed!
fd 8e.json completed, all passed! fd 8e.json completed: 0 passed, 1000 FAILED
fd 8f.json completed, all passed! fd 8f.json completed, all passed!
fd 90.json completed, all passed! fd 90.json completed, all passed!
fd 91.json completed, all passed! fd 91.json completed, all passed!
@ -1250,7 +1250,7 @@ fd 92.json completed, all passed!
fd 93.json completed, all passed! fd 93.json completed, all passed!
fd 94.json completed, all passed! fd 94.json completed, all passed!
fd 95.json completed, all passed! fd 95.json completed, all passed!
fd 96.json completed, all passed! fd 96.json completed: 0 passed, 1000 FAILED
fd 97.json completed, all passed! fd 97.json completed, all passed!
fd 98.json completed, all passed! fd 98.json completed, all passed!
fd 99.json completed, all passed! fd 99.json completed, all passed!
@ -1258,7 +1258,7 @@ fd 9a.json completed, all passed!
fd 9b.json completed, all passed! fd 9b.json completed, all passed!
fd 9c.json completed, all passed! fd 9c.json completed, all passed!
fd 9d.json completed, all passed! fd 9d.json completed, all passed!
fd 9e.json completed, all passed! fd 9e.json completed: 0 passed, 1000 FAILED
fd 9f.json completed, all passed! fd 9f.json completed, all passed!
fd a0.json completed, all passed! fd a0.json completed, all passed!
fd a1.json completed, all passed! fd a1.json completed, all passed!
@ -1266,7 +1266,7 @@ fd a2.json completed, all passed!
fd a3.json completed, all passed! fd a3.json completed, all passed!
fd a4.json completed, all passed! fd a4.json completed, all passed!
fd a5.json completed, all passed! fd a5.json completed, all passed!
fd a6.json completed, all passed! fd a6.json completed: 0 passed, 1000 FAILED
fd a7.json completed, all passed! fd a7.json completed, all passed!
fd a8.json completed, all passed! fd a8.json completed, all passed!
fd a9.json completed, all passed! fd a9.json completed, all passed!
@ -1274,7 +1274,7 @@ fd aa.json completed, all passed!
fd ab.json completed, all passed! fd ab.json completed, all passed!
fd ac.json completed, all passed! fd ac.json completed, all passed!
fd ad.json completed, all passed! fd ad.json completed, all passed!
fd ae.json completed, all passed! fd ae.json completed: 0 passed, 1000 FAILED
fd af.json completed, all passed! fd af.json completed, all passed!
fd b0.json completed, all passed! fd b0.json completed, all passed!
fd b1.json completed, all passed! fd b1.json completed, all passed!
@ -1282,7 +1282,7 @@ fd b2.json completed, all passed!
fd b3.json completed, all passed! fd b3.json completed, all passed!
fd b4.json completed, all passed! fd b4.json completed, all passed!
fd b5.json completed, all passed! fd b5.json completed, all passed!
fd b6.json completed, all passed! fd b6.json completed: 0 passed, 1000 FAILED
fd b7.json completed, all passed! fd b7.json completed, all passed!
fd b8.json completed, all passed! fd b8.json completed, all passed!
fd b9.json completed, all passed! fd b9.json completed, all passed!
@ -1290,7 +1290,7 @@ fd ba.json completed, all passed!
fd bb.json completed, all passed! fd bb.json completed, all passed!
fd bc.json completed, all passed! fd bc.json completed, all passed!
fd bd.json completed, all passed! fd bd.json completed, all passed!
fd be.json completed, all passed! fd be.json completed: 0 passed, 1000 FAILED
fd bf.json completed, all passed! fd bf.json completed, all passed!
fd c0.json completed, all passed! fd c0.json completed, all passed!
fd c1.json completed, all passed! fd c1.json completed, all passed!
@ -1611,5 +1611,5 @@ fd ff.json completed, all passed!
fe.json completed, all passed! fe.json completed, all passed!
ff.json completed, all passed! ff.json completed, all passed!
passed: 1584670, failed: 25330, total 98% passed: 1564670, failed: 45330, total 97%
completed in 0m 8s completed in 0m 9s

View File

@ -46,6 +46,9 @@ struct Args {
/// Check instruction timings /// Check instruction timings
#[clap(short = 't', long)] #[clap(short = 't', long)]
check_timings: bool, check_timings: bool,
/// Don't check I/O instructions
#[clap(short = 'i', long)]
no_check_io: bool,
/// Directory to the test suite to run /// Directory to the test suite to run
#[clap(long, default_value = DEFAULT_RAD_TESTS)] #[clap(long, default_value = DEFAULT_RAD_TESTS)]
testsuite: String, testsuite: String,
@ -148,7 +151,11 @@ impl TestCase {
} }
fn init_execute_test(cputype: Z80Type, state: &TestState, ports: &[TestPort]) -> Result<(Z80<Instant>, MemoryBlock<Instant>, MemoryBlock<Instant>), Error> { fn init_execute_test(
cputype: Z80Type,
state: &TestState,
ports: &[TestPort],
) -> Result<(Z80<Instant>, MemoryBlock<Instant>, MemoryBlock<Instant>), Error> {
// Insert basic initialization // Insert basic initialization
let len = 0x1_0000; let len = 0x1_0000;
let mut data = Vec::with_capacity(len); let mut data = Vec::with_capacity(len);
@ -220,7 +227,8 @@ fn load_state(
// Load data bytes into memory // Load data bytes into memory
for (addr, byte) in initial.ram.iter() { for (addr, byte) in initial.ram.iter() {
memory.write_u8(Instant::START, *addr, *byte) memory
.write_u8(Instant::START, *addr, *byte)
.map_err(|err| Error::Bus(format!("{:?}", err)))?; .map_err(|err| Error::Bus(format!("{:?}", err)))?;
} }
@ -279,17 +287,19 @@ fn assert_state(
assert_value(cpu.state.iff1 as u8, expected.iff1, "iff1")?; assert_value(cpu.state.iff1 as u8, expected.iff1, "iff1")?;
assert_value(cpu.state.iff2 as u8, expected.iff2, "iff2")?; assert_value(cpu.state.iff2 as u8, expected.iff2, "iff2")?;
// Load data bytes into memory // Compare data bytes in memory
for (addr, byte) in expected.ram.iter() { for (addr, byte) in expected.ram.iter() {
let actual = memory.read_u8(Instant::START, *addr) let actual = memory
.read_u8(Instant::START, *addr)
.map_err(|err| Error::Bus(format!("{:?}", err)))?; .map_err(|err| Error::Bus(format!("{:?}", err)))?;
assert_value(actual, *byte, &format!("ram at {:x}", addr))?; assert_value(actual, *byte, &format!("ram at {:x}", addr))?;
} }
// Load data bytes into io space // Compare data bytes in io space
for port in ports.iter() { for port in ports.iter() {
if port.atype == "w" { if port.atype == "w" {
let actual = io.read_u8(Instant::START, port.addr) let actual = io
.read_u8(Instant::START, port.addr)
.map_err(|err| Error::Bus(format!("{:?}", err)))?; .map_err(|err| Error::Bus(format!("{:?}", err)))?;
assert_value(actual, port.value, &format!("port value at {:x}", port.addr))?; assert_value(actual, port.value, &format!("port value at {:x}", port.addr))?;
} }
@ -306,20 +316,20 @@ fn step_cpu_and_assert(
args: &Args, args: &Args,
) -> Result<(), Error> { ) -> Result<(), Error> {
//let clock_elapsed = cpu.step((memory, io))?; //let clock_elapsed = cpu.step((memory, io))?;
let clock_elapsed = cpu.step(Instant::START, memory) let clock_elapsed = cpu
.step(Instant::START, memory)
.map_err(|err| Error::Step(format!("{:?}", err)))?; .map_err(|err| Error::Step(format!("{:?}", err)))?;
assert_state(cpu, memory, io, &case.final_state, args.check_extra_flags, &case.ports)?; assert_state(cpu, memory, io, &case.final_state, args.check_extra_flags, &case.ports)?;
if args.check_timings { if args.check_timings {
// TODO re-enable. not sure why it can't divide here let cycles = clock_elapsed.as_duration() / cpu.frequency.period_duration();
//let cycles = clock_elapsed / cpu.frequency.period_duration(); if cycles != case.cycles.len() as u64 {
//if cycles != case.cycles.len() { return Err(Error::Assertion(format!(
// return Err(Error::Assertion(format!( "expected instruction to take {} cycles, but took {}",
// "expected instruction to take {} cycles, but took {}", case.cycles.len(),
// case.cycles.len(), cycles
// cycles )));
// ))); }
//}
} }
Ok(()) Ok(())
@ -338,8 +348,8 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
if args.debug { if args.debug {
case.dump(); case.dump();
println!(); println!();
initial_cpu.dump_state(Instant::START); initial_cpu.dump_state(Instant::START, &mut memory);
cpu.dump_state(Instant::START); cpu.dump_state(Instant::START, &mut memory);
} }
println!("FAILED: {:?}", err); println!("FAILED: {:?}", err);
} }
@ -371,6 +381,10 @@ fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) {
} }
} }
if args.no_check_io && !case.ports.is_empty() {
continue;
}
// Sort the ram memory for debugging help // Sort the ram memory for debugging help
if args.debug { if args.debug {
case.initial_state.ram.sort_by_key(|(addr, _)| *addr); case.initial_state.ram.sort_by_key(|(addr, _)| *addr);

View File

@ -1,7 +1,7 @@
* fix the Z80 dumping functions
* fix the Z80 reset and bus_request signals * fix the Z80 reset and bus_request signals
* the emulator_hal_memory should throw an error when an access will straddle the end of memory? Or should it autowrap? * the emulator_hal_memory should throw an error when an access will straddle the end of memory? Or should it autowrap?
* fix the m68k dumping functions
* convert computie system to use the new moa-system library crate to replace the old core crate * convert computie system to use the new moa-system library crate to replace the old core crate
* change package names to drop the 's', so moa-systems-computie becomes moa-system-computie * change package names to drop the 's', so moa-systems-computie becomes moa-system-computie