Separated moa-core dependency into an optional feature flag

This commit is contained in:
transistor 2024-03-13 21:49:04 -07:00
parent af1c660dc0
commit 545f339fe2
34 changed files with 622 additions and 512 deletions

2
Cargo.lock generated
View File

@ -774,6 +774,8 @@ dependencies = [
"log", "log",
"moa-common", "moa-common",
"moa-core", "moa-core",
"moa-debugger",
"moa-host",
"moa-m68k", "moa-m68k",
"moa-peripherals-generic", "moa-peripherals-generic",
"moa-peripherals-motorola", "moa-peripherals-motorola",

View File

@ -1,4 +1,5 @@
[workspace] [workspace]
resolver = "2"
members = [ members = [
"emulator/core", "emulator/core",
"emulator/frontends/common", "emulator/frontends/common",
@ -18,5 +19,6 @@ opt-level = 3
[profile.release] [profile.release]
debug = true debug = true
# TODO there are many overflow errors, which could be bugs
#overflow-checks = true #overflow-checks = true

View File

@ -479,3 +479,8 @@ General Work
- So far it's going quite well. I really like the pattern of making the cycle be like a transaction, - So far it's going quite well. I really like the pattern of making the cycle be like a transaction,
and making it possible to decompose it, especially for testing. I still need to fix the tests and making it possible to decompose it, especially for testing. I still need to fix the tests
- next step is to push System up from the interrupt handling code - next step is to push System up from the interrupt handling code
2024-03-10
- the emulator-hal conversion is going well. I'm thinking it makes more sense for the Address of
BusAccess to be a generic instead of an associated type, but I'll need to finish converting
everything to get a better sense of it. There's a lot of cleanup to do

View File

@ -3,6 +3,8 @@ use std::fmt;
use std::error::{Error as StdError}; use std::error::{Error as StdError};
use moa_host::HostError; use moa_host::HostError;
use emulator_hal::bus;
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EmulatorErrorKind { pub enum EmulatorErrorKind {
Misc, Misc,

View File

@ -26,11 +26,11 @@ impl InterruptController {
Ok(()) Ok(())
} }
pub fn check(&mut self) -> (bool, u8) { pub fn check(&mut self) -> (bool, u8, u8) {
if self.highest > 0 { if self.highest > 0 {
(true, self.highest) (true, self.highest, self.interrupts[self.highest as usize].1)
} else { } else {
(false, 0) (false, 0, 0)
} }
} }

View File

@ -11,7 +11,7 @@ pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debugga
pub use crate::devices::{read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable}; pub use crate::devices::{read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable};
pub use crate::error::Error; pub use crate::error::Error;
pub use crate::interrupts::InterruptController; pub use crate::interrupts::InterruptController;
pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice}; 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::bus::{BusAccess};

View File

@ -358,20 +358,46 @@ pub fn dump_slice(data: &[u8], mut count: usize) {
} }
} }
pub fn dump_memory<Bus, Address, Instant>(bus: &mut Bus, clock: Instant, addr: Address, count: Address)
where
Bus: BusAccess<Address, Instant>,
Address: From<u64> + Into<u64> + Copy,
Instant: Copy,
{
let mut addr = addr.into();
let mut count = count.into();
while count > 0 {
let mut line = format!("{:#010x}: ", addr);
let to = if count < 16 { count / 2 } else { 8 };
for _ in 0..to {
let word = bus.read_beu16(clock, Address::from(addr));
if word.is_err() {
println!("{}", line);
return;
}
write!(line, "{:#06x} ", word.unwrap()).unwrap();
addr += 2;
count -= 2;
}
println!("{}", line);
}
}
use emulator_hal::bus::{self, BusAccess}; use emulator_hal::bus::{self, BusAccess};
impl bus::Error for Error {} impl bus::Error for Error {}
impl BusAccess<u64, Instant> for BusPort { impl BusAccess<u64, Instant> for &mut dyn Addressable {
type Error = Error; type Error = Error;
fn read(&mut self, now: Instant, addr: Address, data: &mut [u8]) -> Result<usize, Self::Error> { fn read(&mut self, now: Instant, addr: Address, data: &mut [u8]) -> Result<usize, Self::Error> {
<Self as Addressable>::read(self, now, addr, data)?; (*self).read(now, addr, data)?;
Ok(data.len()) Ok(data.len())
} }
fn write(&mut self, now: Instant, addr: Address, data: &[u8]) -> Result<usize, Self::Error> { fn write(&mut self, now: Instant, addr: Address, data: &[u8]) -> Result<usize, Self::Error> {
<Self as Addressable>::write(self, now, addr, data)?; (*self).write(now, addr, data)?;
Ok(data.len()) Ok(data.len())
} }
} }

View File

@ -7,6 +7,10 @@ edition = "2021"
log = "0.4" log = "0.4"
thiserror = "1.0" thiserror = "1.0"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" }
moa-parsing = { path = "../../libraries/parsing" } moa-parsing = { path = "../../libraries/parsing" }
emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" }
moa-core = { path = "../../core", optional = true }
[features]
moa = []

View File

