Separated moa-core dependency into an optional feature flag
This commit is contained in:
parent
af1c660dc0
commit
545f339fe2
|
@ -774,6 +774,8 @@ dependencies = [
|
|||
"log",
|
||||
"moa-common",
|
||||
"moa-core",
|
||||
"moa-debugger",
|
||||
"moa-host",
|
||||
"moa-m68k",
|
||||
"moa-peripherals-generic",
|
||||
"moa-peripherals-motorola",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"emulator/core",
|
||||
"emulator/frontends/common",
|
||||
|
@ -18,5 +19,6 @@ opt-level = 3
|
|||
|
||||
[profile.release]
|
||||
debug = true
|
||||
# TODO there are many overflow errors, which could be bugs
|
||||
#overflow-checks = true
|
||||
|
||||
|
|
|
@ -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,
|
||||
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
|
||||
|
||||
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
|
||||
|
|
|
@ -3,6 +3,8 @@ use std::fmt;
|
|||
use std::error::{Error as StdError};
|
||||
use moa_host::HostError;
|
||||
|
||||
use emulator_hal::bus;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum EmulatorErrorKind {
|
||||
Misc,
|
||||
|
|
|
@ -26,11 +26,11 @@ impl InterruptController {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check(&mut self) -> (bool, u8) {
|
||||
pub fn check(&mut self) -> (bool, u8, u8) {
|
||||
if self.highest > 0 {
|
||||
(true, self.highest)
|
||||
(true, self.highest, self.interrupts[self.highest as usize].1)
|
||||
} else {
|
||||
(false, 0)
|
||||
(false, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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::error::Error;
|
||||
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 emulator_hal::bus::{BusAccess};
|
||||
|
|
|
@ -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};
|
||||
|
||||
impl bus::Error for Error {}
|
||||
|
||||
impl BusAccess<u64, Instant> for BusPort {
|
||||
impl BusAccess<u64, Instant> for &mut dyn Addressable {
|
||||
type Error = 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())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ edition = "2021"
|
|||
log = "0.4"
|
||||
thiserror = "1.0"
|
||||
femtos = "0.1"
|
||||
moa-core = { path = "../../core" }
|
||||
moa-parsing = { path = "../../libraries/parsing" }
|
||||
emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" }
|
||||
|
||||
moa-core = { path = "../../core", optional = true }
|
||||
|
||||
[features]
|
||||
moa = []
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use moa_core::Error;
|
||||
use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser};
|
||||
use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser, ParserError};
|
||||
|
||||
use super::state::M68kType;
|
||||
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)]
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -114,7 +128,7 @@ impl M68kAssembler {
|
|||
|
||||
fn parse(&mut self, text: &str) -> Result<Vec<(usize, AssemblyLine)>, Error> {
|
||||
let mut parser = AssemblyParser::new(text);
|
||||
parser.parse()
|
||||
Ok(parser.parse()?)
|
||||
}
|
||||
|
||||
fn apply_relocations(&mut self) -> Result<(), Error> {
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
use femtos::Instant;
|
||||
use emulator_hal::bus::{self, BusAccess};
|
||||
|
||||
use moa_core::{System, Error, Address, Addressable, Debuggable};
|
||||
|
||||
use super::state::M68k;
|
||||
use super::state::{M68k, M68kError};
|
||||
use super::decode::M68kDecoder;
|
||||
use super::execute::M68kCycleExecutor;
|
||||
use super::memory::M68kAddress;
|
||||
|
@ -33,53 +31,11 @@ pub struct M68kDebugger {
|
|||
pub(crate) stack_tracer: StackTracer,
|
||||
}
|
||||
|
||||
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);
|
||||
// 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>
|
||||
impl<'a, Bus, BusError> M68kCycleExecutor<'a, Bus>
|
||||
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 {
|
||||
if *breakpoint == self.state.pc {
|
||||
if self.debugger.skip_breakpoint > 0 {
|
||||
|
@ -87,7 +43,7 @@ where
|
|||
return Ok(());
|
||||
} else {
|
||||
self.debugger.skip_breakpoint = 1;
|
||||
return Err(Error::breakpoint(format!("breakpoint reached: {:08x}", *breakpoint)));
|
||||
return Err(M68kError::Breakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
use femtos::Instant;
|
||||
use emulator_hal::bus::{self, BusAccess, Error as BusError};
|
||||
|
||||
use moa_core::{Error, Address, Addressable};
|
||||
use emulator_hal::bus::BusAccess;
|
||||
|
||||
use crate::state::{M68kType, M68kError, Exceptions};
|
||||
use crate::memory::{M68kBusPort, M68kAddress};
|
||||
|
@ -54,9 +52,9 @@ pub struct InstructionDecoding<'a, Bus>
|
|||
where
|
||||
Bus: BusAccess<M68kAddress, Instant>,
|
||||
{
|
||||
port: &'a mut Bus,
|
||||
memory: &'a mut M68kBusPort,
|
||||
decoder: &'a mut M68kDecoder,
|
||||
pub(crate) port: &'a mut Bus,
|
||||
pub(crate) memory: &'a mut M68kBusPort,
|
||||
pub(crate) decoder: &'a mut M68kDecoder,
|
||||
}
|
||||
|
||||
impl M68kDecoder {
|
||||
|
@ -109,7 +107,7 @@ impl M68kDecoder {
|
|||
println!("{:?}", err);
|
||||
match err {
|
||||
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>> =
|
||||
(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();
|
||||
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
|
||||
use femtos::{Instant, Duration};
|
||||
use emulator_hal::bus::{self, BusAccess, BusAdapter};
|
||||
use femtos::Instant;
|
||||
use emulator_hal::bus::BusAccess;
|
||||
|
||||
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable, BusPort};
|
||||
|
||||
use crate::state::{M68k, M68kType, M68kError, M68kState, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
|
||||
use crate::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority};
|
||||
use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress};
|
||||
use crate::decode::M68kDecoder;
|
||||
use crate::debugger::M68kDebugger;
|
||||
|
@ -37,7 +35,6 @@ pub enum Used {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct M68kCycle {
|
||||
|
||||
pub decoder: M68kDecoder,
|
||||
pub timing: M68kInstructionTiming,
|
||||
pub memory: M68kBusPort,
|
||||
|
@ -50,7 +47,7 @@ impl M68kCycle {
|
|||
Self {
|
||||
decoder: M68kDecoder::new(cputype, true, 0),
|
||||
timing: M68kInstructionTiming::new(cputype, data_width),
|
||||
memory: M68kBusPort::new(Instant::START),
|
||||
memory: M68kBusPort::default(),
|
||||
current_clock: Instant::START,
|
||||
}
|
||||
}
|
||||
|
@ -61,13 +58,16 @@ impl M68kCycle {
|
|||
Self {
|
||||
decoder: M68kDecoder::new(cpu.info.chip, is_supervisor, cpu.state.pc),
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
if cpu.stats.cycle_number > cpu.stats.last_update {
|
||||
cpu.stats.last_update = cpu.stats.last_update + 1_000_000;
|
||||
|
@ -76,25 +76,15 @@ impl M68kCycle {
|
|||
cpu.stats.last_time = now;
|
||||
}
|
||||
|
||||
let adapter = bus::BusAdapter::new(
|
||||
&mut cpu.port,
|
||||
translate_address,
|
||||
|err| err,
|
||||
);
|
||||
|
||||
M68kCycleExecutor {
|
||||
state: &mut cpu.state,
|
||||
port: adapter,
|
||||
port: bus,
|
||||
debugger: &mut cpu.debugger,
|
||||
cycle: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_address(addr_in: M68kAddress) -> u64 {
|
||||
addr_in as u64
|
||||
}
|
||||
|
||||
pub struct M68kCycleExecutor<'a, Bus>
|
||||
where
|
||||
Bus: BusAccess<M68kAddress, Instant>,
|
||||
|
@ -109,117 +99,23 @@ impl<'a, Bus> M68kCycleExecutor<'a, Bus>
|
|||
where
|
||||
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 {
|
||||
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>
|
||||
where
|
||||
Bus: BusAccess<M68kAddress, Instant>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn step(&mut self, system: &System) -> Result<ClockCycles, 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>> {
|
||||
pub fn step(&mut self) -> Result<(), M68kError<Bus::Error>> {
|
||||
match self.state.status {
|
||||
Status::Init => self.reset_cpu(),
|
||||
Status::Stopped => Err(M68kError::Halted),
|
||||
Status::Running => self.cycle_one(system),
|
||||
Status::Running => self.cycle_one(),
|
||||
}?;
|
||||
Ok(self.cycle.timing.calculate_clocks())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -232,15 +128,18 @@ where
|
|||
}
|
||||
|
||||
#[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.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(())
|
||||
}
|
||||
|
||||
/*
|
||||
#[inline]
|
||||
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError<Bus::Error>> {
|
||||
// TODO this could move somewhere else
|
||||
|
@ -270,11 +169,15 @@ where
|
|||
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
#[inline]
|
||||
pub fn check_pending_interrupts2(&mut self, interrupt: Option<(InterruptPriority, u8)>) -> Result<InterruptAcknowledge, M68kError> {
|
||||
self.state.pending_ipl = interrupt.unwrap_or(InterruptPriority::NoInterrupt);
|
||||
pub fn check_pending_interrupts(&mut self, interrupt: (bool, u8, u8)) -> Result<(InterruptPriority, Option<u8>), M68kError<Bus::Error>> {
|
||||
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 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;
|
||||
|
||||
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;
|
||||
let acknowledge = self.state.current_ipl;
|
||||
let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?;
|
||||
//let acknowledge = self.state.current_ipl;
|
||||
//let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?;
|
||||
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;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok((self.state.current_ipl, None))
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError<Bus::Error>> {
|
||||
log::debug!("{}: raising exception {}", DEV_NAME, number);
|
||||
|
@ -339,7 +241,7 @@ where
|
|||
self.push_word((ins_word & 0xFFF0) | extra_code)?;
|
||||
|
||||
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)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -364,12 +266,28 @@ where
|
|||
self.push_word(sr)?;
|
||||
|
||||
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)?;
|
||||
|
||||
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]
|
||||
pub fn decode_and_execute(&mut self) -> Result<(), M68kError<Bus::Error>> {
|
||||
self.decode_next()?;
|
||||
|
@ -967,7 +885,7 @@ where
|
|||
*self.get_stack_pointer_mut() -= 4;
|
||||
let sp = *self.get_stack_pointer_mut();
|
||||
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_stack_pointer_mut() = (sp as i32).wrapping_add(offset) as u32;
|
||||
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>> {
|
||||
for i in 0..8 {
|
||||
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);
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
for i in 0..8 {
|
||||
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);
|
||||
}
|
||||
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>> {
|
||||
for i in 0..8 {
|
||||
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();
|
||||
}
|
||||
mask >>= 1;
|
||||
|
@ -1135,7 +1053,7 @@ where
|
|||
for i in 0..8 {
|
||||
if (mask & 0x01) != 0 {
|
||||
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();
|
||||
}
|
||||
mask >>= 1;
|
||||
|
@ -1148,14 +1066,14 @@ where
|
|||
if (mask & 0x01) != 0 {
|
||||
let value = *self.get_a_reg_mut(i);
|
||||
addr -= size.in_bytes();
|
||||
self.set_address_sized(addr as Address, value, size)?;
|
||||
self.set_address_sized(addr, value, size)?;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
for i in (0..8).rev() {
|
||||
if (mask & 0x01) != 0 {
|
||||
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;
|
||||
}
|
||||
|
@ -1166,7 +1084,7 @@ where
|
|||
match dir {
|
||||
Direction::ToTarget => {
|
||||
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 {
|
||||
let byte = self.state.d_reg[dreg as usize] >> shift;
|
||||
self.set_address_sized(addr, byte, Size::Byte)?;
|
||||
|
@ -1176,7 +1094,7 @@ where
|
|||
},
|
||||
Direction::FromTarget => {
|
||||
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 {
|
||||
let byte = self.get_address_sized(addr, Size::Byte)?;
|
||||
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::IndirectAReg(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) => {
|
||||
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) => {
|
||||
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) => {
|
||||
let base_value = self.get_base_reg_value(base_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) => {
|
||||
let base_value = self.get_base_reg_value(base_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)?;
|
||||
self.get_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, size)
|
||||
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), size)
|
||||
},
|
||||
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
|
||||
let base_value = self.get_base_reg_value(base_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)?;
|
||||
self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size)
|
||||
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), size)
|
||||
},
|
||||
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) => {
|
||||
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) => {
|
||||
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) => {
|
||||
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) => {
|
||||
let base_value = self.get_base_reg_value(base_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) => {
|
||||
let base_value = self.get_base_reg_value(base_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)?;
|
||||
self.set_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, value, size)?;
|
||||
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), value, size)?;
|
||||
},
|
||||
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
|
||||
let base_value = self.get_base_reg_value(base_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)?;
|
||||
self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size)?;
|
||||
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), value, size)?;
|
||||
},
|
||||
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)),
|
||||
}
|
||||
|
@ -1640,13 +1558,13 @@ where
|
|||
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
|
||||
let base_value = self.get_base_reg_value(base_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)
|
||||
},
|
||||
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
|
||||
let base_value = self.get_base_reg_value(base_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)
|
||||
},
|
||||
Target::IndirectMemory(addr, _) => {
|
||||
|
@ -1684,44 +1602,44 @@ where
|
|||
*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();
|
||||
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();
|
||||
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>> {
|
||||
let is_supervisor = self.is_supervisor();
|
||||
*self.get_stack_pointer_mut() -= 2;
|
||||
let addr = *self.get_stack_pointer_mut();
|
||||
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?;
|
||||
self.port.write_beu16(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?;
|
||||
self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Word, value as u32)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_word(&mut self) -> Result<u16, M68kError<Bus::Error>> {
|
||||
let is_supervisor = self.is_supervisor();
|
||||
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.port.read_beu16(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?;
|
||||
let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Word)?;
|
||||
*self.get_stack_pointer_mut() += 2;
|
||||
Ok(value)
|
||||
Ok(value as u16)
|
||||
}
|
||||
|
||||
fn push_long(&mut self, value: u32) -> Result<(), M68kError<Bus::Error>> {
|
||||
let is_supervisor = self.is_supervisor();
|
||||
*self.get_stack_pointer_mut() -= 4;
|
||||
let addr = *self.get_stack_pointer_mut();
|
||||
self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?;
|
||||
self.port.write_beu32(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?;
|
||||
self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Long, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_long(&mut self) -> Result<u32, M68kError<Bus::Error>> {
|
||||
let is_supervisor = self.is_supervisor();
|
||||
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.port.read_beu32(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?;
|
||||
let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Long)?;
|
||||
*self.get_stack_pointer_mut() += 4;
|
||||
Ok(value)
|
||||
}
|
||||
|
|
|
@ -9,5 +9,8 @@ pub mod memory;
|
|||
pub mod timing;
|
||||
pub mod tests;
|
||||
|
||||
#[cfg(feature = "moa")]
|
||||
pub mod moa;
|
||||
|
||||
pub use self::state::{M68k, M68kType, M68kError};
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
use core::cmp;
|
||||
use core::fmt::Write;
|
||||
use femtos::Instant;
|
||||
use emulator_hal::bus::{BusAccess};
|
||||
use emulator_hal::bus::BusAccess;
|
||||
|
||||
use moa_core::{Error, Address, Addressable};
|
||||
|
||||
use crate::state::{M68k, M68kError, Exceptions};
|
||||
use crate::state::{M68k, M68kError, CpuInfo, Exceptions};
|
||||
use crate::instructions::Size;
|
||||
|
||||
#[repr(u8)]
|
||||
|
@ -102,7 +102,8 @@ impl MemoryRequest {
|
|||
}
|
||||
|
||||
//pub type M68kAddress = (FunctionCode, u32);
|
||||
pub type M68kAddress = u64;
|
||||
pub type M68kAddress = u32;
|
||||
pub type M68kAddressSpace = (FunctionCode, u32);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InstructionRequest {
|
||||
|
@ -113,6 +114,8 @@ pub struct InstructionRequest {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct M68kBusPort {
|
||||
pub request: MemoryRequest,
|
||||
pub data_bytewidth: usize,
|
||||
pub address_mask: u32,
|
||||
pub cycle_start_clock: Instant,
|
||||
pub current_clock: Instant,
|
||||
}
|
||||
|
@ -126,6 +129,8 @@ impl Default for M68kBusPort {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
request: Default::default(),
|
||||
data_bytewidth: 32 / 8,
|
||||
address_mask: 0xFFFF_FFFF,
|
||||
cycle_start_clock: Instant::START,
|
||||
current_clock: Instant::START,
|
||||
}
|
||||
|
@ -133,36 +138,82 @@ impl Default for M68kBusPort {
|
|||
}
|
||||
|
||||
impl M68kBusPort {
|
||||
pub fn new(clock: Instant) -> Self {
|
||||
pub fn from_info(info: &CpuInfo, clock: Instant) -> Self {
|
||||
Self {
|
||||
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,
|
||||
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
|
||||
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
|
||||
{
|
||||
self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?;
|
||||
Ok(match 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))?)
|
||||
self.read_sized(port, addr, size)
|
||||
}
|
||||
|
||||
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
|
||||
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
|
||||
{
|
||||
self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?;
|
||||
Ok(match size {
|
||||
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))?)
|
||||
self.write_sized(port, addr, size, value)
|
||||
}
|
||||
|
||||
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>,
|
||||
{
|
||||
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>>
|
||||
|
@ -178,7 +229,7 @@ impl M68kBusPort {
|
|||
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
|
||||
{
|
||||
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>> {
|
||||
|
@ -197,14 +248,6 @@ impl M68kBusPort {
|
|||
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>> {
|
||||
|
@ -215,22 +258,31 @@ fn validate_address<BusError>(addr: u32) -> Result<u32, M68kError<BusError>> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl BusType for M68kBusPort {
|
||||
type Instant = Instant;
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl BusAccess<u32> for M68kBusPort {
|
||||
fn read(&mut self, now: Self::Instant, addr: Address, data: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.
|
||||
}
|
||||
|
||||
fn write(&mut self, now: Self::Instant, addr: Address, data: &[u8]) -> Result<usize, Self::Error> {
|
||||
pub fn dump_memory<Bus, Address, Instant>(bus: &mut Bus, clock: Instant, addr: Address, count: Address)
|
||||
where
|
||||
Bus: BusAccess<Address, Instant>,
|
||||
Address: From<u32> + Into<u32> + 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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
pub(crate) struct TargetAccess {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,8 @@
|
|||
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use femtos::{Instant, Frequency};
|
||||
|
||||
use moa_core::{Address, Bus, BusPort};
|
||||
use core::fmt::{self, Write};
|
||||
use femtos::{Duration, Frequency};
|
||||
|
||||
use crate::debugger::M68kDebugger;
|
||||
use crate::memory::M68kBusPort;
|
||||
use crate::instructions::Target;
|
||||
use crate::execute::M68kCycle;
|
||||
|
||||
|
@ -82,7 +77,7 @@ impl From<M68kType> for CoreType {
|
|||
}
|
||||
|
||||
impl CpuInfo {
|
||||
fn from(cputype: M68kType, frequency: Frequency) -> Self {
|
||||
pub fn from_type(cputype: M68kType, frequency: Frequency) -> Self {
|
||||
match cputype {
|
||||
M68kType::MC68008 => Self {
|
||||
chip: cputype,
|
||||
|
@ -218,7 +213,6 @@ pub struct M68k {
|
|||
pub info: CpuInfo,
|
||||
pub state: M68kState,
|
||||
pub debugger: M68kDebugger,
|
||||
pub port: BusPort,
|
||||
pub stats: M68kStatistics,
|
||||
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 {
|
||||
pub fn new(info: CpuInfo, port: BusPort) -> M68k {
|
||||
pub fn new(info: CpuInfo) -> Self {
|
||||
M68k {
|
||||
info,
|
||||
state: M68kState::default(),
|
||||
debugger: M68kDebugger::default(),
|
||||
port,
|
||||
stats: Default::default(),
|
||||
cycle: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_type(cputype: M68kType, frequency: Frequency, bus: Rc<RefCell<Bus>>, addr_offset: Address) -> Self {
|
||||
let info = CpuInfo::from(cputype, frequency);
|
||||
Self::new(info, BusPort::new(addr_offset, info.address_width as u8, info.data_width as u8, bus))
|
||||
pub fn from_type(cputype: M68kType, freq: Frequency) -> Self {
|
||||
Self::new(CpuInfo::from_type(cputype, freq))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,28 +4,36 @@ mod decode_unit_tests {
|
|||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
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::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister};
|
||||
use crate::decode::M68kDecoder;
|
||||
use crate::decode::{M68kDecoder, InstructionDecoding};
|
||||
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 mem = MemoryBlock::new(vec![0; 0x0000100]);
|
||||
bus.borrow_mut().insert(0x00000000, Device::new(mem));
|
||||
|
||||
let port = if cputype <= M68kType::MC68010 {
|
||||
M68kBusPort::new(BusPort::new(0, 24, 16, bus))
|
||||
} else {
|
||||
M68kBusPort::new(BusPort::new(0, 32, 32, bus))
|
||||
let mut bus = 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 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);
|
||||
(port, decoder)
|
||||
decoding
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -34,216 +42,216 @@ mod decode_unit_tests {
|
|||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 offset = -8;
|
||||
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
|
||||
|
||||
port.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, brief_extension).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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
|
||||
port.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_beu16(Instant::START, INIT_ADDR, brief_extension).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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 offset = -1843235 as i32;
|
||||
let brief_extension = 0xF3B0;
|
||||
|
||||
port.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_beu16(Instant::START, INIT_ADDR, brief_extension).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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 offset = -1843235 as i32;
|
||||
let brief_extension = 0xF370;
|
||||
|
||||
port.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_beu16(Instant::START, INIT_ADDR, brief_extension).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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 offset = -8;
|
||||
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
|
||||
|
||||
port.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, brief_extension).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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
|
||||
port.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_beu16(Instant::START, INIT_ADDR, brief_extension).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));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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));
|
||||
}
|
||||
}
|
||||
|
@ -252,18 +260,20 @@ mod decode_unit_tests {
|
|||
#[cfg(test)]
|
||||
mod execute_unit_tests {
|
||||
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::execute::{Used, M68kCycle, M68kCycleExecutor};
|
||||
use crate::instructions::{Instruction, Target, Size};
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
const INIT_STACK: u32 = 0x00002000;
|
||||
const INIT_ADDR: u32 = 0x00000010;
|
||||
|
||||
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
|
||||
where
|
||||
F: FnMut(M68kCycleExecutor),
|
||||
F: FnMut(M68kCycleExecutor<&mut BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error>>),
|
||||
{
|
||||
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, 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();
|
||||
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);
|
||||
assert_eq!(executor.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK as u32);
|
||||
|
@ -322,7 +340,7 @@ mod execute_unit_tests {
|
|||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
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;
|
||||
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||
|
@ -336,7 +354,7 @@ mod execute_unit_tests {
|
|||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
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;
|
||||
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||
|
@ -351,7 +369,7 @@ mod execute_unit_tests {
|
|||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
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;
|
||||
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||
|
@ -374,5 +392,3 @@ mod execute_unit_tests {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
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::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
|
||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
||||
//cpu.reset_cpu().unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
||||
//assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
//assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
||||
|
||||
let cycle = M68kCycle::new(&cpu, system.clock);
|
||||
assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
|
||||
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
//assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
|
||||
//assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
(cpu, cycle, system)
|
||||
}
|
||||
|
||||
|
@ -97,14 +98,24 @@ fn load_memory(system: &System, data: &[u16]) {
|
|||
fn run_decode_test(case: &TestCase) {
|
||||
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
|
||||
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 {
|
||||
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();
|
||||
assert_eq!(executor.cycle.decoder.instruction, ins.clone());
|
||||
},
|
||||
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();
|
||||
println!("{:?}", executor.cycle.decoder.instruction);
|
||||
assert!(next.is_err());
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
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::state::M68kState;
|
||||
|
@ -37,7 +38,7 @@ struct TestCase {
|
|||
|
||||
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
|
||||
where
|
||||
F: FnMut(M68kCycleExecutor, System),
|
||||
F: FnMut(M68kCycleExecutor<&mut BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error>>, &System),
|
||||
{
|
||||
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, 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);
|
||||
cpu.step(&system).unwrap();
|
||||
|
||||
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.ssp, INIT_STACK as u32);
|
||||
assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP);
|
||||
|
||||
test_func(executor, system)
|
||||
test_func(executor, &system)
|
||||
}
|
||||
|
||||
fn build_state(state: &TestState) -> M68kState {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::BusAdapter;
|
||||
|
||||
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> {
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
timing.add_instruction(&executor.cycle.decoder.instruction);
|
||||
let result = timing.calculate_clocks(false, 1);
|
||||
let result = timing.calculate_clocks();
|
||||
let expected = match case.cpu {
|
||||
M68kType::MC68000 => case.timing.0,
|
||||
M68kType::MC68010 => case.timing.1,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::BusAdapter;
|
||||
|
||||
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> {
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
timing.add_instruction(&executor.cycle.decoder.instruction);
|
||||
let result = timing.calculate_clocks(false, 1);
|
||||
let result = timing.calculate_clocks();
|
||||
let expected = match case.cpu {
|
||||
M68kType::MC68000 => case.timing.0,
|
||||
M68kType::MC68010 => case.timing.1,
|
||||
|
|
|
@ -9,10 +9,15 @@ use nix::fcntl::OFlag;
|
|||
use nix::pty::{self, PtyMaster};
|
||||
use nix::fcntl::{fcntl, FcntlArg};
|
||||
|
||||
use moa_core::Error;
|
||||
use moa_core::host::Tty;
|
||||
use moa_host::Tty;
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum SimplePtyError {
|
||||
Open,
|
||||
PtsName,
|
||||
}
|
||||
|
||||
pub struct SimplePty {
|
||||
pub name: String,
|
||||
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| {
|
||||
pty::grantpt(&pty)?;
|
||||
pty::unlockpt(&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 (output_tx, output_rx) = mpsc::channel();
|
||||
let shared = SimplePty::new(name.clone(), input_rx, output_tx);
|
||||
|
|
|
@ -11,10 +11,12 @@ simple_logger = "^2"
|
|||
femtos = "0.1"
|
||||
|
||||
moa-core = { path = "../../core" }
|
||||
moa-host = { path = "../../libraries/host" }
|
||||
moa-common = { path = "../common", features = ["tty"] }
|
||||
|
||||
moa-debugger = { path = "../../libraries/debugger" }
|
||||
moa-systems-genesis = { path = "../../systems/genesis" }
|
||||
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-motorola = { path = "../../peripherals/motorola" }
|
||||
|
|
|
@ -3,8 +3,9 @@ use clap::{Command, Arg, ArgAction, ArgMatches};
|
|||
use std::io::{self, Write};
|
||||
use femtos::Duration;
|
||||
|
||||
use moa_core::{Error, System, DebugControl, Debugger};
|
||||
use moa_core::host::{Host, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender};
|
||||
use moa_core::{Error, System};
|
||||
use moa_debugger::{Debugger, DebugControl};
|
||||
use moa_host::{Host, HostError, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender};
|
||||
|
||||
pub struct ConsoleFrontend;
|
||||
|
||||
|
@ -13,7 +14,7 @@ impl Host for ConsoleFrontend {
|
|||
|
||||
fn add_pty(&self) -> Result<Box<dyn Tty>, HostError<Self::Error>> {
|
||||
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>> {
|
||||
|
|
|
@ -2,8 +2,14 @@
|
|||
use std::str::Chars;
|
||||
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)]
|
||||
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![];
|
||||
loop {
|
||||
let lineno = self.lexer.get_next_lineno();
|
||||
|
@ -47,7 +53,7 @@ impl<'input> AssemblyParser<'input> {
|
|||
Ok(output)
|
||||
}
|
||||
|
||||
fn parse_line(&mut self) -> Result<Option<AssemblyLine>, Error> {
|
||||
fn parse_line(&mut self) -> Result<Option<AssemblyLine>, ParserError> {
|
||||
let token = loop {
|
||||
match self.lexer.get_next() {
|
||||
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))
|
||||
}
|
||||
|
||||
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![];
|
||||
|
||||
// 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![];
|
||||
|
||||
// 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()?;
|
||||
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") {
|
||||
(16, s)
|
||||
} 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)
|
||||
};
|
||||
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()
|
||||
}
|
||||
|
||||
pub fn expect_next(&mut self) -> Result<String, Error> {
|
||||
self.get_next().ok_or_else(|| Error::new(format!("unexpected end of input at line {}", self.lineno)))
|
||||
pub fn expect_next(&mut self) -> Result<String, ParserError> {
|
||||
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()?;
|
||||
if token == expected {
|
||||
Ok(())
|
||||
} 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();
|
||||
if token.is_none() || token.as_ref().unwrap() == "\n" {
|
||||
Ok(())
|
||||
} 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()
|
||||
}
|
||||
|
||||
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 {
|
||||
Ok(())
|
||||
} 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)?;
|
||||
if let AssemblyOperand::Label(name) = &args[0] {
|
||||
Ok(name.clone())
|
||||
} 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 {
|
||||
Ok(*value)
|
||||
} 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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,6 @@ log = "0.4"
|
|||
femtos = "0.1"
|
||||
moa-core = { path = "../../core" }
|
||||
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-motorola = { path = "../../peripherals/motorola" }
|
||||
|
|
|
@ -45,7 +45,7 @@ pub fn build_computie<H: Host>(host: &H, options: ComputieOptions) -> Result<Sys
|
|||
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.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))?;
|
||||
|
||||
|
||||
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.add_breakpoint(0x10781a);
|
||||
|
|
|
@ -10,6 +10,6 @@ moa-core = { path = "../../core" }
|
|||
moa-signals = { path = "../../libraries/signals" }
|
||||
moa-host = { path = "../../libraries/host" }
|
||||
moa-peripherals-yamaha = { path = "../../peripherals/yamaha" }
|
||||
moa-m68k = { path = "../../cpus/m68k" }
|
||||
moa-m68k = { path = "../../cpus/m68k", features = ["moa"] }
|
||||
moa-z80 = { path = "../../cpus/z80" }
|
||||
|
||||
|
|
|
@ -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)?;
|
||||
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))?;
|
||||
|
||||
Ok(system)
|
||||
|
|
|
@ -9,6 +9,6 @@ femtos = "0.1"
|
|||
moa-core = { path = "../../core" }
|
||||
moa-host = { path = "../../libraries/host" }
|
||||
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-zilog = { path = "../../peripherals/zilog" }
|
||||
|
|
|
@ -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))?;
|
||||
|
||||
|
||||
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();
|
||||
//system.enable_debugging();
|
||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||
femtos = "0.1"
|
||||
|
||||
moa-core = { path = "../../emulator/core" }
|
||||
moa-m68k = { path = "../../emulator/cpus/m68k" }
|
||||
moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
|
|
@ -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
|
||||
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!
|
||||
DBcc.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
|
||||
|
|
4
todo.txt
4
todo.txt
|
@ -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
|
||||
* 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
|
||||
|
|
Loading…
Reference in New Issue