@ -1,12 +1,26 @@
use std::collections::HashMap; use std::collections::HashMap;
use moa_core::Error; use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser, ParserError};
use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser};
use super::state::M68kType; use super::state::M68kType;
use super::instructions::Size; use super::instructions::Size;
#[derive(Clone, Debug)]
pub struct Error(String);
impl Error {
pub fn new(msg: String) -> Self {
Self(msg)
}
}
impl From<ParserError> for Error {
fn from(err: ParserError) -> Self {
Self(err.0)
}
}
#[repr(usize)] #[repr(usize)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -114,7 +128,7 @@ impl M68kAssembler {
fn parse(&mut self, text: &str) -> Result<Vec<(usize, AssemblyLine)>, Error> { fn parse(&mut self, text: &str) -> Result<Vec<(usize, AssemblyLine)>, Error> {
let mut parser = AssemblyParser::new(text); let mut parser = AssemblyParser::new(text);
parser.parse() Ok(parser.parse()?)
} }
fn apply_relocations(&mut self) -> Result<(), Error> { fn apply_relocations(&mut self) -> Result<(), Error> {

View File

@ -2,9 +2,7 @@
use femtos::Instant; use femtos::Instant;
use emulator_hal::bus::{self, BusAccess}; use emulator_hal::bus::{self, BusAccess};
use moa_core::{System, Error, Address, Addressable, Debuggable}; use super::state::{M68k, M68kError};
use super::state::M68k;
use super::decode::M68kDecoder; use super::decode::M68kDecoder;
use super::execute::M68kCycleExecutor; use super::execute::M68kCycleExecutor;
use super::memory::M68kAddress; use super::memory::M68kAddress;
@ -33,53 +31,11 @@ pub struct M68kDebugger {
pub(crate) stack_tracer: StackTracer, pub(crate) stack_tracer: StackTracer,
} }
impl Debuggable for M68k { impl<'a, Bus, BusError> M68kCycleExecutor<'a, Bus>
fn add_breakpoint(&mut self, addr: Address) {
self.debugger.breakpoints.push(addr as u32);
}
fn remove_breakpoint(&mut self, addr: Address) {
if let Some(index) = self.debugger.breakpoints.iter().position(|a| *a == addr as u32) {
self.debugger.breakpoints.remove(index);
}
}
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
// TODO this is called by the debugger, but should be called some other way
//let _ = self.decoder.decode_at(&mut self.port, true, self.state.pc);
//self.decoder.dump_decoded(&mut self.port);
//self.dump_state();
Ok(())
}
fn print_disassembly(&mut self, addr: Address, count: usize) {
let mut decoder = M68kDecoder::new(self.info.chip, true, 0);
// TODO temporarily disabled
//decoder.dump_disassembly(&mut self.port, addr as u32, count as u32);
}
fn run_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}", BusAccess::read_beu32(&mut self.port, system.clock, *addr as Address)?);
}
},
"so" | "stepout" => {
self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1);
},
_ => { return Ok(true); },
}
Ok(false)
}
}
impl<'a, Bus> M68kCycleExecutor<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
pub fn check_breakpoints(&mut self) -> Result<(), Error> { pub fn check_breakpoints(&mut self) -> Result<(), M68kError<BusError>> {
for breakpoint in &self.debugger.breakpoints { for breakpoint in &self.debugger.breakpoints {
if *breakpoint == self.state.pc { if *breakpoint == self.state.pc {
if self.debugger.skip_breakpoint > 0 { if self.debugger.skip_breakpoint > 0 {
@ -87,7 +43,7 @@ where
return Ok(()); return Ok(());
} else { } else {
self.debugger.skip_breakpoint = 1; self.debugger.skip_breakpoint = 1;
return Err(Error::breakpoint(format!("breakpoint reached: {:08x}", *breakpoint))); return Err(M68kError::Breakpoint);
} }
} }
} }

View File

@ -1,8 +1,6 @@
use femtos::Instant; use femtos::Instant;
use emulator_hal::bus::{self, BusAccess, Error as BusError}; use emulator_hal::bus::BusAccess;
use moa_core::{Error, Address, Addressable};
use crate::state::{M68kType, M68kError, Exceptions}; use crate::state::{M68kType, M68kError, Exceptions};
use crate::memory::{M68kBusPort, M68kAddress}; use crate::memory::{M68kBusPort, M68kAddress};
@ -54,9 +52,9 @@ pub struct InstructionDecoding<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
port: &'a mut Bus, pub(crate) port: &'a mut Bus,
memory: &'a mut M68kBusPort, pub(crate) memory: &'a mut M68kBusPort,
decoder: &'a mut M68kDecoder, pub(crate) decoder: &'a mut M68kDecoder,
} }
impl M68kDecoder { impl M68kDecoder {
@ -109,7 +107,7 @@ impl M68kDecoder {
println!("{:?}", err); println!("{:?}", err);
match err { match err {
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => { M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => {
println!(" at {:08x}: {:04x}", self.start, port.read_beu16(memory.current_clock, self.start as Address).unwrap()); println!(" at {:08x}: {:04x}", self.start, port.read_beu16(memory.current_clock, self.start).unwrap());
}, },
_ => { }, _ => { },
} }
@ -125,7 +123,7 @@ impl M68kDecoder {
{ {
let ins_data: Result<String, M68kError<Bus::Error>> = let ins_data: Result<String, M68kError<Bus::Error>> =
(0..((self.end - self.start) / 2)).map(|offset| (0..((self.end - self.start) / 2)).map(|offset|
Ok(format!("{:04x} ", port.read_beu16(clock, (self.start + (offset * 2)) as Address).unwrap())) Ok(format!("{:04x} ", port.read_beu16(clock, self.start + (offset * 2)).unwrap()))
).collect(); ).collect();
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
} }

View File

@ -1,10 +1,8 @@
use femtos::{Instant, Duration}; use femtos::Instant;
use emulator_hal::bus::{self, BusAccess, BusAdapter}; use emulator_hal::bus::BusAccess;
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable, BusPort}; use crate::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority};
use crate::state::{M68k, M68kType, M68kError, M68kState, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress};
use crate::decode::M68kDecoder; use crate::decode::M68kDecoder;
use crate::debugger::M68kDebugger; use crate::debugger::M68kDebugger;
@ -37,7 +35,6 @@ pub enum Used {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct M68kCycle { pub struct M68kCycle {
pub decoder: M68kDecoder, pub decoder: M68kDecoder,
pub timing: M68kInstructionTiming, pub timing: M68kInstructionTiming,
pub memory: M68kBusPort, pub memory: M68kBusPort,
@ -50,7 +47,7 @@ impl M68kCycle {
Self { Self {
decoder: M68kDecoder::new(cputype, true, 0), decoder: M68kDecoder::new(cputype, true, 0),
timing: M68kInstructionTiming::new(cputype, data_width), timing: M68kInstructionTiming::new(cputype, data_width),
memory: M68kBusPort::new(Instant::START), memory: M68kBusPort::default(),
current_clock: Instant::START, current_clock: Instant::START,
} }
} }
@ -61,13 +58,16 @@ impl M68kCycle {
Self { Self {
decoder: M68kDecoder::new(cpu.info.chip, is_supervisor, cpu.state.pc), decoder: M68kDecoder::new(cpu.info.chip, is_supervisor, cpu.state.pc),
timing: M68kInstructionTiming::new(cpu.info.chip, cpu.info.data_width as u8), timing: M68kInstructionTiming::new(cpu.info.chip, cpu.info.data_width as u8),
memory: M68kBusPort::new(clock), memory: M68kBusPort::from_info(&cpu.info, clock),
current_clock: clock, current_clock: clock,
} }
} }
#[inline] #[inline]
pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a, bus::BusAdapter<M68kAddress, u64, Instant, &'a mut BusPort, Error>> { pub fn begin<'a, Bus>(mut self, cpu: &'a mut M68k, bus: Bus) -> M68kCycleExecutor<'a, Bus>
where
Bus: BusAccess<M68kAddress, Instant>,
{
cpu.stats.cycle_number += 1; cpu.stats.cycle_number += 1;
if cpu.stats.cycle_number > cpu.stats.last_update { if cpu.stats.cycle_number > cpu.stats.last_update {
cpu.stats.last_update = cpu.stats.last_update + 1_000_000; cpu.stats.last_update = cpu.stats.last_update + 1_000_000;
@ -76,25 +76,15 @@ impl M68kCycle {
cpu.stats.last_time = now; cpu.stats.last_time = now;
} }
let adapter = bus::BusAdapter::new(
&mut cpu.port,
translate_address,
|err| err,
);
M68kCycleExecutor { M68kCycleExecutor {
state: &mut cpu.state, state: &mut cpu.state,
port: adapter, port: bus,
debugger: &mut cpu.debugger, debugger: &mut cpu.debugger,
cycle: self, cycle: self,
} }
} }
} }
fn translate_address(addr_in: M68kAddress) -> u64 {
addr_in as u64
}
pub struct M68kCycleExecutor<'a, Bus> pub struct M68kCycleExecutor<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
@ -109,117 +99,23 @@ impl<'a, Bus> M68kCycleExecutor<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
#[inline]
pub fn dump_state(&mut self) {
println!("Status: {:?}", self.state.status);
println!("PC: {:#010x}", self.state.pc);
println!("SR: {:#06x}", self.state.sr);
for i in 0..7 {
println!("D{}: {:#010x} A{}: {:#010x}", i, self.state.d_reg[i as usize], i, self.state.a_reg[i as usize]);
}
println!("D7: {:#010x} USP: {:#010x}", self.state.d_reg[7], self.state.usp);
println!(" SSP: {:#010x}", self.state.ssp);
println!("Current Instruction: {:#010x} {:?}", self.cycle.decoder.start, self.cycle.decoder.instruction);
println!();
self.cycle.memory.dump_memory(&mut self.port, self.state.ssp, 0x40);
println!();
}
pub fn end(self) -> M68kCycle { pub fn end(self) -> M68kCycle {
self.cycle self.cycle
} }
} }
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<Duration, Error> {
let cycle = M68kCycle::new(self, system.clock);
let mut executor = cycle.begin(self);
let clocks = executor.step(system)?;
self.cycle = Some(executor.end());
Ok(self.info.frequency.period_duration() * clocks as u64)
}
fn on_error(&mut self, _system: &System) {
// TODO the cycle data in dropped by this point
//self.dump_state();
}
}
impl Interruptable for M68k { }
impl Transmutable for M68k {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
Some(self)
}
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
Some(self)
}
}
impl<BusError: bus::Error> From<M68kError<BusError>> for Error {
fn from(err: M68kError<BusError>) -> Self {
match err {
M68kError::Halted => Self::Other("cpu halted".to_string()),
M68kError::Exception(ex) => Self::Processor(ex as u32),
M68kError::Interrupt(num) => Self::Processor(num as u32),
M68kError::Breakpoint => Self::Breakpoint("breakpoint".to_string()),
M68kError::InvalidTarget(target) => Self::new(target.to_string()),
M68kError::BusError(msg) => Self::Other(format!("{:?}", msg)),
M68kError::Other(msg) => Self::Other(msg),
}
}
}
impl<BusError> From<Error> for M68kError<BusError> {
fn from(err: Error) -> Self {
match err {
Error::Processor(ex) => M68kError::Interrupt(ex as u8),
Error::Breakpoint(msg) => M68kError::Breakpoint,
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(format!("{}", msg)),
}
}
}
impl<'a, Bus> M68kCycleExecutor<'a, Bus> impl<'a, Bus> M68kCycleExecutor<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
#[inline] #[inline]
pub fn step(&mut self, system: &System) -> Result<ClockCycles, M68kError<Bus::Error>> { pub fn step(&mut self) -> Result<(), M68kError<Bus::Error>> {
let result = self.step_one(system);
self.process_error(result, 4)
}
#[inline]
pub fn process_error<T>(&mut self, result: Result<T, M68kError<Bus::Error>>, ok: T) -> Result<T, M68kError<Bus::Error>> {
match result {
Ok(value) => Ok(value),
Err(M68kError::Exception(ex)) => {
self.exception(ex as u8, false)?;
Ok(ok)
},
Err(M68kError::Interrupt(ex)) => {
self.exception(ex as u8, false)?;
Ok(ok)
},
Err(err) => Err(err),
}
}
#[inline]
pub fn step_one(&mut self, system: &System) -> Result<ClockCycles, M68kError<Bus::Error>> {
match self.state.status { match self.state.status {
Status::Init => self.reset_cpu(), Status::Init => self.reset_cpu(),
Status::Stopped => Err(M68kError::Halted), Status::Stopped => Err(M68kError::Halted),
Status::Running => self.cycle_one(system), Status::Running => self.cycle_one(),
}?; }?;
Ok(self.cycle.timing.calculate_clocks()) Ok(())
} }
#[inline] #[inline]
@ -232,15 +128,18 @@ where
} }
#[inline] #[inline]
pub fn cycle_one(&mut self, system: &System) -> Result<(), M68kError<Bus::Error>> { pub fn cycle_one(&mut self) -> Result<(), M68kError<Bus::Error>> {
self.check_breakpoints()?; self.check_breakpoints()?;
self.decode_and_execute()?; let result = self.decode_and_execute();
self.process_error(result)?;
self.check_pending_interrupts(system)?; // TODO this is called by the step function directly, but should be integrated better
//self.check_pending_interrupts(system)?;
Ok(()) Ok(())
} }
/*
#[inline] #[inline]
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError<Bus::Error>> { pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError<Bus::Error>> {
// TODO this could move somewhere else // TODO this could move somewhere else
@ -270,11 +169,15 @@ where
Ok(()) Ok(())
} }
*/
/*
#[inline] #[inline]
pub fn check_pending_interrupts2(&mut self, interrupt: Option<(InterruptPriority, u8)>) -> Result<InterruptAcknowledge, M68kError> { pub fn check_pending_interrupts(&mut self, interrupt: (bool, u8, u8)) -> Result<(InterruptPriority, Option<u8>), M68kError<Bus::Error>> {
self.state.pending_ipl = interrupt.unwrap_or(InterruptPriority::NoInterrupt); let ack_num;
(self.state.pending_ipl, ack_num) = match interrupt {
(true, priority, ack) => (InterruptPriority::from_u8(priority), ack),
(false, _, ack) => (InterruptPriority::NoInterrupt, ack),
};
let current_ipl = self.state.current_ipl as u8; let current_ipl = self.state.current_ipl as u8;
let pending_ipl = self.state.pending_ipl as u8; let pending_ipl = self.state.pending_ipl as u8;
@ -283,12 +186,12 @@ where
let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8; let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8;
if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl { if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl {
log::debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos()); //log::debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos());
self.state.current_ipl = self.state.pending_ipl; self.state.current_ipl = self.state.pending_ipl;
let acknowledge = self.state.current_ipl; //let acknowledge = self.state.current_ipl;
let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?; //let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?;
self.exception(ack_num, true)?; self.exception(ack_num, true)?;
return Ok(()); return Ok((self.state.current_ipl, Some(ack_num)));
} }
} }
@ -296,9 +199,8 @@ where
self.state.current_ipl = self.state.pending_ipl; self.state.current_ipl = self.state.pending_ipl;
} }
Ok(()) Ok((self.state.current_ipl, None))
} }
*/
pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError<Bus::Error>> { pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError<Bus::Error>> {
log::debug!("{}: raising exception {}", DEV_NAME, number); log::debug!("{}: raising exception {}", DEV_NAME, number);
@ -339,7 +241,7 @@ where
self.push_word((ins_word & 0xFFF0) | extra_code)?; self.push_word((ins_word & 0xFFF0) | extra_code)?;
let vector = self.state.vbr + offset as u32; let vector = self.state.vbr + offset as u32;
let addr = self.get_address_sized(vector as Address, Size::Long)?; let addr = self.get_address_sized(vector, Size::Long)?;
self.set_pc(addr)?; self.set_pc(addr)?;
Ok(()) Ok(())
@ -364,12 +266,28 @@ where
self.push_word(sr)?; self.push_word(sr)?;
let vector = self.state.vbr + offset as u32; let vector = self.state.vbr + offset as u32;
let addr = self.get_address_sized(vector as Address, Size::Long)?; let addr = self.get_address_sized(vector, Size::Long)?;
self.set_pc(addr)?; self.set_pc(addr)?;
Ok(()) Ok(())
} }
#[inline]
pub fn process_error(&mut self, result: Result<(), M68kError<Bus::Error>>) -> Result<(), M68kError<Bus::Error>> {
match result {
Ok(value) => Ok(value),
Err(M68kError::Exception(ex)) => {
self.exception(ex as u8, false)?;
Ok(())
},
Err(M68kError::Interrupt(ex)) => {
self.exception(ex as u8, false)?;
Ok(())
},
Err(err) => Err(err),
}
}
#[inline] #[inline]
pub fn decode_and_execute(&mut self) -> Result<(), M68kError<Bus::Error>> { pub fn decode_and_execute(&mut self) -> Result<(), M68kError<Bus::Error>> {
self.decode_next()?; self.decode_next()?;
@ -967,7 +885,7 @@ where
*self.get_stack_pointer_mut() -= 4; *self.get_stack_pointer_mut() -= 4;
let sp = *self.get_stack_pointer_mut(); let sp = *self.get_stack_pointer_mut();
let value = *self.get_a_reg_mut(reg); let value = *self.get_a_reg_mut(reg);
self.set_address_sized(sp as Address, value, Size::Long)?; self.set_address_sized(sp, value, Size::Long)?;
*self.get_a_reg_mut(reg) = sp; *self.get_a_reg_mut(reg) = sp;
*self.get_stack_pointer_mut() = (sp as i32).wrapping_add(offset) as u32; *self.get_stack_pointer_mut() = (sp as i32).wrapping_add(offset) as u32;
Ok(()) Ok(())
@ -1109,14 +1027,14 @@ where
fn move_memory_to_registers(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, M68kError<Bus::Error>> { fn move_memory_to_registers(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, M68kError<Bus::Error>> {
for i in 0..8 { for i in 0..8 {
if (mask & 0x01) != 0 { if (mask & 0x01) != 0 {
self.state.d_reg[i] = sign_extend_to_long(self.get_address_sized(addr as Address, size)?, size) as u32; self.state.d_reg[i] = sign_extend_to_long(self.get_address_sized(addr, size)?, size) as u32;
(addr, _) = overflowing_add_sized(addr, size.in_bytes(), Size::Long); (addr, _) = overflowing_add_sized(addr, size.in_bytes(), Size::Long);
} }
mask >>= 1; mask >>= 1;
} }
for i in 0..8 { for i in 0..8 {
if (mask & 0x01) != 0 { if (mask & 0x01) != 0 {
*self.get_a_reg_mut(i) = sign_extend_to_long(self.get_address_sized(addr as Address, size)?, size) as u32; *self.get_a_reg_mut(i) = sign_extend_to_long(self.get_address_sized(addr, size)?, size) as u32;
(addr, _) = overflowing_add_sized(addr, size.in_bytes(), Size::Long); (addr, _) = overflowing_add_sized(addr, size.in_bytes(), Size::Long);
} }
mask >>= 1; mask >>= 1;
@ -1127,7 +1045,7 @@ where
fn move_registers_to_memory(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, M68kError<Bus::Error>> { fn move_registers_to_memory(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, M68kError<Bus::Error>> {
for i in 0..8 { for i in 0..8 {
if (mask & 0x01) != 0 { if (mask & 0x01) != 0 {
self.set_address_sized(addr as Address, self.state.d_reg[i], size)?; self.set_address_sized(addr, self.state.d_reg[i], size)?;
addr += size.in_bytes(); addr += size.in_bytes();
} }
mask >>= 1; mask >>= 1;
@ -1135,7 +1053,7 @@ where
for i in 0..8 { for i in 0..8 {
if (mask & 0x01) != 0 { if (mask & 0x01) != 0 {
let value = *self.get_a_reg_mut(i); let value = *self.get_a_reg_mut(i);
self.set_address_sized(addr as Address, value, size)?; self.set_address_sized(addr, value, size)?;
addr += size.in_bytes(); addr += size.in_bytes();
} }
mask >>= 1; mask >>= 1;
@ -1148,14 +1066,14 @@ where
if (mask & 0x01) != 0 { if (mask & 0x01) != 0 {
let value = *self.get_a_reg_mut(i); let value = *self.get_a_reg_mut(i);
addr -= size.in_bytes(); addr -= size.in_bytes();
self.set_address_sized(addr as Address, value, size)?; self.set_address_sized(addr, value, size)?;
} }
mask >>= 1; mask >>= 1;
} }
for i in (0..8).rev() { for i in (0..8).rev() {
if (mask & 0x01) != 0 { if (mask & 0x01) != 0 {
addr -= size.in_bytes(); addr -= size.in_bytes();
self.set_address_sized(addr as Address, self.state.d_reg[i], size)?; self.set_address_sized(addr, self.state.d_reg[i], size)?;
} }
mask >>= 1; mask >>= 1;
} }
@ -1166,7 +1084,7 @@ where
match dir { match dir {
Direction::ToTarget => { Direction::ToTarget => {
let mut shift = (size.in_bits() as i32) - 8; let mut shift = (size.in_bits() as i32) - 8;
let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address; let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32);
while shift >= 0 { while shift >= 0 {
let byte = self.state.d_reg[dreg as usize] >> shift; let byte = self.state.d_reg[dreg as usize] >> shift;
self.set_address_sized(addr, byte, Size::Byte)?; self.set_address_sized(addr, byte, Size::Byte)?;
@ -1176,7 +1094,7 @@ where
}, },
Direction::FromTarget => { Direction::FromTarget => {
let mut shift = (size.in_bits() as i32) - 8; let mut shift = (size.in_bits() as i32) - 8;
let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address; let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32);
while shift >= 0 { while shift >= 0 {
let byte = self.get_address_sized(addr, Size::Byte)?; let byte = self.get_address_sized(addr, Size::Byte)?;
self.state.d_reg[dreg as usize] |= byte << shift; self.state.d_reg[dreg as usize] |= byte << shift;
@ -1551,35 +1469,35 @@ where
Target::DirectAReg(reg) => Ok(get_value_sized(*self.get_a_reg_mut(reg), size)), Target::DirectAReg(reg) => Ok(get_value_sized(*self.get_a_reg_mut(reg), size)),
Target::IndirectAReg(reg) => { Target::IndirectAReg(reg) => {
let addr = *self.get_a_reg_mut(reg); let addr = *self.get_a_reg_mut(reg);
self.get_address_sized(addr as Address, size) self.get_address_sized(addr, size)
}, },
Target::IndirectARegInc(reg) => { Target::IndirectARegInc(reg) => {
let addr = self.post_increment_areg_target(reg, size, used); let addr = self.post_increment_areg_target(reg, size, used);
self.get_address_sized(addr as Address, size) self.get_address_sized(addr, size)
}, },
Target::IndirectARegDec(reg) => { Target::IndirectARegDec(reg) => {
let addr = self.pre_decrement_areg_target(reg, size, Used::Once); let addr = self.pre_decrement_areg_target(reg, size, Used::Once);
self.get_address_sized(addr as Address, size) self.get_address_sized(addr, size)
}, },
Target::IndirectRegOffset(base_reg, index_reg, displacement) => { Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
self.get_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, size) self.get_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32), size)
}, },
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?; let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?;
self.get_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, size) self.get_address_sized(intermediate.wrapping_add(outer_disp as u32), size)
}, },
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?; let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?;
self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size) self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32), size)
}, },
Target::IndirectMemory(addr, _) => { Target::IndirectMemory(addr, _) => {
self.get_address_sized(addr as Address, size) self.get_address_sized(addr, size)
}, },
} }
} }
@ -1594,35 +1512,35 @@ where
}, },
Target::IndirectAReg(reg) => { Target::IndirectAReg(reg) => {
let addr = *self.get_a_reg_mut(reg); let addr = *self.get_a_reg_mut(reg);
self.set_address_sized(addr as Address, value, size)?; self.set_address_sized(addr, value, size)?;
}, },
Target::IndirectARegInc(reg) => { Target::IndirectARegInc(reg) => {
let addr = self.post_increment_areg_target(reg, size, Used::Once); let addr = self.post_increment_areg_target(reg, size, Used::Once);
self.set_address_sized(addr as Address, value, size)?; self.set_address_sized(addr, value, size)?;
}, },
Target::IndirectARegDec(reg) => { Target::IndirectARegDec(reg) => {
let addr = self.pre_decrement_areg_target(reg, size, used); let addr = self.pre_decrement_areg_target(reg, size, used);
self.set_address_sized(addr as Address, value, size)?; self.set_address_sized(addr, value, size)?;
}, },
Target::IndirectRegOffset(base_reg, index_reg, displacement) => { Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
self.set_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, value, size)?; self.set_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32), value, size)?;
}, },
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?; let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?;
self.set_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, value, size)?; self.set_address_sized(intermediate.wrapping_add(outer_disp as u32), value, size)?;
}, },
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?; let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?;
self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size)?; self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32), value, size)?;
}, },
Target::IndirectMemory(addr, _) => { Target::IndirectMemory(addr, _) => {
self.set_address_sized(addr as Address, value, size)?; self.set_address_sized(addr, value, size)?;
}, },
Target::Immediate(_) => return Err(M68kError::InvalidTarget(target)), Target::Immediate(_) => return Err(M68kError::InvalidTarget(target)),
} }
@ -1640,13 +1558,13 @@ where
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?; let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?;
intermediate.wrapping_add(outer_disp as u32) intermediate.wrapping_add(outer_disp as u32)
}, },
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg); let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg); let index_value = self.get_index_reg_value(&index_reg);
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?; let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?;
intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32)
}, },
Target::IndirectMemory(addr, _) => { Target::IndirectMemory(addr, _) => {
@ -1684,44 +1602,44 @@ where
*reg_addr *reg_addr
} }
fn get_address_sized(&mut self, addr: Address, size: Size) -> Result<u32, M68kError<Bus::Error>> { fn get_address_sized(&mut self, addr: M68kAddress, size: Size) -> Result<u32, M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, size) self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, size)
} }
fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), M68kError<Bus::Error>> { fn set_address_sized(&mut self, addr: M68kAddress, value: u32, size: Size) -> Result<(), M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, value, size) self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, size, value)
} }
fn push_word(&mut self, value: u16) -> Result<(), M68kError<Bus::Error>> { fn push_word(&mut self, value: u16) -> Result<(), M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor();
*self.get_stack_pointer_mut() -= 2; *self.get_stack_pointer_mut() -= 2;
let addr = *self.get_stack_pointer_mut(); let addr = *self.get_stack_pointer_mut();
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?; self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Word, value as u32)?;
self.port.write_beu16(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?;
Ok(()) Ok(())
} }
fn pop_word(&mut self) -> Result<u16, M68kError<Bus::Error>> { fn pop_word(&mut self) -> Result<u16, M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor();
let addr = *self.get_stack_pointer_mut(); let addr = *self.get_stack_pointer_mut();
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Read, MemType::Data, false)?; let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Word)?;
let value = self.port.read_beu16(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?;
*self.get_stack_pointer_mut() += 2; *self.get_stack_pointer_mut() += 2;
Ok(value) Ok(value as u16)
} }
fn push_long(&mut self, value: u32) -> Result<(), M68kError<Bus::Error>> { fn push_long(&mut self, value: u32) -> Result<(), M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor();
*self.get_stack_pointer_mut() -= 4; *self.get_stack_pointer_mut() -= 4;
let addr = *self.get_stack_pointer_mut(); let addr = *self.get_stack_pointer_mut();
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?; self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Long, value)?;
self.port.write_beu32(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?;
Ok(()) Ok(())
} }
fn pop_long(&mut self) -> Result<u32, M68kError<Bus::Error>> { fn pop_long(&mut self) -> Result<u32, M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor();
let addr = *self.get_stack_pointer_mut(); let addr = *self.get_stack_pointer_mut();
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Read, MemType::Data, false)?; let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Long)?;
let value = self.port.read_beu32(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?;
*self.get_stack_pointer_mut() += 4; *self.get_stack_pointer_mut() += 4;
Ok(value) Ok(value)
} }

View File

@ -9,5 +9,8 @@ pub mod memory;
pub mod timing; pub mod timing;
pub mod tests; pub mod tests;
#[cfg(feature = "moa")]
pub mod moa;
pub use self::state::{M68k, M68kType, M68kError}; pub use self::state::{M68k, M68kType, M68kError};

View File

@ -1,10 +1,10 @@
use core::cmp;
use core::fmt::Write;
use femtos::Instant; use femtos::Instant;
use emulator_hal::bus::{BusAccess}; use emulator_hal::bus::BusAccess;
use moa_core::{Error, Address, Addressable}; use crate::state::{M68k, M68kError, CpuInfo, Exceptions};
use crate::state::{M68k, M68kError, Exceptions};
use crate::instructions::Size; use crate::instructions::Size;
#[repr(u8)] #[repr(u8)]
@ -102,7 +102,8 @@ impl MemoryRequest {
} }
//pub type M68kAddress = (FunctionCode, u32); //pub type M68kAddress = (FunctionCode, u32);
pub type M68kAddress = u64; pub type M68kAddress = u32;
pub type M68kAddressSpace = (FunctionCode, u32);
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct InstructionRequest { pub struct InstructionRequest {
@ -113,6 +114,8 @@ pub struct InstructionRequest {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct M68kBusPort { pub struct M68kBusPort {
pub request: MemoryRequest, pub request: MemoryRequest,
pub data_bytewidth: usize,
pub address_mask: u32,
pub cycle_start_clock: Instant, pub cycle_start_clock: Instant,
pub current_clock: Instant, pub current_clock: Instant,
} }
@ -126,6 +129,8 @@ impl Default for M68kBusPort {
fn default() -> Self { fn default() -> Self {
Self { Self {
request: Default::default(), request: Default::default(),
data_bytewidth: 32 / 8,
address_mask: 0xFFFF_FFFF,
cycle_start_clock: Instant::START, cycle_start_clock: Instant::START,
current_clock: Instant::START, current_clock: Instant::START,
} }
@ -133,36 +138,82 @@ impl Default for M68kBusPort {
} }
impl M68kBusPort { impl M68kBusPort {
pub fn new(clock: Instant) -> Self { pub fn from_info(info: &CpuInfo, clock: Instant) -> Self {
Self { Self {
request: Default::default(), request: Default::default(),
data_bytewidth: info.data_width as usize / 8,
address_mask: 1_u32.wrapping_shl(info.address_width as u32).wrapping_sub(1),
cycle_start_clock: clock, cycle_start_clock: clock,
current_clock: clock, current_clock: clock,
} }
} }
pub(crate) fn read_data_sized<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: Address, size: Size) -> Result<u32, M68kError<BusError>> fn read<Bus, BusError>(&mut self, bus: &mut Bus, clock: Instant, addr: M68kAddress, data: &mut [u8]) -> Result<(), M68kError<BusError>>
where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{
let addr = addr & self.address_mask;
for i in (0..data.len()).step_by(self.data_bytewidth as usize) {
let addr_index = (addr + i as M68kAddress) & self.address_mask;
let end = cmp::min(i + self.data_bytewidth as usize, data.len());
bus.read(clock, addr_index, &mut data[i..end])
.map_err(|err| M68kError::BusError(err))?;
}
Ok(())
}
fn write<Bus, BusError>(&mut self, bus: &mut Bus, clock: Instant, addr: M68kAddress, data: &[u8]) -> Result<(), M68kError<BusError>>
where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{
let addr = addr & self.address_mask;
for i in (0..data.len()).step_by(self.data_bytewidth as usize) {
let addr_index = (addr + i as M68kAddress) & self.address_mask;
let end = cmp::min(i + self.data_bytewidth as usize, data.len());
bus.write(clock, addr_index, &data[i..end])
.map_err(|err| M68kError::BusError(err))?;
}
Ok(())
}
fn read_sized<Bus, BusError>(&mut self, bus: &mut Bus, addr: M68kAddress, size: Size) -> Result<u32, M68kError<BusError>>
where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{
let mut data = [0; 4];
match size {
Size::Byte => self.read(bus, self.current_clock, addr, &mut data[3..4]),
Size::Word => self.read(bus, self.current_clock, addr, &mut data[2..4]),
Size::Long => self.read(bus, self.current_clock, addr, &mut data[0..4]),
}.map(|_| u32::from_be_bytes(data))
}
fn write_sized<Bus, BusError>(&mut self, bus: &mut Bus, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError<BusError>>
where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{
let data = value.to_be_bytes();
match size {
Size::Byte => self.write(bus, self.current_clock, addr, &data[3..4]),
Size::Word => self.write(bus, self.current_clock, addr, &data[2..4]),
Size::Long => self.write(bus, self.current_clock, addr, &data[0..4]),
}
}
pub(crate) fn read_data_sized<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result<u32, M68kError<BusError>>
where where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?; self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?;
Ok(match size { self.read_sized(port, addr, size)
Size::Byte => port.read_u8(self.current_clock, addr).map(|value| value as u32),
Size::Word => port.read_beu16(self.current_clock, addr).map(|value| value as u32),
Size::Long => port.read_beu32(self.current_clock, addr),
}.map_err(|err| M68kError::BusError(err))?)
} }
pub(crate) fn write_data_sized<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), M68kError<BusError>> pub(crate) fn write_data_sized<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError<BusError>>
where where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?; self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?;
Ok(match size { self.write_sized(port, addr, size, value)
Size::Byte => port.write_u8(self.current_clock, addr, value as u8),
Size::Word => port.write_beu16(self.current_clock, addr, value as u16),
Size::Long => port.write_beu32(self.current_clock, addr, value),
}.map_err(|err| M68kError::BusError(err))?)
} }
pub(crate) fn read_instruction_word<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u16, M68kError<BusError>> pub(crate) fn read_instruction_word<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u16, M68kError<BusError>>
@ -170,7 +221,7 @@ impl M68kBusPort {
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.request.instruction(is_supervisor, addr)?; self.request.instruction(is_supervisor, addr)?;
Ok(port.read_beu16(self.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?) Ok(self.read_sized(port, addr, Size::Word)? as u16)
} }
pub(crate) fn read_instruction_long<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u32, M68kError<BusError>> pub(crate) fn read_instruction_long<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u32, M68kError<BusError>>
@ -178,7 +229,7 @@ impl M68kBusPort {
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.request.instruction(is_supervisor, addr)?; self.request.instruction(is_supervisor, addr)?;
Ok(port.read_beu32(self.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?) self.read_sized(port, addr, Size::Long)
} }
pub(crate) fn start_request<BusError>(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, M68kError<BusError>> { pub(crate) fn start_request<BusError>(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, M68kError<BusError>> {
@ -197,14 +248,6 @@ impl M68kBusPort {
validate_address(addr) validate_address(addr)
} }
} }
pub(crate) fn dump_memory<Bus, BusError>(&mut self, port: &mut Bus, addr: u32, length: usize)
where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{
// TODO temporarily disabled
//port.dump_memory(self.current_clock, addr as Address, length as u64);
}
} }
fn validate_address<BusError>(addr: u32) -> Result<u32, M68kError<BusError>> { fn validate_address<BusError>(addr: u32) -> Result<u32, M68kError<BusError>> {
@ -215,22 +258,31 @@ fn validate_address<BusError>(addr: u32) -> Result<u32, M68kError<BusError>> {
} }
} }
/* pub fn dump_memory<Bus, Address, Instant>(bus: &mut Bus, clock: Instant, addr: Address, count: Address)
impl BusType for M68kBusPort { where
type Instant = Instant; Bus: BusAccess<Address, Instant>,
type Error = Error; Address: From<u32> + Into<u32> + Copy,
} Instant: Copy,
{
impl BusAccess<u32> for M68kBusPort { let mut addr = addr.into();
fn read(&mut self, now: Self::Instant, addr: Address, data: &mut [u8]) -> Result<usize, Self::Error> { let mut count = count.into();
self. while count > 0 {
} let mut line = format!("{:#010x}: ", addr);
fn write(&mut self, now: Self::Instant, addr: Address, data: &[u8]) -> Result<usize, Self::Error> {
let to = if count < 16 { count / 2 } else { 8 };
for _ in 0..to {
let word = bus.read_beu16(clock, Address::from(addr));
if word.is_err() {
println!("{}", line);
return;
}
write!(line, "{:#06x} ", word.unwrap()).unwrap();
addr += 2;
count -= 2;
}
println!("{}", line);
} }
} }
*/
/* /*
pub(crate) struct TargetAccess { pub(crate) struct TargetAccess {

View File

@ -0,0 +1,124 @@
use femtos::{Instant, Duration};
use emulator_hal::bus;
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
use crate::state::{M68k, M68kError};
use crate::decode::M68kDecoder;
use crate::execute::M68kCycle;
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<Duration, Error> {
let cycle = M68kCycle::new(self, system.clock);
let mut bus = system.bus.borrow_mut();
let mut adapter: bus::BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = bus::BusAdapter::new(
&mut *bus,
|addr| addr as u64,
|err| err.try_into().unwrap(),
);
let mut executor = cycle.begin(self, &mut adapter);
executor.check_breakpoints()?;
executor.step()?;
let interrupt = system.get_interrupt_controller().check();
if let (priority, Some(ack)) = executor.check_pending_interrupts(interrupt)? {
log::debug!("interrupt: {:?} @ {} ns", priority, system.clock.as_duration().as_nanos());
system.get_interrupt_controller().acknowledge(priority as u8)?;
}
self.cycle = Some(executor.end());
Ok(self.last_cycle_duration())
}
fn on_error(&mut self, _system: &System) {
let mut output = String::with_capacity(256);
self.dump_state(&mut output);
println!("{}", output);
}
}
impl Interruptable for M68k { }
impl Transmutable for M68k {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
Some(self)
}
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
Some(self)
}
}
impl<BusError> From<Error> for M68kError<BusError> {
fn from(err: Error) -> Self {
match err {
Error::Processor(ex) => M68kError::Interrupt(ex as u8),
Error::Breakpoint(msg) => M68kError::Breakpoint,
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(format!("{}", msg)),
}
}
}
impl<BusError: bus::Error> From<M68kError<BusError>> for Error {
fn from(err: M68kError<BusError>) -> Self {
match err {
M68kError::Halted => Self::Other("cpu halted".to_string()),
M68kError::Exception(ex) => Self::Processor(ex as u32),
M68kError::Interrupt(num) => Self::Processor(num as u32),
M68kError::Breakpoint => Self::Breakpoint("breakpoint".to_string()),
M68kError::InvalidTarget(target) => Self::new(target.to_string()),
M68kError::BusError(msg) => Self::Other(format!("{:?}", msg)),
M68kError::Other(msg) => Self::Other(msg),
}
}
}
impl Debuggable for M68k {
fn add_breakpoint(&mut self, addr: Address) {
self.debugger.breakpoints.push(addr as u32);
}
fn remove_breakpoint(&mut self, addr: Address) {
if let Some(index) = self.debugger.breakpoints.iter().position(|a| *a == addr as u32) {
self.debugger.breakpoints.remove(index);
}
}
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
// TODO this is called by the debugger, but should be called some other way
//let _ = self.decoder.decode_at(&mut self.port, true, self.state.pc);
//self.decoder.dump_decoded(&mut self.port);
//self.dump_state();
Ok(())
}
fn print_disassembly(&mut self, addr: Address, count: usize) {
let mut decoder = M68kDecoder::new(self.info.chip, true, 0);
//decoder.dump_disassembly(&mut self.port, self.cycle.memory, addr as u32, count as u32);
}
fn run_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}", system.bus.borrow_mut().read_beu32(system.clock, *addr as Address)?);
}
},
"so" | "stepout" => {
self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1);
},
_ => { return Ok(true); },
}
Ok(false)
}
}

View File

@ -1,13 +1,8 @@
use std::rc::Rc; use core::fmt::{self, Write};
use std::cell::RefCell; use femtos::{Duration, Frequency};
use std::fmt::Display;
use femtos::{Instant, Frequency};
use moa_core::{Address, Bus, BusPort};
use crate::debugger::M68kDebugger; use crate::debugger::M68kDebugger;
use crate::memory::M68kBusPort;
use crate::instructions::Target; use crate::instructions::Target;
use crate::execute::M68kCycle; use crate::execute::M68kCycle;
@ -82,7 +77,7 @@ impl From<M68kType> for CoreType {
} }
impl CpuInfo { impl CpuInfo {
fn from(cputype: M68kType, frequency: Frequency) -> Self { pub fn from_type(cputype: M68kType, frequency: Frequency) -> Self {
match cputype { match cputype {
M68kType::MC68008 => Self { M68kType::MC68008 => Self {
chip: cputype, chip: cputype,
@ -218,7 +213,6 @@ pub struct M68k {
pub info: CpuInfo, pub info: CpuInfo,
pub state: M68kState, pub state: M68kState,
pub debugger: M68kDebugger, pub debugger: M68kDebugger,
pub port: BusPort,
pub stats: M68kStatistics, pub stats: M68kStatistics,
pub cycle: Option<M68kCycle>, pub cycle: Option<M68kCycle>,
} }
@ -242,21 +236,50 @@ impl Default for M68kState {
} }
} }
impl M68kState {
pub fn dump_state<W: Write>(&mut self, writer: &mut W) -> Result<(), fmt::Error> {
writeln!(writer, "Status: {:?}", self.status)?;
writeln!(writer, "PC: {:#010x}", self.pc)?;
writeln!(writer, "SR: {:#06x}", self.sr)?;
for i in 0..7 {
writeln!(writer, "D{}: {:#010x} A{}: {:#010x}", i, self.d_reg[i as usize], i, self.a_reg[i as usize])?;
}
writeln!(writer, "D7: {:#010x} USP: {:#010x}", self.d_reg[7], self.usp)?;
writeln!(writer, " SSP: {:#010x}", self.ssp)?;
Ok(())
}
}
impl M68k { impl M68k {
pub fn new(info: CpuInfo, port: BusPort) -> M68k { pub fn new(info: CpuInfo) -> Self {
M68k { M68k {
info, info,
state: M68kState::default(), state: M68kState::default(),
debugger: M68kDebugger::default(), debugger: M68kDebugger::default(),
port,
stats: Default::default(), stats: Default::default(),
cycle: None, cycle: None,
} }
} }
pub fn from_type(cputype: M68kType, frequency: Frequency, bus: Rc<RefCell<Bus>>, addr_offset: Address) -> Self { pub fn from_type(cputype: M68kType, freq: Frequency) -> Self {
let info = CpuInfo::from(cputype, frequency); Self::new(CpuInfo::from_type(cputype, freq))
Self::new(info, BusPort::new(addr_offset, info.address_width as u8, info.data_width as u8, bus)) }
pub fn dump_state<W: Write>(&mut self, writer: &mut W) {
self.state.dump_state(writer);
if let Some(cycle) = self.cycle.as_ref() {
println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction);
println!();
}
//memory::dump_memory(&mut self.port, self.cycle.current_clock, self.state.ssp, 0x40);
println!();
}
#[inline]
pub fn last_cycle_duration(&self) -> Duration {
let clocks = self.cycle.as_ref().map(|cycle| cycle.timing.calculate_clocks()).unwrap_or(4);
self.info.frequency.period_duration() * clocks as u64
} }
} }

View File

@ -4,28 +4,36 @@ mod decode_unit_tests {
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use femtos::Instant; use femtos::Instant;
use emulator_hal::bus::{BusAccess, BusAdapter};
use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, Device}; use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, Device, Error};
use crate::M68kType; use crate::M68kType;
use crate::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister}; use crate::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister};
use crate::decode::M68kDecoder; use crate::decode::{M68kDecoder, InstructionDecoding};
use crate::memory::M68kBusPort; use crate::memory::M68kBusPort;
const INIT_ADDR: Address = 0x00000000; const INIT_ADDR: u32 = 0x00000000;
fn init_decode_test(cputype: M68kType) -> (M68kBusPort, M68kDecoder) { fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, BusAdapter<u32, u64, Instant, &'a mut dyn Addressable, Error>> {
let bus = Rc::new(RefCell::new(Bus::default())); let bus = Rc::new(RefCell::new(Bus::default()));
let mem = MemoryBlock::new(vec![0; 0x0000100]); let mem = MemoryBlock::new(vec![0; 0x0000100]);
bus.borrow_mut().insert(0x00000000, Device::new(mem)); bus.borrow_mut().insert(0x00000000, Device::new(mem));
let port = if cputype <= M68kType::MC68010 { let mut bus = bus.borrow_mut();
M68kBusPort::new(BusPort::new(0, 24, 16, bus)) let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
} else { &mut *bus,
M68kBusPort::new(BusPort::new(0, 32, 32, bus)) |addr| addr as u64,
|err| err.try_into().unwrap(),
);
let mut decoder = M68kDecoder::new(cputype, true, 0);
let mut decoding = InstructionDecoding {
port: &mut adapter,
memory: &mut M68kBusPort::default(),
decoder: &mut decoder,
}; };
let decoder = M68kDecoder::new(cputype, true, 0); decoding
(port, decoder)
} }
// //
@ -34,216 +42,216 @@ mod decode_unit_tests {
#[test] #[test]
fn target_direct_d() { fn target_direct_d() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Word; let size = Size::Word;
let target = decoder.get_mode_as_target(&mut port, 0b000, 0b001, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b000, 0b001, Some(size)).unwrap();
assert_eq!(target, Target::DirectDReg(1)); assert_eq!(target, Target::DirectDReg(1));
} }
#[test] #[test]
fn target_direct_a() { fn target_direct_a() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Word; let size = Size::Word;
let target = decoder.get_mode_as_target(&mut port, 0b001, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b001, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::DirectAReg(2)); assert_eq!(target, Target::DirectAReg(2));
} }
#[test] #[test]
fn target_indirect_a() { fn target_indirect_a() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Long; let size = Size::Long;
let expected = 0x12345678; let expected = 0x12345678;
port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b010, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b010, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectAReg(2)); assert_eq!(target, Target::IndirectAReg(2));
} }
#[test] #[test]
fn target_indirect_a_inc() { fn target_indirect_a_inc() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Long; let size = Size::Long;
let expected = 0x12345678; let expected = 0x12345678;
port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b011, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b011, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectARegInc(2)); assert_eq!(target, Target::IndirectARegInc(2));
} }
#[test] #[test]
fn target_indirect_a_dec() { fn target_indirect_a_dec() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Long; let size = Size::Long;
let expected = 0x12345678; let expected = 0x12345678;
port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b100, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b100, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectARegDec(2)); assert_eq!(target, Target::IndirectARegDec(2));
} }
#[test] #[test]
fn target_indirect_a_reg_offset() { fn target_indirect_a_reg_offset() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Long; let size = Size::Long;
let offset = -8; let offset = -8;
port.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b101, 0b100, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset));
} }
#[test] #[test]
fn target_indirect_a_reg_brief_extension_word() { fn target_indirect_a_reg_brief_extension_word() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Long; let size = Size::Long;
let offset = -8; let offset = -8;
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
port.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset));
} }
#[test] #[test]
fn target_indirect_a_reg_full_extension_word() { fn target_indirect_a_reg_full_extension_word() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); let mut decoder = init_decode_test(M68kType::MC68020);
let size = Size::Word; let size = Size::Word;
let offset = -1843235 as i32; let offset = -1843235 as i32;
let brief_extension = 0xF330; let brief_extension = 0xF330;
port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
} }
#[test] #[test]
fn target_indirect_a_reg_full_extension_word_no_base() { fn target_indirect_a_reg_full_extension_word_no_base() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); let mut decoder = init_decode_test(M68kType::MC68020);
let size = Size::Word; let size = Size::Word;
let offset = -1843235 as i32; let offset = -1843235 as i32;
let brief_extension = 0xF3B0; let brief_extension = 0xF3B0;
port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
} }
#[test] #[test]
fn target_indirect_a_reg_full_extension_word_no_index() { fn target_indirect_a_reg_full_extension_word_no_index() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); let mut decoder = init_decode_test(M68kType::MC68020);
let size = Size::Word; let size = Size::Word;
let offset = -1843235 as i32; let offset = -1843235 as i32;
let brief_extension = 0xF370; let brief_extension = 0xF370;
port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset));
} }
#[test] #[test]
fn target_indirect_pc_offset() { fn target_indirect_pc_offset() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Long; let size = Size::Long;
let offset = -8; let offset = -8;
port.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b010, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset));
} }
#[test] #[test]
fn target_indirect_pc_brief_extension_word() { fn target_indirect_pc_brief_extension_word() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Word; let size = Size::Word;
let offset = -8; let offset = -8;
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
port.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b011, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset));
} }
#[test] #[test]
fn target_indirect_pc_full_extension_word() { fn target_indirect_pc_full_extension_word() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); let mut decoder = init_decode_test(M68kType::MC68020);
let size = Size::Word; let size = Size::Word;
let offset = -1843235 as i32; let offset = -1843235 as i32;
let brief_extension = 0xF330; let brief_extension = 0xF330;
port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b011, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap();
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
} }
#[test] #[test]
fn target_indirect_immediate_word() { fn target_indirect_immediate_word() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Word; let size = Size::Word;
let expected = 0x1234; let expected = 0x1234;
port.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b000, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b000, Some(size)).unwrap();
assert_eq!(target, Target::IndirectMemory(expected, Size::Word)); assert_eq!(target, Target::IndirectMemory(expected, Size::Word));
} }
#[test] #[test]
fn target_indirect_immediate_long() { fn target_indirect_immediate_long() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Word; let size = Size::Word;
let expected = 0x12345678; let expected = 0x12345678;
port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b001, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b001, Some(size)).unwrap();
assert_eq!(target, Target::IndirectMemory(expected, Size::Long)); assert_eq!(target, Target::IndirectMemory(expected, Size::Long));
} }
#[test] #[test]
fn target_immediate() { fn target_immediate() {
let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); let mut decoder = init_decode_test(M68kType::MC68010);
let size = Size::Word; let size = Size::Word;
let expected = 0x1234; let expected = 0x1234;
port.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap();
let target = decoder.get_mode_as_target(&mut port, 0b111, 0b100, Some(size)).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b100, Some(size)).unwrap();
assert_eq!(target, Target::Immediate(expected)); assert_eq!(target, Target::Immediate(expected));
} }
} }
@ -252,18 +260,20 @@ mod decode_unit_tests {
#[cfg(test)] #[cfg(test)]
mod execute_unit_tests { mod execute_unit_tests {
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; use emulator_hal::bus::{BusAdapter, BusAccess};
use moa_core::{System, MemoryBlock, Addressable, Steppable, Device, Error};
use crate::{M68k, M68kType}; use crate::{M68k, M68kType};
use crate::execute::{Used, M68kCycle, M68kCycleExecutor}; use crate::execute::{Used, M68kCycle, M68kCycleExecutor};
use crate::instructions::{Instruction, Target, Size}; use crate::instructions::{Instruction, Target, Size};
const INIT_STACK: Address = 0x00002000; const INIT_STACK: u32 = 0x00002000;
const INIT_ADDR: Address = 0x00000010; const INIT_ADDR: u32 = 0x00000010;
fn run_execute_test<F>(cputype: M68kType, mut test_func: F) fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
where where
F: FnMut(M68kCycleExecutor), F: FnMut(M68kCycleExecutor<&mut BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error>>),
{ {
let mut system = System::default(); let mut system = System::default();
@ -274,10 +284,18 @@ mod execute_unit_tests {
system.get_bus().write_beu32(system.clock, 0, INIT_STACK as u32).unwrap(); system.get_bus().write_beu32(system.clock, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(system.clock, 4, INIT_ADDR as u32).unwrap(); system.get_bus().write_beu32(system.clock, 4, INIT_ADDR as u32).unwrap();
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
cpu.step(&system).unwrap(); cpu.step(&system).unwrap();
let mut cycle = M68kCycle::new(&mut cpu, system.clock); let mut cycle = M68kCycle::new(&mut cpu, system.clock);
let mut executor = cycle.begin(&mut cpu);
let mut bus = system.bus.borrow_mut();
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
&mut *bus,
|addr| addr as u64,
|err| err.try_into().unwrap(),
);
let mut executor = cycle.begin(&mut cpu, &mut adapter);
executor.cycle.decoder.init(true, executor.state.pc); executor.cycle.decoder.init(true, executor.state.pc);
assert_eq!(executor.state.pc, INIT_ADDR as u32); assert_eq!(executor.state.pc, INIT_ADDR as u32);
assert_eq!(executor.state.ssp, INIT_STACK as u32); assert_eq!(executor.state.ssp, INIT_STACK as u32);
@ -322,7 +340,7 @@ mod execute_unit_tests {
let size = Size::Long; let size = Size::Long;
let expected = 0x12345678; let expected = 0x12345678;
let target = Target::IndirectAReg(2); let target = Target::IndirectAReg(2);
cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
cycle.state.a_reg[2] = INIT_ADDR as u32; cycle.state.a_reg[2] = INIT_ADDR as u32;
let result = cycle.get_target_value(target, size, Used::Once).unwrap(); let result = cycle.get_target_value(target, size, Used::Once).unwrap();
@ -336,7 +354,7 @@ mod execute_unit_tests {
let size = Size::Long; let size = Size::Long;
let expected = 0x12345678; let expected = 0x12345678;
let target = Target::IndirectARegInc(2); let target = Target::IndirectARegInc(2);
cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
cycle.state.a_reg[2] = INIT_ADDR as u32; cycle.state.a_reg[2] = INIT_ADDR as u32;
let result = cycle.get_target_value(target, size, Used::Once).unwrap(); let result = cycle.get_target_value(target, size, Used::Once).unwrap();
@ -351,7 +369,7 @@ mod execute_unit_tests {
let size = Size::Long; let size = Size::Long;
let expected = 0x12345678; let expected = 0x12345678;
let target = Target::IndirectARegDec(2); let target = Target::IndirectARegDec(2);
cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
cycle.state.a_reg[2] = (INIT_ADDR as u32) + 4; cycle.state.a_reg[2] = (INIT_ADDR as u32) + 4;
let result = cycle.get_target_value(target, size, Used::Once).unwrap(); let result = cycle.get_target_value(target, size, Used::Once).unwrap();
@ -374,5 +392,3 @@ mod execute_unit_tests {
}); });
} }
} }

View File

@ -1,7 +1,8 @@
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use emulator_hal::bus::BusAdapter;
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device}; use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device, Error};
use moa_m68k::{M68k, M68kType}; use moa_m68k::{M68k, M68kType};
use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction}; use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction};
@ -77,12 +78,12 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
// Initialize the CPU and make sure it's in the expected state // Initialize the CPU and make sure it's in the expected state
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
//cpu.reset_cpu().unwrap(); //cpu.reset_cpu().unwrap();
assert_eq!(cpu.state.pc, INIT_ADDR as u32); //assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32); //assert_eq!(cpu.state.ssp, INIT_STACK as u32);
let cycle = M68kCycle::new(&cpu, system.clock); let cycle = M68kCycle::new(&cpu, system.clock);
assert_eq!(cycle.decoder.start, INIT_ADDR as u32); //assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
assert_eq!(cycle.decoder.instruction, Instruction::NOP); //assert_eq!(cycle.decoder.instruction, Instruction::NOP);
(cpu, cycle, system) (cpu, cycle, system)
} }
@ -97,14 +98,24 @@ fn load_memory(system: &System, data: &[u16]) {
fn run_decode_test(case: &TestCase) { fn run_decode_test(case: &TestCase) {
let (mut cpu, cycle, system) = init_decode_test(case.cpu); let (mut cpu, cycle, system) = init_decode_test(case.cpu);
load_memory(&system, case.data); load_memory(&system, case.data);
let mut bus = system.bus.borrow_mut();
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
&mut *bus,
|addr| addr as u64,
|err| err.try_into().unwrap(),
);
match &case.ins { match &case.ins {
Some(ins) => { Some(ins) => {
let mut executor = cycle.begin(&mut cpu); let mut executor = cycle.begin(&mut cpu, &mut adapter);
executor.reset_cpu().unwrap();
executor.decode_next().unwrap(); executor.decode_next().unwrap();
assert_eq!(executor.cycle.decoder.instruction, ins.clone()); assert_eq!(executor.cycle.decoder.instruction, ins.clone());
}, },
None => { None => {
let mut executor = cycle.begin(&mut cpu); let mut executor = cycle.begin(&mut cpu, &mut adapter);
executor.reset_cpu().unwrap();
let next = executor.decode_next(); let next = executor.decode_next();
println!("{:?}", executor.cycle.decoder.instruction); println!("{:?}", executor.cycle.decoder.instruction);
assert!(next.is_err()); assert!(next.is_err());

View File

@ -1,7 +1,8 @@
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use emulator_hal::bus::BusAdapter;
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device, Error};
use moa_m68k::{M68k, M68kType}; use moa_m68k::{M68k, M68kType};
use moa_m68k::state::M68kState; use moa_m68k::state::M68kState;
@ -37,7 +38,7 @@ struct TestCase {
fn run_execute_test<F>(cputype: M68kType, mut test_func: F) fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
where where
F: FnMut(M68kCycleExecutor, System), F: FnMut(M68kCycleExecutor<&mut BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error>>, &System),
{ {
let mut system = System::default(); let mut system = System::default();
@ -48,17 +49,24 @@ where
system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap(); system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap();
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap(); system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap();
let mut bus = system.bus.borrow_mut();
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
&mut *bus,
|addr| addr as u64,
|err| err.try_into().unwrap(),
);
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
cpu.step(&system).unwrap(); cpu.step(&system).unwrap();
let cycle = M68kCycle::new(&cpu, system.clock); let cycle = M68kCycle::new(&cpu, system.clock);
let mut executor = cycle.begin(&mut cpu); let executor = cycle.begin(&mut cpu, &mut adapter);
assert_eq!(executor.state.pc, INIT_ADDR as u32); assert_eq!(executor.state.pc, INIT_ADDR as u32);
assert_eq!(executor.state.ssp, INIT_STACK as u32); assert_eq!(executor.state.ssp, INIT_STACK as u32);
assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP); assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP);
test_func(executor, system) test_func(executor, &system)
} }
fn build_state(state: &TestState) -> M68kState { fn build_state(state: &TestState) -> M68kState {

View File

@ -1,5 +1,6 @@
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use emulator_hal::bus::BusAdapter;
use moa_core::{System, Error, MemoryBlock, Address, Addressable, Device}; use moa_core::{System, Error, MemoryBlock, Address, Addressable, Device};
@ -42,7 +43,15 @@ fn load_memory(system: &System, data: &[u16]) {
fn run_timing_test(case: &TimingCase) -> Result<(), Error> { fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
let (mut cpu, cycle, system) = init_decode_test(case.cpu); let (mut cpu, cycle, system) = init_decode_test(case.cpu);
let mut executor = cycle.begin(&mut cpu);
let mut bus = system.bus.borrow_mut();
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
&mut *bus,
|addr| addr as u64,
|err| err.try_into().unwrap(),
);
let mut executor = cycle.begin(&mut cpu, &mut adapter);
let mut timing = M68kInstructionTiming::new(case.cpu, 16); let mut timing = M68kInstructionTiming::new(case.cpu, 16);
load_memory(&system, case.data); load_memory(&system, case.data);
@ -50,7 +59,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
timing.add_instruction(&executor.cycle.decoder.instruction); timing.add_instruction(&executor.cycle.decoder.instruction);
let result = timing.calculate_clocks(false, 1); let result = timing.calculate_clocks();
let expected = match case.cpu { let expected = match case.cpu {
M68kType::MC68000 => case.timing.0, M68kType::MC68000 => case.timing.0,
M68kType::MC68010 => case.timing.1, M68kType::MC68010 => case.timing.1,

View File

@ -1,5 +1,6 @@
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use emulator_hal::bus::BusAdapter;
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device}; use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device};
@ -56,7 +57,15 @@ fn load_memory(system: &System, data: &[u16]) {
fn run_timing_test(case: &TimingCase) -> Result<(), Error> { fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
let (mut cpu, cycle, system) = init_decode_test(case.cpu); let (mut cpu, cycle, system) = init_decode_test(case.cpu);
let mut executor = cycle.begin(&mut cpu);
let mut bus = system.bus.borrow_mut();
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
&mut *bus,
|addr| addr as u64,
|err| err.try_into().unwrap(),
);
let mut executor = cycle.begin(&mut cpu, &mut adapter);
let mut timing = M68kInstructionTiming::new(case.cpu, 16); let mut timing = M68kInstructionTiming::new(case.cpu, 16);
load_memory(&system, case.data); load_memory(&system, case.data);
@ -64,7 +73,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
timing.add_instruction(&executor.cycle.decoder.instruction); timing.add_instruction(&executor.cycle.decoder.instruction);
let result = timing.calculate_clocks(false, 1); let result = timing.calculate_clocks();
let expected = match case.cpu { let expected = match case.cpu {
M68kType::MC68000 => case.timing.0, M68kType::MC68000 => case.timing.0,
M68kType::MC68010 => case.timing.1, M68kType::MC68010 => case.timing.1,

View File

@ -9,10 +9,15 @@ use nix::fcntl::OFlag;
use nix::pty::{self, PtyMaster}; use nix::pty::{self, PtyMaster};
use nix::fcntl::{fcntl, FcntlArg}; use nix::fcntl::{fcntl, FcntlArg};
use moa_core::Error; use moa_host::Tty;
use moa_core::host::Tty;
#[derive(Debug, PartialEq, Eq)]
pub enum SimplePtyError {
Open,
PtsName,
}
pub struct SimplePty { pub struct SimplePty {
pub name: String, pub name: String,
input: mpsc::Receiver<u8>, input: mpsc::Receiver<u8>,
@ -28,14 +33,14 @@ impl SimplePty {
} }
} }
pub fn open() -> Result<SimplePty, Error> { pub fn open() -> Result<SimplePty, SimplePtyError> {
let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| { let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| {
pty::grantpt(&pty)?; pty::grantpt(&pty)?;
pty::unlockpt(&pty)?; pty::unlockpt(&pty)?;
Ok(pty) Ok(pty)
}).map_err(|_| Error::new("Error opening new pseudoterminal"))?; }).map_err(|_| SimplePtyError::Open)?;
let name = unsafe { pty::ptsname(&pty).map_err(|_| Error::new("Unable to get pty name"))? }; let name = unsafe { pty::ptsname(&pty).map_err(|_| SimplePtyError::PtsName)? };
let (input_tx, input_rx) = mpsc::channel(); let (input_tx, input_rx) = mpsc::channel();
let (output_tx, output_rx) = mpsc::channel(); let (output_tx, output_rx) = mpsc::channel();
let shared = SimplePty::new(name.clone(), input_rx, output_tx); let shared = SimplePty::new(name.clone(), input_rx, output_tx);

View File

@ -11,10 +11,12 @@ simple_logger = "^2"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
moa-common = { path = "../common", features = ["tty"] } moa-common = { path = "../common", features = ["tty"] }
moa-debugger = { path = "../../libraries/debugger" }
moa-systems-genesis = { path = "../../systems/genesis" } moa-systems-genesis = { path = "../../systems/genesis" }
moa-systems-computie = { path = "../../systems/computie" } moa-systems-computie = { path = "../../systems/computie" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k", features = ["moa"] }
moa-peripherals-generic = { path = "../../peripherals/generic" } moa-peripherals-generic = { path = "../../peripherals/generic" }
moa-peripherals-motorola = { path = "../../peripherals/motorola" } moa-peripherals-motorola = { path = "../../peripherals/motorola" }

View File

@ -3,8 +3,9 @@ use clap::{Command, Arg, ArgAction, ArgMatches};
use std::io::{self, Write}; use std::io::{self, Write};
use femtos::Duration; use femtos::Duration;
use moa_core::{Error, System, DebugControl, Debugger}; use moa_core::{Error, System};
use moa_core::host::{Host, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender}; use moa_debugger::{Debugger, DebugControl};
use moa_host::{Host, HostError, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender};
pub struct ConsoleFrontend; pub struct ConsoleFrontend;
@ -13,7 +14,7 @@ impl Host for ConsoleFrontend {
fn add_pty(&self) -> Result<Box<dyn Tty>, HostError<Self::Error>> { fn add_pty(&self) -> Result<Box<dyn Tty>, HostError<Self::Error>> {
use moa_common::tty::SimplePty; use moa_common::tty::SimplePty;
Ok(Box::new(SimplePty::open()?)) Ok(Box::new(SimplePty::open().map_err(|err| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?))
} }
fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> { fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> {

View File

@ -2,8 +2,14 @@
use std::str::Chars; use std::str::Chars;
use std::iter::Peekable; use std::iter::Peekable;
use moa_core::Error;
pub struct ParserError(pub String);
impl ParserError {
pub fn new(msg: String) -> Self {
Self(msg)
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum AssemblyLine { pub enum AssemblyLine {
@ -34,7 +40,7 @@ impl<'input> AssemblyParser<'input> {
} }
} }
pub fn parse(&mut self) -> Result<Vec<(usize, AssemblyLine)>, Error> { pub fn parse(&mut self) -> Result<Vec<(usize, AssemblyLine)>, ParserError> {
let mut output = vec![]; let mut output = vec![];
loop { loop {
let lineno = self.lexer.get_next_lineno(); let lineno = self.lexer.get_next_lineno();
@ -47,7 +53,7 @@ impl<'input> AssemblyParser<'input> {
Ok(output) Ok(output)
} }
fn parse_line(&mut self) -> Result<Option<AssemblyLine>, Error> { fn parse_line(&mut self) -> Result<Option<AssemblyLine>, ParserError> {
let token = loop { let token = loop {
match self.lexer.get_next() { match self.lexer.get_next() {
Some(token) if token == "\n" => { }, Some(token) if token == "\n" => { },
@ -73,7 +79,7 @@ impl<'input> AssemblyParser<'input> {
} }
}, },
_ => { _ => {
return Err(Error::new(format!("parse error at line {}: expected word, found {:?}", self.lexer.lineno(), token))); return Err(ParserError::new(format!("parse error at line {}: expected word, found {:?}", self.lexer.lineno(), token)));
}, },
}; };
@ -81,7 +87,7 @@ impl<'input> AssemblyParser<'input> {
Ok(Some(result)) Ok(Some(result))
} }
fn parse_list_of_words(&mut self) -> Result<Vec<String>, Error> { fn parse_list_of_words(&mut self) -> Result<Vec<String>, ParserError> {
let mut list = vec![]; let mut list = vec![];
// If we're already at the end of the line, then it's an empty list, so return // If we're already at the end of the line, then it's an empty list, so return
@ -101,7 +107,7 @@ impl<'input> AssemblyParser<'input> {
} }
} }
fn parse_list_of_operands(&mut self) -> Result<Vec<AssemblyOperand>, Error> { fn parse_list_of_operands(&mut self) -> Result<Vec<AssemblyOperand>, ParserError> {
let mut list = vec![]; let mut list = vec![];
// If we're already at the end of the line, then it's an empty list, so return // If we're already at the end of the line, then it's an empty list, so return
@ -121,7 +127,7 @@ impl<'input> AssemblyParser<'input> {
} }
} }
fn parse_operand(&mut self) -> Result<AssemblyOperand, Error> { fn parse_operand(&mut self) -> Result<AssemblyOperand, ParserError> {
let token = self.lexer.expect_next()?; let token = self.lexer.expect_next()?;
match token.as_str() { match token.as_str() {
"%" => { "%" => {
@ -163,7 +169,7 @@ impl<'input> AssemblyParser<'input> {
} }
} }
fn parse_any_number(lineno: usize, string: &str) -> Result<usize, Error> { fn parse_any_number(lineno: usize, string: &str) -> Result<usize, ParserError> {
let (radix, numeric) = if let Some(s) = string.strip_prefix("0x") { let (radix, numeric) = if let Some(s) = string.strip_prefix("0x") {
(16, s) (16, s)
} else if let Some(s) = string.strip_prefix("0b") { } else if let Some(s) = string.strip_prefix("0b") {
@ -174,7 +180,7 @@ fn parse_any_number(lineno: usize, string: &str) -> Result<usize, Error> {
(10, string) (10, string)
}; };
usize::from_str_radix(numeric, radix) usize::from_str_radix(numeric, radix)
.map_err(|_| Error::new(format!("parse error at line {}: expected number after #, but found {:?}", lineno, string))) .map_err(|_| ParserError::new(format!("parse error at line {}: expected number after #, but found {:?}", lineno, string)))
} }
@ -230,25 +236,25 @@ impl<'input> AssemblyLexer<'input> {
self.peeked.clone() self.peeked.clone()
} }
pub fn expect_next(&mut self) -> Result<String, Error> { pub fn expect_next(&mut self) -> Result<String, ParserError> {
self.get_next().ok_or_else(|| Error::new(format!("unexpected end of input at line {}", self.lineno))) self.get_next().ok_or_else(|| ParserError::new(format!("unexpected end of input at line {}", self.lineno)))
} }
pub fn expect_token(&mut self, expected: &str) -> Result<(), Error> { pub fn expect_token(&mut self, expected: &str) -> Result<(), ParserError> {
let token = self.expect_next()?; let token = self.expect_next()?;
if token == expected { if token == expected {
Ok(()) Ok(())
} else { } else {
Err(Error::new(format!("parse error at line {}: expected {:?}, found {:?}", self.lineno, expected, token))) Err(ParserError::new(format!("parse error at line {}: expected {:?}, found {:?}", self.lineno, expected, token)))
} }
} }
pub fn expect_end(&mut self) -> Result<(), Error> { pub fn expect_end(&mut self) -> Result<(), ParserError> {
let token = self.get_next(); let token = self.get_next();
if token.is_none() || token.as_ref().unwrap() == "\n" { if token.is_none() || token.as_ref().unwrap() == "\n" {
Ok(()) Ok(())
} else { } else {
Err(Error::new(format!("expected end of line at {}: found {:?}", self.lineno, token))) Err(ParserError::new(format!("expected end of line at {}: found {:?}", self.lineno, token)))
} }
} }
@ -301,28 +307,28 @@ fn is_digit(ch: char) -> bool {
ch.is_ascii_digit() ch.is_ascii_digit()
} }
pub fn expect_args(lineno: usize, args: &[AssemblyOperand], expected: usize) -> Result<(), Error> { pub fn expect_args(lineno: usize, args: &[AssemblyOperand], expected: usize) -> Result<(), ParserError> {
if args.len() == expected { if args.len() == expected {
Ok(()) Ok(())
} else { } else {
Err(Error::new(format!("error at line {}: expected {} args, but found {}", lineno, expected, args.len()))) Err(ParserError::new(format!("error at line {}: expected {} args, but found {}", lineno, expected, args.len())))
} }
} }
pub fn expect_label(lineno: usize, args: &[AssemblyOperand]) -> Result<String, Error> { pub fn expect_label(lineno: usize, args: &[AssemblyOperand]) -> Result<String, ParserError> {
expect_args(lineno, args, 1)?; expect_args(lineno, args, 1)?;
if let AssemblyOperand::Label(name) = &args[0] { if let AssemblyOperand::Label(name) = &args[0] {
Ok(name.clone()) Ok(name.clone())
} else { } else {
Err(Error::new(format!("error at line {}: expected a label, but found {:?}", lineno, args))) Err(ParserError::new(format!("error at line {}: expected a label, but found {:?}", lineno, args)))
} }
} }
pub fn expect_immediate(lineno: usize, operand: &AssemblyOperand) -> Result<usize, Error> { pub fn expect_immediate(lineno: usize, operand: &AssemblyOperand) -> Result<usize, ParserError> {
if let AssemblyOperand::Immediate(value) = operand { if let AssemblyOperand::Immediate(value) = operand {
Ok(*value) Ok(*value)
} else { } else {
Err(Error::new(format!("error at line {}: expected an immediate value, but found {:?}", lineno, operand))) Err(ParserError::new(format!("error at line {}: expected an immediate value, but found {:?}", lineno, operand)))
} }
} }

View File

@ -8,6 +8,6 @@ log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" } moa-host = { path = "../../libraries/host" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k", features = ["moa"] }
moa-peripherals-generic = { path = "../../peripherals/generic" } moa-peripherals-generic = { path = "../../peripherals/generic" }
moa-peripherals-motorola = { path = "../../peripherals/motorola" } moa-peripherals-motorola = { path = "../../peripherals/motorola" }

View File

@ -45,7 +45,7 @@ pub fn build_computie<H: Host>(host: &H, options: ComputieOptions) -> Result<Sys
system.add_addressable_device(0x00700000, Device::new(serial))?; system.add_addressable_device(0x00700000, Device::new(serial))?;
let mut cpu = M68k::from_type(M68kType::MC68010, options.frequency, system.bus.clone(), 0); let mut cpu = M68k::from_type(M68kType::MC68010, options.frequency);
//cpu.enable_tracing(); //cpu.enable_tracing();
//cpu.add_breakpoint(0x10781a); //cpu.add_breakpoint(0x10781a);
@ -83,7 +83,7 @@ pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
system.add_addressable_device(0x00700000, Device::new(serial))?; system.add_addressable_device(0x00700000, Device::new(serial))?;
let cpu = M68k::from_type(M68kType::MC68030, Frequency::from_hz(10_000_000), system.bus.clone(), 0); let cpu = M68k::from_type(M68kType::MC68030, Frequency::from_hz(10_000_000));
//cpu.enable_tracing(); //cpu.enable_tracing();
//cpu.add_breakpoint(0x10781a); //cpu.add_breakpoint(0x10781a);

View File

@ -10,6 +10,6 @@ moa-core = { path = "../../core" }
moa-signals = { path = "../../libraries/signals" } moa-signals = { path = "../../libraries/signals" }
moa-host = { path = "../../libraries/host" } moa-host = { path = "../../libraries/host" }
moa-peripherals-yamaha = { path = "../../peripherals/yamaha" } moa-peripherals-yamaha = { path = "../../peripherals/yamaha" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k", features = ["moa"] }
moa-z80 = { path = "../../cpus/z80" } moa-z80 = { path = "../../cpus/z80" }

View File

@ -94,7 +94,7 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
let vdp = Ym7101::new(host, interrupt, coproc_sn_sound)?; let vdp = Ym7101::new(host, interrupt, coproc_sn_sound)?;
system.add_peripheral("vdp", 0x00c00000, Device::new(vdp))?; system.add_peripheral("vdp", 0x00c00000, Device::new(vdp))?;
let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454), system.bus.clone(), 0); let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454));
system.add_interruptable_device("cpu", Device::new(cpu))?; system.add_interruptable_device("cpu", Device::new(cpu))?;
Ok(system) Ok(system)

View File

@ -9,6 +9,6 @@ femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" } moa-host = { path = "../../libraries/host" }
moa-signals = { path = "../../libraries/signals" } moa-signals = { path = "../../libraries/signals" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k", features = ["moa"] }
moa-peripherals-mos = { path = "../../peripherals/mos" } moa-peripherals-mos = { path = "../../peripherals/mos" }
moa-peripherals-zilog = { path = "../../peripherals/zilog" } moa-peripherals-zilog = { path = "../../peripherals/zilog" }

View File

@ -71,7 +71,7 @@ pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
system.add_addressable_device(0x00000000, Device::new(mainboard))?; system.add_addressable_device(0x00000000, Device::new(mainboard))?;
let mut cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_833_600), system.bus.clone(), 0); let mut cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_833_600));
//cpu.enable_tracing(); //cpu.enable_tracing();
//system.enable_debugging(); //system.enable_debugging();

View File

@ -7,7 +7,7 @@ edition = "2021"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../emulator/core" } moa-core = { path = "../../emulator/core" }
moa-m68k = { path = "../../emulator/cpus/m68k" } moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] }
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

@ -1,4 +1,4 @@
Last run on 2024-03-08 at commit 8b274f72ccf6f143e527cb95552f80deedc2fc64 Last run on 2024-03-13 at commit af1c660dc0682a62c123b1d7577f2ce2b5f3d8ad
ABCD.json.gz completed: 7993 passed, 72 FAILED ABCD.json.gz completed: 7993 passed, 72 FAILED
ADD.b.json.gz completed, all passed! ADD.b.json.gz completed, all passed!
@ -37,93 +37,3 @@ CMPA.l.json.gz completed, all passed!
CMPA.w.json.gz completed, all passed! CMPA.w.json.gz completed, all passed!
DBcc.json.gz completed, all passed! DBcc.json.gz completed, all passed!
DIVS.json.gz completed, all passed! DIVS.json.gz completed, all passed!
DIVU.json.gz completed: 8064 passed, 1 FAILED
EOR.b.json.gz completed, all passed!
EOR.l.json.gz completed: 7519 passed, 546 FAILED
EOR.w.json.gz completed: 7525 passed, 540 FAILED
EORItoCCR.json.gz completed, all passed!
EORItoSR.json.gz completed, all passed!
EXG.json.gz completed, all passed!
EXT.l.json.gz completed, all passed!
EXT.w.json.gz completed, all passed!
JMP.json.gz completed, all passed!
JSR.json.gz completed, all passed!
LEA.json.gz completed, all passed!
LINK.json.gz completed, all passed!
LSL.b.json.gz completed, all passed!
LSL.l.json.gz completed, all passed!
LSL.w.json.gz completed: 7910 passed, 155 FAILED
LSR.b.json.gz completed, all passed!
LSR.l.json.gz completed, all passed!
LSR.w.json.gz completed: 7909 passed, 156 FAILED
MOVE.b.json.gz completed, all passed!
MOVE.l.json.gz completed: 5827 passed, 2238 FAILED
MOVE.q.json.gz completed, all passed!
MOVE.w.json.gz completed: 5855 passed, 2210 FAILED
MOVEA.l.json.gz completed, all passed!
MOVEA.w.json.gz completed, all passed!
MOVEM.l.json.gz completed: 6035 passed, 2030 FAILED
MOVEM.w.json.gz completed: 6431 passed, 1634 FAILED
MOVEP.l.json.gz completed: 4036 passed, 4029 FAILED
MOVEP.w.json.gz completed: 4046 passed, 4019 FAILED
MOVEfromSR.json.gz completed: 6896 passed, 1169 FAILED
MOVEfromUSP.json.gz completed, all passed!
MOVEtoCCR.json.gz completed, all passed!
MOVEtoSR.json.gz completed, all passed!
MOVEtoUSP.json.gz completed, all passed!
MULS.json.gz completed, all passed!
MULU.json.gz completed, all passed!
NBCD.json.gz completed: 8037 passed, 28 FAILED
NEG.b.json.gz completed, all passed!
NEG.l.json.gz completed: 7552 passed, 513 FAILED
NEG.w.json.gz completed: 7531 passed, 534 FAILED
NEGX.b.json.gz completed, all passed!
NEGX.l.json.gz completed: 7520 passed, 545 FAILED
NEGX.w.json.gz completed: 7510 passed, 555 FAILED
NOP.json.gz completed, all passed!
NOT.b.json.gz completed, all passed!
NOT.l.json.gz completed: 7512 passed, 553 FAILED
NOT.w.json.gz completed: 7530 passed, 535 FAILED
OR.b.json.gz completed, all passed!
OR.l.json.gz completed: 7756 passed, 309 FAILED
OR.w.json.gz completed: 7765 passed, 300 FAILED
ORItoCCR.json.gz completed, all passed!
ORItoSR.json.gz completed, all passed!
PEA.json.gz completed, all passed!
RESET.json.gz completed, all passed!
ROL.b.json.gz completed, all passed!
ROL.l.json.gz completed, all passed!
ROL.w.json.gz completed: 7898 passed, 167 FAILED
ROR.b.json.gz completed, all passed!
ROR.l.json.gz completed, all passed!
ROR.w.json.gz completed: 7932 passed, 133 FAILED
ROXL.b.json.gz completed: 8032 passed, 33 FAILED
ROXL.l.json.gz completed: 8029 passed, 36 FAILED
ROXL.w.json.gz completed: 7890 passed, 175 FAILED
ROXR.b.json.gz completed: 8027 passed, 38 FAILED
ROXR.l.json.gz completed: 8039 passed, 26 FAILED
ROXR.w.json.gz completed: 7880 passed, 185 FAILED
RTE.json.gz completed, all passed!
RTR.json.gz completed, all passed!
RTS.json.gz completed, all passed!
SBCD.json.gz completed: 6809 passed, 1256 FAILED
SUB.b.json.gz completed, all passed!
SUB.l.json.gz completed: 7747 passed, 318 FAILED
SUB.w.json.gz completed: 7716 passed, 349 FAILED
SUBA.l.json.gz completed, all passed!
SUBA.w.json.gz completed, all passed!
SUBX.b.json.gz completed, all passed!
SUBX.l.json.gz completed: 5481 passed, 2584 FAILED
SUBX.w.json.gz completed, all passed!
SWAP.json.gz completed, all passed!
Scc.json.gz completed, all passed!
TAS.json.gz completed, all passed!
TRAP.json.gz completed, all passed!
TRAPV.json.gz completed, all passed!
TST.b.json.gz completed, all passed!
TST.l.json.gz completed, all passed!
TST.w.json.gz completed, all passed!
UNLINK.json.gz completed, all passed!
passed: 966037, failed: 34023, total 97%
completed in 13m 59s

View File

@ -1,4 +1,8 @@
* the next step is to factor all of moa_core into the moa.rs file, with BusPort being the last big piece
The functionality of BusPort should be integrated into memory.rs, to break up operations based on the cpu type
and then you won't need a value to hold on to port in a special bundle type. It can be borrowed in the step function from system.bus
* I want to push System, and BusPort into only the step function * I want to push System, and BusPort into only the step function
* first I need to make Decoder take &mut Addressable, and still function like it does * first I need to make Decoder take &mut Addressable, and still function like it does
* next I need to make Executor only access through a &mut Addressable * next I need to make Executor only access through a &mut Addressable