mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-26 22:50:25 +00:00
Refactoring m68k to use a temporary cycle struct
I'm trying to extract the memory/bus interface, and pass it in at the start of each cycle instead of having the BusPort permanently embedded, which will allow migrating to emulator-hal. The functional way would be argument drilling; passing an extra argument to each function in the entire execution core. The problem is that it's messy, so a solution that is still functional is to implement all of the execution logic on a newtype that contains a reference to the mutable state and the owned cycle data, and at the end of the cycle, decompose the M68kCycleGuard that holds the reference, and keep the cycle data for debugging purposes.
This commit is contained in:
parent
83289d6b8e
commit
cff6a48cc7
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -417,6 +417,10 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "emulator-hal"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@ -763,6 +767,7 @@ dependencies = [
|
|||||||
name = "moa-core"
|
name = "moa-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emulator-hal",
|
||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-host",
|
"moa-host",
|
||||||
@ -788,6 +793,7 @@ dependencies = [
|
|||||||
name = "moa-m68k"
|
name = "moa-m68k"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emulator-hal",
|
||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
@ -935,10 +941,12 @@ dependencies = [
|
|||||||
name = "moa-z80"
|
name = "moa-z80"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emulator-hal",
|
||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
"moa-signals",
|
"moa-signals",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13,6 +13,9 @@ exclude = [
|
|||||||
]
|
]
|
||||||
default-members = ["emulator/frontends/minifb"]
|
default-members = ["emulator/frontends/minifb"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
#overflow-checks = true
|
#overflow-checks = true
|
||||||
|
@ -8,3 +8,4 @@ log = "0.4"
|
|||||||
femtos = "0.1"
|
femtos = "0.1"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
moa-host = { path = "../libraries/host" }
|
moa-host = { path = "../libraries/host" }
|
||||||
|
emulator-hal = { path = "/media/work/projects/emulator-hal/emulator-hal" }
|
||||||
|
@ -14,3 +14,5 @@ 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};
|
||||||
pub use crate::system::System;
|
pub use crate::system::System;
|
||||||
|
|
||||||
|
pub use emulator_hal::bus::{BusAccess};
|
||||||
|
|
||||||
|
@ -210,3 +210,26 @@ impl NextStep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
use emulator_hal::bus::{BusType, BusAccess};
|
||||||
|
|
||||||
|
impl BusType for System {
|
||||||
|
type Address = u64;
|
||||||
|
type Error = Error;
|
||||||
|
type Instant = Instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BusAccess for System {
|
||||||
|
fn read(&mut self, _now: Instant, addr: u64, data: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
let addr = addr as usize;
|
||||||
|
data.copy_from_slice(&self.0[addr..addr + data.len()]);
|
||||||
|
Ok(data.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, _now: Instant, addr: u64, data: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
let addr = addr as usize;
|
||||||
|
self.0[addr..addr + data.len()].copy_from_slice(data);
|
||||||
|
Ok(data.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -9,3 +9,4 @@ thiserror = "1.0"
|
|||||||
femtos = "0.1"
|
femtos = "0.1"
|
||||||
moa-core = { path = "../../core" }
|
moa-core = { path = "../../core" }
|
||||||
moa-parsing = { path = "../../libraries/parsing" }
|
moa-parsing = { path = "../../libraries/parsing" }
|
||||||
|
emulator-hal = { path = "/media/work/projects/emulator-hal/emulator-hal" }
|
||||||
|
@ -3,6 +3,7 @@ use moa_core::{System, Error, Address, Addressable, Debuggable};
|
|||||||
|
|
||||||
use super::state::M68k;
|
use super::state::M68k;
|
||||||
use super::decode::M68kDecoder;
|
use super::decode::M68kDecoder;
|
||||||
|
use super::execute::M68kCycleGuard;
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct StackTracer {
|
pub struct StackTracer {
|
||||||
@ -40,9 +41,10 @@ impl Debuggable for M68k {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
|
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
|
||||||
let _ = self.decoder.decode_at(&mut self.port, true, self.state.pc);
|
// TODO this is called by the debugger, but should be called some other way
|
||||||
self.decoder.dump_decoded(&mut self.port);
|
//let _ = self.decoder.decode_at(&mut self.port, true, self.state.pc);
|
||||||
self.dump_state();
|
//self.decoder.dump_decoded(&mut self.port);
|
||||||
|
//self.dump_state();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +70,7 @@ impl Debuggable for M68k {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl M68k {
|
impl<'a> M68kCycleGuard<'a> {
|
||||||
pub fn check_breakpoints(&mut self) -> Result<(), Error> {
|
pub fn check_breakpoints(&mut self) -> Result<(), Error> {
|
||||||
for breakpoint in &self.debugger.breakpoints {
|
for breakpoint in &self.debugger.breakpoints {
|
||||||
if *breakpoint == self.state.pc {
|
if *breakpoint == self.state.pc {
|
||||||
|
@ -37,7 +37,7 @@ const OPCG_SHIFT: u8 = 0xE;
|
|||||||
const OPCG_FLINE: u8 = 0xF;
|
const OPCG_FLINE: u8 = 0xF;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct M68kDecoder {
|
pub struct M68kDecoder {
|
||||||
pub cputype: M68kType,
|
pub cputype: M68kType,
|
||||||
pub is_supervisor: bool,
|
pub is_supervisor: bool,
|
||||||
@ -66,45 +66,45 @@ impl M68kDecoder {
|
|||||||
self.end = start;
|
self.end = start;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_at(&mut self, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> {
|
pub fn decode_at(&mut self, bus: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> {
|
||||||
self.init(is_supervisor, start);
|
self.init(is_supervisor, start);
|
||||||
self.instruction = self.decode_next(memory)?;
|
self.instruction = self.decode_next(bus)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_next(&mut self, memory: &mut M68kBusPort) -> Result<Instruction, M68kError> {
|
pub fn decode_next(&mut self, bus: &mut M68kBusPort) -> Result<Instruction, M68kError> {
|
||||||
let ins = self.read_instruction_word(memory)?;
|
let ins = self.read_instruction_word(bus)?;
|
||||||
self.instruction_word = ins;
|
self.instruction_word = ins;
|
||||||
|
|
||||||
match ((ins & 0xF000) >> 12) as u8 {
|
match ((ins & 0xF000) >> 12) as u8 {
|
||||||
OPCG_BIT_OPS => self.decode_group_bit_ops(memory, ins),
|
OPCG_BIT_OPS => self.decode_group_bit_ops(bus, ins),
|
||||||
OPCG_MOVE_BYTE => self.decode_group_move_byte(memory, ins),
|
OPCG_MOVE_BYTE => self.decode_group_move_byte(bus, ins),
|
||||||
OPCG_MOVE_LONG => self.decode_group_move_long(memory, ins),
|
OPCG_MOVE_LONG => self.decode_group_move_long(bus, ins),
|
||||||
OPCG_MOVE_WORD => self.decode_group_move_word(memory, ins),
|
OPCG_MOVE_WORD => self.decode_group_move_word(bus, ins),
|
||||||
OPCG_MISC => self.decode_group_misc(memory, ins),
|
OPCG_MISC => self.decode_group_misc(bus, ins),
|
||||||
OPCG_ADDQ_SUBQ => self.decode_group_addq_subq(memory, ins),
|
OPCG_ADDQ_SUBQ => self.decode_group_addq_subq(bus, ins),
|
||||||
OPCG_BRANCH => self.decode_group_branch(memory, ins),
|
OPCG_BRANCH => self.decode_group_branch(bus, ins),
|
||||||
OPCG_MOVEQ => self.decode_group_moveq(memory, ins),
|
OPCG_MOVEQ => self.decode_group_moveq(bus, ins),
|
||||||
OPCG_DIV_OR => self.decode_group_div_or(memory, ins),
|
OPCG_DIV_OR => self.decode_group_div_or(bus, ins),
|
||||||
OPCG_SUB => self.decode_group_sub(memory, ins),
|
OPCG_SUB => self.decode_group_sub(bus, ins),
|
||||||
OPCG_ALINE => Ok(Instruction::UnimplementedA(ins)),
|
OPCG_ALINE => Ok(Instruction::UnimplementedA(ins)),
|
||||||
OPCG_CMP_EOR => self.decode_group_cmp_eor(memory, ins),
|
OPCG_CMP_EOR => self.decode_group_cmp_eor(bus, ins),
|
||||||
OPCG_MUL_AND => self.decode_group_mul_and(memory, ins),
|
OPCG_MUL_AND => self.decode_group_mul_and(bus, ins),
|
||||||
OPCG_ADD => self.decode_group_add(memory, ins),
|
OPCG_ADD => self.decode_group_add(bus, ins),
|
||||||
OPCG_SHIFT => self.decode_group_shift(memory, ins),
|
OPCG_SHIFT => self.decode_group_shift(bus, ins),
|
||||||
OPCG_FLINE => Ok(Instruction::UnimplementedF(ins)),
|
OPCG_FLINE => Ok(Instruction::UnimplementedF(ins)),
|
||||||
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_bit_ops(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_bit_ops(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let optype = (ins & 0x0F00) >> 8;
|
let optype = (ins & 0x0F00) >> 8;
|
||||||
|
|
||||||
if (ins & 0x13F) == 0x03C {
|
if (ins & 0x13F) == 0x03C {
|
||||||
match (ins & 0x00C0) >> 6 {
|
match (ins & 0x00C0) >> 6 {
|
||||||
0b00 => {
|
0b00 => {
|
||||||
let data = self.read_instruction_word(memory)?;
|
let data = self.read_instruction_word(bus)?;
|
||||||
match optype {
|
match optype {
|
||||||
0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
|
0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
|
||||||
0b0010 => Ok(Instruction::ANDtoCCR(data as u8)),
|
0b0010 => Ok(Instruction::ANDtoCCR(data as u8)),
|
||||||
@ -113,7 +113,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
0b01 => {
|
0b01 => {
|
||||||
let data = self.read_instruction_word(memory)?;
|
let data = self.read_instruction_word(bus)?;
|
||||||
match optype {
|
match optype {
|
||||||
0b0000 => Ok(Instruction::ORtoSR(data)),
|
0b0000 => Ok(Instruction::ORtoSR(data)),
|
||||||
0b0010 => Ok(Instruction::ANDtoSR(data)),
|
0b0010 => Ok(Instruction::ANDtoSR(data)),
|
||||||
@ -128,16 +128,16 @@ impl M68kDecoder {
|
|||||||
let areg = get_low_reg(ins);
|
let areg = get_low_reg(ins);
|
||||||
let dir = if (ins & 0x0080) == 0 { Direction::FromTarget } else { Direction::ToTarget };
|
let dir = if (ins & 0x0080) == 0 { Direction::FromTarget } else { Direction::ToTarget };
|
||||||
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
|
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
|
||||||
let offset = self.read_instruction_word(memory)? as i16;
|
let offset = self.read_instruction_word(bus)? as i16;
|
||||||
Ok(Instruction::MOVEP(dreg, areg, offset, size, dir))
|
Ok(Instruction::MOVEP(dreg, areg, offset, size, dir))
|
||||||
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
|
} else if (ins & 0x0100) == 0x0100 || (ins & 0x0F00) == 0x0800 {
|
||||||
let bitnum = if (ins & 0x0100) == 0x0100 {
|
let bitnum = if (ins & 0x0100) == 0x0100 {
|
||||||
Target::DirectDReg(get_high_reg(ins))
|
Target::DirectDReg(get_high_reg(ins))
|
||||||
} else {
|
} else {
|
||||||
Target::Immediate(self.read_instruction_word(memory)? as u32)
|
Target::Immediate(self.read_instruction_word(bus)? as u32)
|
||||||
};
|
};
|
||||||
|
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
|
||||||
let size = match target {
|
let size = match target {
|
||||||
Target::DirectAReg(_) | Target::DirectDReg(_) => Size::Long,
|
Target::DirectAReg(_) | Target::DirectDReg(_) => Size::Long,
|
||||||
_ => Size::Byte,
|
_ => Size::Byte,
|
||||||
@ -153,12 +153,12 @@ impl M68kDecoder {
|
|||||||
} else {
|
} else {
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
let data = match size {
|
let data = match size {
|
||||||
Some(Size::Byte) => self.read_instruction_word(memory)? as u32 & 0xFF,
|
Some(Size::Byte) => self.read_instruction_word(bus)? as u32 & 0xFF,
|
||||||
Some(Size::Word) => self.read_instruction_word(memory)? as u32,
|
Some(Size::Word) => self.read_instruction_word(bus)? as u32,
|
||||||
Some(Size::Long) => self.read_instruction_long(memory)?,
|
Some(Size::Long) => self.read_instruction_long(bus)?,
|
||||||
None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
||||||
};
|
};
|
||||||
let target = self.decode_lower_effective_address(memory, ins, size)?;
|
let target = self.decode_lower_effective_address(bus, ins, size)?;
|
||||||
|
|
||||||
match optype {
|
match optype {
|
||||||
0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())),
|
0b0000 => Ok(Instruction::OR(Target::Immediate(data), target, size.unwrap())),
|
||||||
@ -173,16 +173,16 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_move_byte(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_move_byte(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let src = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
|
let src = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
|
||||||
let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Byte))?;
|
let dest = self.decode_upper_effective_address(bus, ins, Some(Size::Byte))?;
|
||||||
Ok(Instruction::MOVE(src, dest, Size::Byte))
|
Ok(Instruction::MOVE(src, dest, Size::Byte))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_move_long(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_move_long(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let src = self.decode_lower_effective_address(memory, ins, Some(Size::Long))?;
|
let src = self.decode_lower_effective_address(bus, ins, Some(Size::Long))?;
|
||||||
let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Long))?;
|
let dest = self.decode_upper_effective_address(bus, ins, Some(Size::Long))?;
|
||||||
if let Target::DirectAReg(reg) = dest {
|
if let Target::DirectAReg(reg) = dest {
|
||||||
Ok(Instruction::MOVEA(src, reg, Size::Long))
|
Ok(Instruction::MOVEA(src, reg, Size::Long))
|
||||||
} else {
|
} else {
|
||||||
@ -191,9 +191,9 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_move_word(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_move_word(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let src = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let src = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Word))?;
|
let dest = self.decode_upper_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
if let Target::DirectAReg(reg) = dest {
|
if let Target::DirectAReg(reg) = dest {
|
||||||
Ok(Instruction::MOVEA(src, reg, Size::Word))
|
Ok(Instruction::MOVEA(src, reg, Size::Word))
|
||||||
} else {
|
} else {
|
||||||
@ -202,7 +202,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_misc(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_misc(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let ins_0f00 = ins & 0xF00;
|
let ins_0f00 = ins & 0xF00;
|
||||||
let ins_00f0 = ins & 0x0F0;
|
let ins_00f0 = ins & 0x0F0;
|
||||||
|
|
||||||
@ -217,31 +217,31 @@ impl M68kDecoder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let reg = get_high_reg(ins);
|
let reg = get_high_reg(ins);
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
Ok(Instruction::CHK(target, reg, size))
|
Ok(Instruction::CHK(target, reg, size))
|
||||||
} else {
|
} else {
|
||||||
let src = self.decode_lower_effective_address(memory, ins, None)?;
|
let src = self.decode_lower_effective_address(bus, ins, None)?;
|
||||||
let dest = get_high_reg(ins);
|
let dest = get_high_reg(ins);
|
||||||
Ok(Instruction::LEA(src, dest))
|
Ok(Instruction::LEA(src, dest))
|
||||||
}
|
}
|
||||||
} else if (ins & 0xB80) == 0x880 && (ins & 0x038) != 0 {
|
} else if (ins & 0xB80) == 0x880 && (ins & 0x038) != 0 {
|
||||||
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
|
let size = if (ins & 0x0040) == 0 { Size::Word } else { Size::Long };
|
||||||
let data = self.read_instruction_word(memory)?;
|
let data = self.read_instruction_word(bus)?;
|
||||||
let target = self.decode_lower_effective_address(memory, ins, None)?;
|
let target = self.decode_lower_effective_address(bus, ins, None)?;
|
||||||
let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget };
|
let dir = if (ins & 0x0400) == 0 { Direction::ToTarget } else { Direction::FromTarget };
|
||||||
Ok(Instruction::MOVEM(target, size, dir, data))
|
Ok(Instruction::MOVEM(target, size, dir, data))
|
||||||
} else if (ins & 0xF80) == 0xC00 && self.cputype >= M68kType::MC68020 {
|
} else if (ins & 0xF80) == 0xC00 && self.cputype >= M68kType::MC68020 {
|
||||||
let extension = self.read_instruction_word(memory)?;
|
let extension = self.read_instruction_word(bus)?;
|
||||||
let reg_h = if (extension & 0x0400) != 0 { Some(get_low_reg(ins)) } else { None };
|
let reg_h = if (extension & 0x0400) != 0 { Some(get_low_reg(ins)) } else { None };
|
||||||
let reg_l = ((extension & 0x7000) >> 12) as u8;
|
let reg_l = ((extension & 0x7000) >> 12) as u8;
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Long))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Long))?;
|
||||||
let sign = if (ins & 0x0800) == 0 { Sign::Unsigned } else { Sign::Signed };
|
let sign = if (ins & 0x0800) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||||
match (ins & 0x040) == 0 {
|
match (ins & 0x040) == 0 {
|
||||||
true => Ok(Instruction::MULL(target, reg_h, reg_l, sign)),
|
true => Ok(Instruction::MULL(target, reg_h, reg_l, sign)),
|
||||||
false => Ok(Instruction::DIVL(target, reg_h, reg_l, sign)),
|
false => Ok(Instruction::DIVL(target, reg_h, reg_l, sign)),
|
||||||
}
|
}
|
||||||
} else if (ins & 0x800) == 0 {
|
} else if (ins & 0x800) == 0 {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
match (ins & 0x0700) >> 8 {
|
match (ins & 0x0700) >> 8 {
|
||||||
0b000 => {
|
0b000 => {
|
||||||
match get_size(ins) {
|
match get_size(ins) {
|
||||||
@ -275,11 +275,11 @@ impl M68kDecoder {
|
|||||||
let mode = get_low_mode(ins);
|
let mode = get_low_mode(ins);
|
||||||
match (opmode, mode) {
|
match (opmode, mode) {
|
||||||
(0b000, 0b001) if self.cputype >= M68kType::MC68020 => {
|
(0b000, 0b001) if self.cputype >= M68kType::MC68020 => {
|
||||||
let data = self.read_instruction_long(memory)? as i32;
|
let data = self.read_instruction_long(bus)? as i32;
|
||||||
Ok(Instruction::LINK(get_low_reg(ins), data))
|
Ok(Instruction::LINK(get_low_reg(ins), data))
|
||||||
},
|
},
|
||||||
(0b000, _) => {
|
(0b000, _) => {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
|
||||||
Ok(Instruction::NBCD(target))
|
Ok(Instruction::NBCD(target))
|
||||||
},
|
},
|
||||||
(0b001, 0b000) => {
|
(0b001, 0b000) => {
|
||||||
@ -289,7 +289,7 @@ impl M68kDecoder {
|
|||||||
Ok(Instruction::BKPT(get_low_reg(ins)))
|
Ok(Instruction::BKPT(get_low_reg(ins)))
|
||||||
},
|
},
|
||||||
(0b001, _) => {
|
(0b001, _) => {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, None)?;
|
let target = self.decode_lower_effective_address(bus, ins, None)?;
|
||||||
Ok(Instruction::PEA(target))
|
Ok(Instruction::PEA(target))
|
||||||
},
|
},
|
||||||
(0b010, 0b000) => {
|
(0b010, 0b000) => {
|
||||||
@ -307,7 +307,7 @@ impl M68kDecoder {
|
|||||||
if (ins & 0x0FF) == 0xFC {
|
if (ins & 0x0FF) == 0xFC {
|
||||||
Ok(Instruction::ILLEGAL)
|
Ok(Instruction::ILLEGAL)
|
||||||
} else {
|
} else {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
match get_size(ins) {
|
match get_size(ins) {
|
||||||
Some(size) => Ok(Instruction::TST(target, size)),
|
Some(size) => Ok(Instruction::TST(target, size)),
|
||||||
None => Ok(Instruction::TAS(target)),
|
None => Ok(Instruction::TAS(target)),
|
||||||
@ -315,7 +315,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
} else if ins_0f00 == 0xE00 {
|
} else if ins_0f00 == 0xE00 {
|
||||||
if (ins & 0x80) == 0x80 {
|
if (ins & 0x80) == 0x80 {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, None)?;
|
let target = self.decode_lower_effective_address(bus, ins, None)?;
|
||||||
if (ins & 0b01000000) == 0 {
|
if (ins & 0b01000000) == 0 {
|
||||||
Ok(Instruction::JSR(target))
|
Ok(Instruction::JSR(target))
|
||||||
} else {
|
} else {
|
||||||
@ -326,7 +326,7 @@ impl M68kDecoder {
|
|||||||
} else if ins_00f0 == 0x50 {
|
} else if ins_00f0 == 0x50 {
|
||||||
let reg = get_low_reg(ins);
|
let reg = get_low_reg(ins);
|
||||||
if (ins & 0b1000) == 0 {
|
if (ins & 0b1000) == 0 {
|
||||||
let data = (self.read_instruction_word(memory)? as i16) as i32;
|
let data = (self.read_instruction_word(bus)? as i16) as i32;
|
||||||
Ok(Instruction::LINK(reg, data))
|
Ok(Instruction::LINK(reg, data))
|
||||||
} else {
|
} else {
|
||||||
Ok(Instruction::UNLK(reg))
|
Ok(Instruction::UNLK(reg))
|
||||||
@ -340,12 +340,12 @@ impl M68kDecoder {
|
|||||||
0x70 => Ok(Instruction::RESET),
|
0x70 => Ok(Instruction::RESET),
|
||||||
0x71 => Ok(Instruction::NOP),
|
0x71 => Ok(Instruction::NOP),
|
||||||
0x72 => {
|
0x72 => {
|
||||||
let data = self.read_instruction_word(memory)?;
|
let data = self.read_instruction_word(bus)?;
|
||||||
Ok(Instruction::STOP(data))
|
Ok(Instruction::STOP(data))
|
||||||
},
|
},
|
||||||
0x73 => Ok(Instruction::RTE),
|
0x73 => Ok(Instruction::RTE),
|
||||||
0x74 if self.cputype >= M68kType::MC68010 => {
|
0x74 if self.cputype >= M68kType::MC68010 => {
|
||||||
let offset = self.read_instruction_word(memory)? as i16;
|
let offset = self.read_instruction_word(bus)? as i16;
|
||||||
Ok(Instruction::RTD(offset))
|
Ok(Instruction::RTD(offset))
|
||||||
},
|
},
|
||||||
0x75 => Ok(Instruction::RTS),
|
0x75 => Ok(Instruction::RTS),
|
||||||
@ -353,7 +353,7 @@ impl M68kDecoder {
|
|||||||
0x77 => Ok(Instruction::RTR),
|
0x77 => Ok(Instruction::RTR),
|
||||||
0x7A | 0x7B if self.cputype >= M68kType::MC68010 => {
|
0x7A | 0x7B if self.cputype >= M68kType::MC68010 => {
|
||||||
let dir = if ins & 0x01 == 0 { Direction::ToTarget } else { Direction::FromTarget };
|
let dir = if ins & 0x01 == 0 { Direction::ToTarget } else { Direction::FromTarget };
|
||||||
let ins2 = self.read_instruction_word(memory)?;
|
let ins2 = self.read_instruction_word(bus)?;
|
||||||
let target = match ins2 & 0x8000 {
|
let target = match ins2 & 0x8000 {
|
||||||
0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8),
|
0 => Target::DirectDReg(((ins2 & 0x7000) >> 12) as u8),
|
||||||
_ => Target::DirectAReg(((ins2 & 0x7000) >> 12) as u8),
|
_ => Target::DirectAReg(((ins2 & 0x7000) >> 12) as u8),
|
||||||
@ -373,10 +373,10 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_addq_subq(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_addq_subq(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
match get_size(ins) {
|
match get_size(ins) {
|
||||||
Some(size) => {
|
Some(size) => {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
let mut data = ((ins & 0x0E00) >> 9) as u32;
|
let mut data = ((ins & 0x0E00) >> 9) as u32;
|
||||||
if data == 0 {
|
if data == 0 {
|
||||||
data = 8;
|
data = 8;
|
||||||
@ -400,10 +400,10 @@ impl M68kDecoder {
|
|||||||
|
|
||||||
if mode == 0b001 {
|
if mode == 0b001 {
|
||||||
let reg = get_low_reg(ins);
|
let reg = get_low_reg(ins);
|
||||||
let disp = self.read_instruction_word(memory)? as i16;
|
let disp = self.read_instruction_word(bus)? as i16;
|
||||||
Ok(Instruction::DBcc(condition, reg, disp))
|
Ok(Instruction::DBcc(condition, reg, disp))
|
||||||
} else {
|
} else {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Byte))?;
|
||||||
Ok(Instruction::Scc(condition, target))
|
Ok(Instruction::Scc(condition, target))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -411,12 +411,12 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_branch(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_branch(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let mut disp = ((ins & 0xFF) as i8) as i32;
|
let mut disp = ((ins & 0xFF) as i8) as i32;
|
||||||
if disp == 0 {
|
if disp == 0 {
|
||||||
disp = (self.read_instruction_word(memory)? as i16) as i32;
|
disp = (self.read_instruction_word(bus)? as i16) as i32;
|
||||||
} else if disp == -1 && self.cputype >= M68kType::MC68020 {
|
} else if disp == -1 && self.cputype >= M68kType::MC68020 {
|
||||||
disp = self.read_instruction_long(memory)? as i32;
|
disp = self.read_instruction_long(bus)? as i32;
|
||||||
}
|
}
|
||||||
let condition = get_condition(ins);
|
let condition = get_condition(ins);
|
||||||
match condition {
|
match condition {
|
||||||
@ -427,7 +427,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_moveq(&mut self, _memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_moveq(&mut self, _bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
if (ins & 0x0100) != 0 {
|
if (ins & 0x0100) != 0 {
|
||||||
return Err(M68kError::Exception(Exceptions::IllegalInstruction));
|
return Err(M68kError::Exception(Exceptions::IllegalInstruction));
|
||||||
}
|
}
|
||||||
@ -437,7 +437,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_div_or(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_div_or(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
|
|
||||||
if (ins & 0x1F0) == 0x100 {
|
if (ins & 0x1F0) == 0x100 {
|
||||||
@ -450,18 +450,18 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
} else if let Some(size) = size {
|
} else if let Some(size) = size {
|
||||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
||||||
Ok(Instruction::OR(from, to, size))
|
Ok(Instruction::OR(from, to, size))
|
||||||
} else {
|
} else {
|
||||||
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
Ok(Instruction::DIVW(effective_addr, get_high_reg(ins), sign))
|
Ok(Instruction::DIVW(effective_addr, get_high_reg(ins), sign))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_sub(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_sub(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let reg = get_high_reg(ins);
|
let reg = get_high_reg(ins);
|
||||||
let dir = (ins & 0x0100) >> 8;
|
let dir = (ins & 0x0100) >> 8;
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
@ -475,7 +475,7 @@ impl M68kDecoder {
|
|||||||
false => Ok(Instruction::SUBX(Target::IndirectARegDec(src), Target::IndirectARegDec(dest), size)),
|
false => Ok(Instruction::SUBX(Target::IndirectARegDec(src), Target::IndirectARegDec(dest), size)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
if dir == 0 {
|
if dir == 0 {
|
||||||
Ok(Instruction::SUB(target, Target::DirectDReg(reg), size))
|
Ok(Instruction::SUB(target, Target::DirectDReg(reg), size))
|
||||||
} else {
|
} else {
|
||||||
@ -485,14 +485,14 @@ impl M68kDecoder {
|
|||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let size = if dir == 0 { Size::Word } else { Size::Long };
|
let size = if dir == 0 { Size::Word } else { Size::Long };
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
Ok(Instruction::SUBA(target, reg, size))
|
Ok(Instruction::SUBA(target, reg, size))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_cmp_eor(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_cmp_eor(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let reg = get_high_reg(ins);
|
let reg = get_high_reg(ins);
|
||||||
let optype = (ins & 0x0100) >> 8;
|
let optype = (ins & 0x0100) >> 8;
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
@ -501,17 +501,17 @@ impl M68kDecoder {
|
|||||||
if get_low_mode(ins) == 0b001 {
|
if get_low_mode(ins) == 0b001 {
|
||||||
Ok(Instruction::CMP(Target::IndirectARegInc(get_low_reg(ins)), Target::IndirectARegInc(reg), size))
|
Ok(Instruction::CMP(Target::IndirectARegInc(get_low_reg(ins)), Target::IndirectARegInc(reg), size))
|
||||||
} else {
|
} else {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
Ok(Instruction::EOR(Target::DirectDReg(reg), target, size))
|
Ok(Instruction::EOR(Target::DirectDReg(reg), target, size))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(0b0, Some(size)) => {
|
(0b0, Some(size)) => {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
Ok(Instruction::CMP(target, Target::DirectDReg(reg), size))
|
Ok(Instruction::CMP(target, Target::DirectDReg(reg), size))
|
||||||
},
|
},
|
||||||
(_, None) => {
|
(_, None) => {
|
||||||
let size = if optype == 0 { Size::Word } else { Size::Long };
|
let size = if optype == 0 { Size::Word } else { Size::Long };
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
Ok(Instruction::CMPA(target, reg, size))
|
Ok(Instruction::CMPA(target, reg, size))
|
||||||
},
|
},
|
||||||
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
_ => Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
||||||
@ -519,7 +519,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_mul_and(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_mul_and(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
|
|
||||||
if (ins & 0b0001_1111_0000) == 0b0001_0000_0000 {
|
if (ins & 0b0001_1111_0000) == 0b0001_0000_0000 {
|
||||||
@ -541,18 +541,18 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
} else if let Some(size) = size {
|
} else if let Some(size) = size {
|
||||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
||||||
Ok(Instruction::AND(from, to, size))
|
Ok(Instruction::AND(from, to, size))
|
||||||
} else {
|
} else {
|
||||||
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let effective_addr = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
Ok(Instruction::MULW(effective_addr, get_high_reg(ins), sign))
|
Ok(Instruction::MULW(effective_addr, get_high_reg(ins), sign))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn decode_group_add(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_add(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
let reg = get_high_reg(ins);
|
let reg = get_high_reg(ins);
|
||||||
let dir = (ins & 0x0100) >> 8;
|
let dir = (ins & 0x0100) >> 8;
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
@ -566,7 +566,7 @@ impl M68kDecoder {
|
|||||||
false => Ok(Instruction::ADDX(Target::IndirectARegDec(src), Target::IndirectARegDec(dest), size)),
|
false => Ok(Instruction::ADDX(Target::IndirectARegDec(src), Target::IndirectARegDec(dest), size)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
if dir == 0 {
|
if dir == 0 {
|
||||||
Ok(Instruction::ADD(target, Target::DirectDReg(reg), size))
|
Ok(Instruction::ADD(target, Target::DirectDReg(reg), size))
|
||||||
} else {
|
} else {
|
||||||
@ -576,13 +576,13 @@ impl M68kDecoder {
|
|||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let size = if dir == 0 { Size::Word } else { Size::Long };
|
let size = if dir == 0 { Size::Word } else { Size::Long };
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(size))?;
|
||||||
Ok(Instruction::ADDA(target, reg, size))
|
Ok(Instruction::ADDA(target, reg, size))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_group_shift(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
fn decode_group_shift(&mut self, bus: &mut M68kBusPort, ins: u16) -> Result<Instruction, M68kError> {
|
||||||
match get_size(ins) {
|
match get_size(ins) {
|
||||||
Some(size) => {
|
Some(size) => {
|
||||||
let target = Target::DirectDReg(get_low_reg(ins));
|
let target = Target::DirectDReg(get_low_reg(ins));
|
||||||
@ -613,7 +613,7 @@ impl M68kDecoder {
|
|||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
if (ins & 0x800) == 0 {
|
if (ins & 0x800) == 0 {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
let count = Target::Immediate(1);
|
let count = Target::Immediate(1);
|
||||||
let size = Size::Word;
|
let size = Size::Word;
|
||||||
|
|
||||||
@ -636,7 +636,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
} else if self.cputype > M68kType::MC68020 {
|
} else if self.cputype > M68kType::MC68020 {
|
||||||
// Bitfield instructions (MC68020+)
|
// Bitfield instructions (MC68020+)
|
||||||
let ext = self.read_instruction_word(memory)?;
|
let ext = self.read_instruction_word(bus)?;
|
||||||
let reg = ((ext & 0x7000) >> 12) as u8;
|
let reg = ((ext & 0x7000) >> 12) as u8;
|
||||||
|
|
||||||
let offset = match (ext & 0x0800) == 0 {
|
let offset = match (ext & 0x0800) == 0 {
|
||||||
@ -649,7 +649,7 @@ impl M68kDecoder {
|
|||||||
false => RegOrImmediate::DReg((ext & 0x0007) as u8),
|
false => RegOrImmediate::DReg((ext & 0x0007) as u8),
|
||||||
};
|
};
|
||||||
|
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let target = self.decode_lower_effective_address(bus, ins, Some(Size::Word))?;
|
||||||
match (ins & 0x0700) >> 8 {
|
match (ins & 0x0700) >> 8 {
|
||||||
0b010 => Ok(Instruction::BFCHG(target, offset, width)),
|
0b010 => Ok(Instruction::BFCHG(target, offset, width)),
|
||||||
0b100 => Ok(Instruction::BFCLR(target, offset, width)),
|
0b100 => Ok(Instruction::BFCLR(target, offset, width)),
|
||||||
@ -668,42 +668,42 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_instruction_word(&mut self, memory: &mut M68kBusPort) -> Result<u16, M68kError> {
|
fn read_instruction_word(&mut self, bus: &mut M68kBusPort) -> Result<u16, M68kError> {
|
||||||
let word = memory.read_instruction_word(self.is_supervisor, self.end)?;
|
let word = bus.read_instruction_word(self.is_supervisor, self.end)?;
|
||||||
self.end += 2;
|
self.end += 2;
|
||||||
Ok(word)
|
Ok(word)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_instruction_long(&mut self, memory: &mut M68kBusPort) -> Result<u32, M68kError> {
|
fn read_instruction_long(&mut self, bus: &mut M68kBusPort) -> Result<u32, M68kError> {
|
||||||
let word = memory.read_instruction_long(self.is_supervisor, self.end)?;
|
let word = bus.read_instruction_long(self.is_supervisor, self.end)?;
|
||||||
self.end += 4;
|
self.end += 4;
|
||||||
Ok(word)
|
Ok(word)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_lower_effective_address(&mut self, memory: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
|
fn decode_lower_effective_address(&mut self, bus: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
|
||||||
let reg = get_low_reg(ins);
|
let reg = get_low_reg(ins);
|
||||||
let mode = get_low_mode(ins);
|
let mode = get_low_mode(ins);
|
||||||
self.get_mode_as_target(memory, mode, reg, size)
|
self.get_mode_as_target(bus, mode, reg, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_upper_effective_address(&mut self, memory: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
|
fn decode_upper_effective_address(&mut self, bus: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, M68kError> {
|
||||||
let reg = get_high_reg(ins);
|
let reg = get_high_reg(ins);
|
||||||
let mode = get_high_mode(ins);
|
let mode = get_high_mode(ins);
|
||||||
self.get_mode_as_target(memory, mode, reg, size)
|
self.get_mode_as_target(bus, mode, reg, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_extension_displacement(&mut self, memory: &mut M68kBusPort, select: u16) -> Result<i32, M68kError> {
|
fn get_extension_displacement(&mut self, bus: &mut M68kBusPort, select: u16) -> Result<i32, M68kError> {
|
||||||
let result = match select {
|
let result = match select {
|
||||||
0b00 | 0b01 => 0,
|
0b00 | 0b01 => 0,
|
||||||
0b10 => sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word),
|
0b10 => sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word),
|
||||||
0b11 => self.read_instruction_long(memory)? as i32,
|
0b11 => self.read_instruction_long(bus)? as i32,
|
||||||
_ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
_ => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
||||||
};
|
};
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_extension_word(&mut self, memory: &mut M68kBusPort, areg: Option<u8>) -> Result<Target, M68kError> {
|
fn decode_extension_word(&mut self, bus: &mut M68kBusPort, areg: Option<u8>) -> Result<Target, M68kError> {
|
||||||
let brief_extension = self.read_instruction_word(memory)?;
|
let brief_extension = self.read_instruction_word(bus)?;
|
||||||
|
|
||||||
let use_brief = (brief_extension & 0x0100) == 0;
|
let use_brief = (brief_extension & 0x0100) == 0;
|
||||||
|
|
||||||
@ -744,8 +744,8 @@ impl M68kDecoder {
|
|||||||
(true, Some(areg)) => BaseRegister::AReg(areg),
|
(true, Some(areg)) => BaseRegister::AReg(areg),
|
||||||
};
|
};
|
||||||
let opt_index_reg = if use_index { Some(index_reg) } else { None };
|
let opt_index_reg = if use_index { Some(index_reg) } else { None };
|
||||||
let base_disp = self.get_extension_displacement(memory, (brief_extension & 0x0030) >> 4)?;
|
let base_disp = self.get_extension_displacement(bus, (brief_extension & 0x0030) >> 4)?;
|
||||||
let outer_disp = self.get_extension_displacement(memory, brief_extension & 0x0003)?;
|
let outer_disp = self.get_extension_displacement(bus, brief_extension & 0x0003)?;
|
||||||
|
|
||||||
match (use_sub_indirect, pre_not_post) {
|
match (use_sub_indirect, pre_not_post) {
|
||||||
(false, _) => Ok(Target::IndirectRegOffset(opt_base_reg, opt_index_reg, base_disp)),
|
(false, _) => Ok(Target::IndirectRegOffset(opt_base_reg, opt_index_reg, base_disp)),
|
||||||
@ -755,7 +755,7 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_mode_as_target(&mut self, memory: &mut M68kBusPort, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, M68kError> {
|
pub(super) fn get_mode_as_target(&mut self, bus: &mut M68kBusPort, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, M68kError> {
|
||||||
let value = match mode {
|
let value = match mode {
|
||||||
0b000 => Target::DirectDReg(reg),
|
0b000 => Target::DirectDReg(reg),
|
||||||
0b001 => Target::DirectAReg(reg),
|
0b001 => Target::DirectAReg(reg),
|
||||||
@ -763,33 +763,33 @@ impl M68kDecoder {
|
|||||||
0b011 => Target::IndirectARegInc(reg),
|
0b011 => Target::IndirectARegInc(reg),
|
||||||
0b100 => Target::IndirectARegDec(reg),
|
0b100 => Target::IndirectARegDec(reg),
|
||||||
0b101 => {
|
0b101 => {
|
||||||
let displacement = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
|
let displacement = sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word);
|
||||||
Target::IndirectRegOffset(BaseRegister::AReg(reg), None, displacement)
|
Target::IndirectRegOffset(BaseRegister::AReg(reg), None, displacement)
|
||||||
},
|
},
|
||||||
0b110 => {
|
0b110 => {
|
||||||
self.decode_extension_word(memory, Some(reg))?
|
self.decode_extension_word(bus, Some(reg))?
|
||||||
},
|
},
|
||||||
0b111 => {
|
0b111 => {
|
||||||
match reg {
|
match reg {
|
||||||
0b000 => {
|
0b000 => {
|
||||||
let value = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word) as u32;
|
let value = sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word) as u32;
|
||||||
Target::IndirectMemory(value, Size::Word)
|
Target::IndirectMemory(value, Size::Word)
|
||||||
},
|
},
|
||||||
0b001 => {
|
0b001 => {
|
||||||
let value = self.read_instruction_long(memory)?;
|
let value = self.read_instruction_long(bus)?;
|
||||||
Target::IndirectMemory(value, Size::Long)
|
Target::IndirectMemory(value, Size::Long)
|
||||||
},
|
},
|
||||||
0b010 => {
|
0b010 => {
|
||||||
let displacement = sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word);
|
let displacement = sign_extend_to_long(self.read_instruction_word(bus)? as u32, Size::Word);
|
||||||
Target::IndirectRegOffset(BaseRegister::PC, None, displacement)
|
Target::IndirectRegOffset(BaseRegister::PC, None, displacement)
|
||||||
},
|
},
|
||||||
0b011 => {
|
0b011 => {
|
||||||
self.decode_extension_word(memory, None)?
|
self.decode_extension_word(bus, None)?
|
||||||
},
|
},
|
||||||
0b100 => {
|
0b100 => {
|
||||||
let data = match size {
|
let data = match size {
|
||||||
Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word(memory)? as u32,
|
Some(Size::Byte) | Some(Size::Word) => self.read_instruction_word(bus)? as u32,
|
||||||
Some(Size::Long) => self.read_instruction_long(memory)?,
|
Some(Size::Long) => self.read_instruction_long(bus)?,
|
||||||
None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
None => return Err(M68kError::Exception(Exceptions::IllegalInstruction)),
|
||||||
};
|
};
|
||||||
Target::Immediate(data)
|
Target::Immediate(data)
|
||||||
@ -802,19 +802,19 @@ impl M68kDecoder {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_disassembly(&mut self, memory: &mut M68kBusPort, start: u32, length: u32) {
|
pub fn dump_disassembly(&mut self, bus: &mut M68kBusPort, start: u32, length: u32) {
|
||||||
let mut next = start;
|
let mut next = start;
|
||||||
while next < (start + length) {
|
while next < (start + length) {
|
||||||
match self.decode_at(memory, self.is_supervisor, next) {
|
match self.decode_at(bus, self.is_supervisor, next) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
self.dump_decoded(memory);
|
self.dump_decoded(bus);
|
||||||
next = self.end;
|
next = self.end;
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("{:?}", err);
|
println!("{:?}", err);
|
||||||
match err {
|
match err {
|
||||||
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => {
|
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => {
|
||||||
println!(" at {:08x}: {:04x}", self.start, memory.port.read_beu16(memory.current_clock, self.start as Address).unwrap());
|
println!(" at {:08x}: {:04x}", self.start, bus.port.read_beu16(bus.current_clock, self.start as Address).unwrap());
|
||||||
},
|
},
|
||||||
_ => { },
|
_ => { },
|
||||||
}
|
}
|
||||||
@ -824,10 +824,10 @@ impl M68kDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_decoded(&mut self, memory: &mut M68kBusPort) {
|
pub fn dump_decoded(&mut self, bus: &mut M68kBusPort) {
|
||||||
let ins_data: Result<String, M68kError> =
|
let ins_data: Result<String, M68kError> =
|
||||||
(0..((self.end - self.start) / 2)).map(|offset|
|
(0..((self.end - self.start) / 2)).map(|offset|
|
||||||
Ok(format!("{:04x} ", memory.port.read_beu16(memory.current_clock, (self.start + (offset * 2)) as Address).unwrap()))
|
Ok(format!("{:04x} ", bus.port.read_beu16(bus.current_clock, (self.start + (offset * 2)) as Address).unwrap()))
|
||||||
).collect();
|
).collect();
|
||||||
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
|
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,10 @@ use femtos::{Instant, Duration};
|
|||||||
|
|
||||||
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
||||||
|
|
||||||
use crate::state::{M68k, M68kType, M68kError, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
|
use crate::state::{M68k, M68kType, M68kError, M68kState, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
|
||||||
use crate::memory::{MemType, MemAccess};
|
use crate::memory::{MemType, MemAccess, M68kBusPort};
|
||||||
use crate::decode::M68kDecoder;
|
use crate::decode::M68kDecoder;
|
||||||
|
use crate::debugger::M68kDebugger;
|
||||||
use crate::timing::M68kInstructionTiming;
|
use crate::timing::M68kInstructionTiming;
|
||||||
use crate::instructions::{
|
use crate::instructions::{
|
||||||
Register,
|
Register,
|
||||||
@ -32,14 +33,89 @@ pub enum Used {
|
|||||||
Twice,
|
Twice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct M68kCycle {
|
||||||
|
pub decoder: M68kDecoder,
|
||||||
|
pub timing: M68kInstructionTiming,
|
||||||
|
pub current_clock: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl M68kCycle {
|
||||||
|
pub fn default(cputype: M68kType, data_width: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
decoder: M68kDecoder::new(cputype, true, 0),
|
||||||
|
timing: M68kInstructionTiming::new(cputype, data_width),
|
||||||
|
current_clock: Instant::START,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(cpu: &mut M68k, clock: Instant) -> Self {
|
||||||
|
let is_supervisor = cpu.state.sr & (Flags:: Supervisor as u16) != 0;
|
||||||
|
let pc = cpu.state.pc;
|
||||||
|
let data_width = cpu.port.data_width();
|
||||||
|
let cputype = cpu.cputype;
|
||||||
|
Self {
|
||||||
|
decoder: M68kDecoder::new(cputype, is_supervisor, pc),
|
||||||
|
timing: M68kInstructionTiming::new(cputype, data_width),
|
||||||
|
current_clock: clock,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleGuard<'a> {
|
||||||
|
// TODO this port init_cycle must be integrated into the cycle struct instead
|
||||||
|
cpu.port.init_cycle(self.current_clock);
|
||||||
|
|
||||||
|
M68kCycleGuard {
|
||||||
|
state: &mut cpu.state,
|
||||||
|
port: &mut cpu.port,
|
||||||
|
debugger: &mut cpu.debugger,
|
||||||
|
cycle: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct M68kCycleGuard<'a> {
|
||||||
|
pub state: &'a mut M68kState,
|
||||||
|
pub port: &'a mut M68kBusPort,
|
||||||
|
pub debugger: &'a mut M68kDebugger,
|
||||||
|
pub cycle: M68kCycle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> M68kCycleGuard<'a> {
|
||||||
|
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.port.dump_memory(self.state.ssp, 0x40);
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finalize(self) -> M68kCycle {
|
||||||
|
self.cycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Steppable for M68k {
|
impl Steppable for M68k {
|
||||||
fn step(&mut self, system: &System) -> Result<Duration, Error> {
|
fn step(&mut self, system: &System) -> Result<Duration, Error> {
|
||||||
let clocks = self.step_internal(system)?;
|
let mut cycle = M68kCycle::new(self, system.clock);
|
||||||
|
let mut execution = cycle.begin(self);
|
||||||
|
let clocks = execution.step(system)?;
|
||||||
|
self.cycle = execution.finalize();
|
||||||
Ok(self.frequency.period_duration() * clocks as u64)
|
Ok(self.frequency.period_duration() * clocks as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_error(&mut self, _system: &System) {
|
fn on_error(&mut self, _system: &System) {
|
||||||
self.dump_state();
|
// TODO the cycle data in dropped by this point
|
||||||
|
//self.dump_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,9 +158,9 @@ impl From<Error> for M68kError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl M68k {
|
impl<'a> M68kCycleGuard<'a> {
|
||||||
pub fn step_internal(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
|
#[inline]
|
||||||
self.init_cycle(system.clock);
|
pub fn step(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
|
||||||
match self.state.status {
|
match self.state.status {
|
||||||
Status::Init => self.reset_cpu(),
|
Status::Init => self.reset_cpu(),
|
||||||
Status::Stopped => Err(M68kError::Halted),
|
Status::Stopped => Err(M68kError::Halted),
|
||||||
@ -105,14 +181,7 @@ impl M68k {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_cycle(&mut self, clock: Instant) {
|
#[inline]
|
||||||
self.current_clock = clock;
|
|
||||||
self.decoder = M68kDecoder::new(self.cputype, self.is_supervisor(), self.state.pc);
|
|
||||||
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
|
|
||||||
self.port.init_cycle(clock);
|
|
||||||
self.timing.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_cpu(&mut self) -> Result<ClockCycles, M68kError> {
|
pub fn reset_cpu(&mut self) -> Result<ClockCycles, M68kError> {
|
||||||
self.state.ssp = self.get_address_sized(0, Size::Long)?;
|
self.state.ssp = self.get_address_sized(0, Size::Long)?;
|
||||||
self.state.pc = self.get_address_sized(4, Size::Long)?;
|
self.state.pc = self.get_address_sized(4, Size::Long)?;
|
||||||
@ -120,6 +189,7 @@ impl M68k {
|
|||||||
Ok(16)
|
Ok(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn cycle_one(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
|
pub fn cycle_one(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
|
||||||
self.check_breakpoints()?;
|
self.check_breakpoints()?;
|
||||||
|
|
||||||
@ -127,9 +197,10 @@ impl M68k {
|
|||||||
self.execute_current()?;
|
self.execute_current()?;
|
||||||
|
|
||||||
self.check_pending_interrupts(system)?;
|
self.check_pending_interrupts(system)?;
|
||||||
Ok(self.timing.calculate_clocks(false, 1))
|
Ok(self.cycle.timing.calculate_clocks(false, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> {
|
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> {
|
||||||
self.state.pending_ipl = match system.get_interrupt_controller().check() {
|
self.state.pending_ipl = match system.get_interrupt_controller().check() {
|
||||||
(true, priority) => InterruptPriority::from_u8(priority),
|
(true, priority) => InterruptPriority::from_u8(priority),
|
||||||
@ -174,9 +245,9 @@ impl M68k {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_group0_exception(&mut self, number: u8) -> Result<(), M68kError> {
|
fn setup_group0_exception(&mut self, number: u8) -> Result<(), M68kError> {
|
||||||
let sr = self.state.sr;
|
let sr = self.state.sr;
|
||||||
let ins_word = self.decoder.instruction_word;
|
let ins_word = self.cycle.decoder.instruction_word;
|
||||||
let extra_code = self.port.request.get_type_code();
|
let extra_code = self.port.request.get_type_code();
|
||||||
let fault_size = self.port.request.size.in_bytes();
|
let fault_size = self.port.request.size.in_bytes();
|
||||||
let fault_address = self.port.request.address;
|
let fault_address = self.port.request.address;
|
||||||
@ -186,7 +257,7 @@ impl M68k {
|
|||||||
self.set_flag(Flags::Tracing, false);
|
self.set_flag(Flags::Tracing, false);
|
||||||
|
|
||||||
let offset = (number as u16) << 2;
|
let offset = (number as u16) << 2;
|
||||||
if self.cputype >= M68kType::MC68010 {
|
if self.cycle.decoder.cputype >= M68kType::MC68010 {
|
||||||
self.push_word(offset)?;
|
self.push_word(offset)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +274,7 @@ impl M68k {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> {
|
fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> {
|
||||||
let sr = self.state.sr;
|
let sr = self.state.sr;
|
||||||
self.port.request.i_n_bit = true;
|
self.port.request.i_n_bit = true;
|
||||||
|
|
||||||
@ -215,7 +286,7 @@ impl M68k {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let offset = (number as u16) << 2;
|
let offset = (number as u16) << 2;
|
||||||
if self.cputype >= M68kType::MC68010 {
|
if self.cycle.decoder.cputype >= M68kType::MC68010 {
|
||||||
self.push_word(offset)?;
|
self.push_word(offset)?;
|
||||||
}
|
}
|
||||||
self.push_long(self.state.pc)?;
|
self.push_long(self.state.pc)?;
|
||||||
@ -228,19 +299,21 @@ impl M68k {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn decode_next(&mut self) -> Result<(), M68kError> {
|
pub fn decode_next(&mut self) -> Result<(), M68kError> {
|
||||||
let is_supervisor = self.is_supervisor();
|
let is_supervisor = self.is_supervisor();
|
||||||
self.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?;
|
self.cycle.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?;
|
||||||
|
|
||||||
self.timing.add_instruction(&self.decoder.instruction);
|
self.cycle.timing.add_instruction(&self.cycle.decoder.instruction);
|
||||||
|
|
||||||
self.state.pc = self.decoder.end;
|
self.state.pc = self.cycle.decoder.end;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn execute_current(&mut self) -> Result<(), M68kError> {
|
pub fn execute_current(&mut self) -> Result<(), M68kError> {
|
||||||
match self.decoder.instruction {
|
match self.cycle.decoder.instruction {
|
||||||
Instruction::ABCD(src, dest) => self.execute_abcd(src, dest),
|
Instruction::ABCD(src, dest) => self.execute_abcd(src, dest),
|
||||||
Instruction::ADD(src, dest, size) => self.execute_add(src, dest, size),
|
Instruction::ADD(src, dest, size) => self.execute_add(src, dest, size),
|
||||||
Instruction::ADDA(src, dest, size) => self.execute_adda(src, dest, size),
|
Instruction::ADDA(src, dest, size) => self.execute_adda(src, dest, size),
|
||||||
@ -475,7 +548,7 @@ impl M68k {
|
|||||||
fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), M68kError> {
|
fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), M68kError> {
|
||||||
let should_branch = self.get_current_condition(cond);
|
let should_branch = self.get_current_condition(cond);
|
||||||
if should_branch {
|
if should_branch {
|
||||||
if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
if let Err(err) = self.set_pc(self.cycle.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
||||||
self.state.pc -= 2;
|
self.state.pc -= 2;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
@ -484,7 +557,7 @@ impl M68k {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn execute_bra(&mut self, offset: i32) -> Result<(), M68kError> {
|
fn execute_bra(&mut self, offset: i32) -> Result<(), M68kError> {
|
||||||
if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
if let Err(err) = self.set_pc(self.cycle.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
||||||
self.state.pc -= 2;
|
self.state.pc -= 2;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
@ -495,7 +568,7 @@ impl M68k {
|
|||||||
self.push_long(self.state.pc)?;
|
self.push_long(self.state.pc)?;
|
||||||
let sp = *self.get_stack_pointer_mut();
|
let sp = *self.get_stack_pointer_mut();
|
||||||
self.debugger.stack_tracer.push_return(sp);
|
self.debugger.stack_tracer.push_return(sp);
|
||||||
if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
if let Err(err) = self.set_pc(self.cycle.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
||||||
self.state.pc -= 2;
|
self.state.pc -= 2;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
@ -618,7 +691,7 @@ impl M68k {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn execute_clr(&mut self, target: Target, size: Size) -> Result<(), M68kError> {
|
fn execute_clr(&mut self, target: Target, size: Size) -> Result<(), M68kError> {
|
||||||
if self.cputype == M68kType::MC68000 {
|
if self.cycle.decoder.cputype == M68kType::MC68000 {
|
||||||
self.get_target_value(target, size, Used::Twice)?;
|
self.get_target_value(target, size, Used::Twice)?;
|
||||||
self.set_target_value(target, 0, size, Used::Twice)?;
|
self.set_target_value(target, 0, size, Used::Twice)?;
|
||||||
} else {
|
} else {
|
||||||
@ -653,7 +726,7 @@ impl M68k {
|
|||||||
let next = ((get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16).wrapping_sub(1);
|
let next = ((get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16).wrapping_sub(1);
|
||||||
set_value_sized(&mut self.state.d_reg[reg as usize], next as u32, Size::Word);
|
set_value_sized(&mut self.state.d_reg[reg as usize], next as u32, Size::Word);
|
||||||
if next != -1 {
|
if next != -1 {
|
||||||
if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
if let Err(err) = self.set_pc(self.cycle.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
||||||
self.state.pc -= 2;
|
self.state.pc -= 2;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
@ -912,7 +985,7 @@ impl M68k {
|
|||||||
let addr = self.get_target_address(target)?;
|
let addr = self.get_target_address(target)?;
|
||||||
|
|
||||||
// If we're using a MC68020 or higher, and it was Post-Inc/Pre-Dec target, then update the value before it's stored
|
// If we're using a MC68020 or higher, and it was Post-Inc/Pre-Dec target, then update the value before it's stored
|
||||||
if self.cputype >= M68kType::MC68020 {
|
if self.cycle.decoder.cputype >= M68kType::MC68020 {
|
||||||
match target {
|
match target {
|
||||||
Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => {
|
Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => {
|
||||||
let a_reg_mut = self.get_a_reg_mut(reg);
|
let a_reg_mut = self.get_a_reg_mut(reg);
|
||||||
@ -1217,7 +1290,7 @@ impl M68k {
|
|||||||
let sr = self.pop_word()?;
|
let sr = self.pop_word()?;
|
||||||
let addr = self.pop_long()?;
|
let addr = self.pop_long()?;
|
||||||
|
|
||||||
if self.cputype >= M68kType::MC68010 {
|
if self.cycle.decoder.cputype >= M68kType::MC68010 {
|
||||||
let _ = self.pop_word()?;
|
let _ = self.pop_word()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1545,14 +1618,14 @@ impl M68k {
|
|||||||
*self.get_stack_pointer_mut() -= 2;
|
*self.get_stack_pointer_mut() -= 2;
|
||||||
let addr = *self.get_stack_pointer_mut();
|
let addr = *self.get_stack_pointer_mut();
|
||||||
self.port.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?;
|
self.port.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?;
|
||||||
self.port.port.write_beu16(self.current_clock, addr as Address, value)?;
|
self.port.port.write_beu16(self.cycle.current_clock, addr as Address, value)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_word(&mut self) -> Result<u16, M68kError> {
|
fn pop_word(&mut self) -> Result<u16, M68kError> {
|
||||||
let addr = *self.get_stack_pointer_mut();
|
let addr = *self.get_stack_pointer_mut();
|
||||||
self.port.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Read, MemType::Data, false)?;
|
self.port.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Read, MemType::Data, false)?;
|
||||||
let value = self.port.port.read_beu16(self.current_clock, addr as Address)?;
|
let value = self.port.port.read_beu16(self.cycle.current_clock, addr as Address)?;
|
||||||
*self.get_stack_pointer_mut() += 2;
|
*self.get_stack_pointer_mut() += 2;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
@ -1561,14 +1634,14 @@ impl M68k {
|
|||||||
*self.get_stack_pointer_mut() -= 4;
|
*self.get_stack_pointer_mut() -= 4;
|
||||||
let addr = *self.get_stack_pointer_mut();
|
let addr = *self.get_stack_pointer_mut();
|
||||||
self.port.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?;
|
self.port.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?;
|
||||||
self.port.port.write_beu32(self.current_clock, addr as Address, value)?;
|
self.port.port.write_beu32(self.cycle.current_clock, addr as Address, value)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_long(&mut self) -> Result<u32, M68kError> {
|
fn pop_long(&mut self) -> Result<u32, M68kError> {
|
||||||
let addr = *self.get_stack_pointer_mut();
|
let addr = *self.get_stack_pointer_mut();
|
||||||
self.port.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Read, MemType::Data, false)?;
|
self.port.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Read, MemType::Data, false)?;
|
||||||
let value = self.port.port.read_beu32(self.current_clock, addr as Address)?;
|
let value = self.port.port.read_beu32(self.cycle.current_clock, addr as Address)?;
|
||||||
*self.get_stack_pointer_mut() += 4;
|
*self.get_stack_pointer_mut() += 4;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
@ -1605,7 +1678,7 @@ impl M68k {
|
|||||||
fn get_base_reg_value(&self, base_reg: BaseRegister) -> u32 {
|
fn get_base_reg_value(&self, base_reg: BaseRegister) -> u32 {
|
||||||
match base_reg {
|
match base_reg {
|
||||||
BaseRegister::None => 0,
|
BaseRegister::None => 0,
|
||||||
BaseRegister::PC => self.decoder.start + 2,
|
BaseRegister::PC => self.cycle.decoder.start + 2,
|
||||||
BaseRegister::AReg(reg) if reg == 7 => if self.is_supervisor() { self.state.ssp } else { self.state.usp },
|
BaseRegister::AReg(reg) if reg == 7 => if self.is_supervisor() { self.state.ssp } else { self.state.usp },
|
||||||
BaseRegister::AReg(reg) => self.state.a_reg[reg as usize],
|
BaseRegister::AReg(reg) => self.state.a_reg[reg as usize],
|
||||||
}
|
}
|
||||||
@ -1659,7 +1732,7 @@ impl M68k {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_sr(&mut self, value: u16) {
|
fn set_sr(&mut self, value: u16) {
|
||||||
let mask = if self.cputype <= M68kType::MC68010 { 0xA71F } else { 0xF71F };
|
let mask = if self.cycle.decoder.cputype <= M68kType::MC68010 { 0xA71F } else { 0xF71F };
|
||||||
self.state.sr = value & mask;
|
self.state.sr = value & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
use femtos::Instant;
|
use femtos::Instant;
|
||||||
|
use emulator_hal::bus::{BusType, BusAccess};
|
||||||
|
|
||||||
use moa_core::{Error, Address, Addressable, BusPort};
|
use moa_core::{Error, Address, Addressable, BusPort};
|
||||||
|
|
||||||
@ -187,7 +188,22 @@ fn validate_address(addr: u32) -> Result<u32, M68kError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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(crate) struct TargetAccess {
|
pub(crate) struct TargetAccess {
|
||||||
|
@ -10,6 +10,7 @@ use crate::debugger::M68kDebugger;
|
|||||||
use crate::memory::M68kBusPort;
|
use crate::memory::M68kBusPort;
|
||||||
use crate::timing::M68kInstructionTiming;
|
use crate::timing::M68kInstructionTiming;
|
||||||
use crate::instructions::Target;
|
use crate::instructions::Target;
|
||||||
|
use crate::execute::M68kCycle;
|
||||||
|
|
||||||
|
|
||||||
pub type ClockCycles = u16;
|
pub type ClockCycles = u16;
|
||||||
@ -113,11 +114,12 @@ pub struct M68k {
|
|||||||
pub cputype: M68kType,
|
pub cputype: M68kType,
|
||||||
pub frequency: Frequency,
|
pub frequency: Frequency,
|
||||||
pub state: M68kState,
|
pub state: M68kState,
|
||||||
pub decoder: M68kDecoder,
|
//pub decoder: M68kDecoder,
|
||||||
pub timing: M68kInstructionTiming,
|
//pub timing: M68kInstructionTiming,
|
||||||
pub debugger: M68kDebugger,
|
pub debugger: M68kDebugger,
|
||||||
pub port: M68kBusPort,
|
pub port: M68kBusPort,
|
||||||
pub current_clock: Instant,
|
//pub current_clock: Instant,
|
||||||
|
pub cycle: M68kCycle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for M68kState {
|
impl Default for M68kState {
|
||||||
@ -141,15 +143,17 @@ impl Default for M68kState {
|
|||||||
|
|
||||||
impl M68k {
|
impl M68k {
|
||||||
pub fn new(cputype: M68kType, frequency: Frequency, port: BusPort) -> M68k {
|
pub fn new(cputype: M68kType, frequency: Frequency, port: BusPort) -> M68k {
|
||||||
|
let data_width = port.data_width();
|
||||||
M68k {
|
M68k {
|
||||||
cputype,
|
cputype,
|
||||||
frequency,
|
frequency,
|
||||||
state: M68kState::default(),
|
state: M68kState::default(),
|
||||||
decoder: M68kDecoder::new(cputype, true, 0),
|
//decoder: M68kDecoder::new(cputype, true, 0),
|
||||||
timing: M68kInstructionTiming::new(cputype, port.data_width()),
|
//timing: M68kInstructionTiming::new(cputype, port.data_width()),
|
||||||
debugger: M68kDebugger::default(),
|
debugger: M68kDebugger::default(),
|
||||||
port: M68kBusPort::new(port),
|
port: M68kBusPort::new(port),
|
||||||
current_clock: Instant::START,
|
//current_clock: Instant::START,
|
||||||
|
cycle: M68kCycle::default(cputype, data_width),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,21 +166,6 @@ impl M68k {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.decoder.start, self.decoder.instruction);
|
|
||||||
println!();
|
|
||||||
self.port.dump_memory(self.state.ssp, 0x40);
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptPriority {
|
impl InterruptPriority {
|
||||||
|
@ -255,13 +255,16 @@ mod execute_unit_tests {
|
|||||||
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device};
|
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device};
|
||||||
|
|
||||||
use crate::{M68k, M68kType};
|
use crate::{M68k, M68kType};
|
||||||
use crate::execute::Used;
|
use crate::execute::{Used, M68kCycle, M68kCycleGuard};
|
||||||
use crate::instructions::{Instruction, Target, Size};
|
use crate::instructions::{Instruction, Target, Size};
|
||||||
|
|
||||||
const INIT_STACK: Address = 0x00002000;
|
const INIT_STACK: Address = 0x00002000;
|
||||||
const INIT_ADDR: Address = 0x00000010;
|
const INIT_ADDR: Address = 0x00000010;
|
||||||
|
|
||||||
fn init_execute_test(cputype: M68kType) -> (M68k, System) {
|
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
|
||||||
|
where
|
||||||
|
F: FnMut(M68kCycleGuard),
|
||||||
|
{
|
||||||
let mut system = System::default();
|
let mut system = System::default();
|
||||||
|
|
||||||
// Insert basic initialization
|
// Insert basic initialization
|
||||||
@ -273,11 +276,14 @@ mod execute_unit_tests {
|
|||||||
|
|
||||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
||||||
cpu.step(&system).unwrap();
|
cpu.step(&system).unwrap();
|
||||||
cpu.decoder.init(true, cpu.state.pc);
|
let mut cycle = M68kCycle::new(&mut cpu, system.clock);
|
||||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
let mut execution = cycle.begin(&mut cpu);
|
||||||
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
execution.cycle.decoder.init(true, execution.state.pc);
|
||||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
assert_eq!(execution.state.pc, INIT_ADDR as u32);
|
||||||
(cpu, system)
|
assert_eq!(execution.state.ssp, INIT_STACK as u32);
|
||||||
|
assert_eq!(execution.cycle.decoder.instruction, Instruction::NOP);
|
||||||
|
|
||||||
|
test_func(execution);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -286,86 +292,86 @@ mod execute_unit_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_value_direct_d() {
|
fn target_value_direct_d() {
|
||||||
let (mut cpu, _) = init_execute_test(M68kType::MC68010);
|
run_execute_test(M68kType::MC68010, |mut cycle| {
|
||||||
|
|
||||||
let size = Size::Word;
|
let size = Size::Word;
|
||||||
let expected = 0x1234;
|
let expected = 0x1234;
|
||||||
let target = Target::DirectDReg(1);
|
let target = Target::DirectDReg(1);
|
||||||
|
|
||||||
cpu.state.d_reg[1] = expected;
|
cycle.state.d_reg[1] = expected;
|
||||||
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
|
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_value_direct_a() {
|
fn target_value_direct_a() {
|
||||||
let (mut cpu, _) = init_execute_test(M68kType::MC68010);
|
run_execute_test(M68kType::MC68010, |mut cycle| {
|
||||||
|
|
||||||
let size = Size::Word;
|
let size = Size::Word;
|
||||||
let expected = 0x1234;
|
let expected = 0x1234;
|
||||||
let target = Target::DirectAReg(2);
|
let target = Target::DirectAReg(2);
|
||||||
|
|
||||||
cpu.state.a_reg[2] = expected;
|
cycle.state.a_reg[2] = expected;
|
||||||
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
|
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_value_indirect_a() {
|
fn target_value_indirect_a() {
|
||||||
let (mut cpu, _) = init_execute_test(M68kType::MC68010);
|
run_execute_test(M68kType::MC68010, |mut cycle| {
|
||||||
|
|
||||||
let size = Size::Long;
|
let size = Size::Long;
|
||||||
let expected = 0x12345678;
|
let expected = 0x12345678;
|
||||||
let target = Target::IndirectAReg(2);
|
let target = Target::IndirectAReg(2);
|
||||||
cpu.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||||
|
|
||||||
cpu.state.a_reg[2] = INIT_ADDR as u32;
|
cycle.state.a_reg[2] = INIT_ADDR as u32;
|
||||||
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
|
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_value_indirect_a_inc() {
|
fn target_value_indirect_a_inc() {
|
||||||
let (mut cpu, _) = init_execute_test(M68kType::MC68010);
|
run_execute_test(M68kType::MC68010, |mut cycle| {
|
||||||
|
|
||||||
let size = Size::Long;
|
let size = Size::Long;
|
||||||
let expected = 0x12345678;
|
let expected = 0x12345678;
|
||||||
let target = Target::IndirectARegInc(2);
|
let target = Target::IndirectARegInc(2);
|
||||||
cpu.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||||
|
|
||||||
cpu.state.a_reg[2] = INIT_ADDR as u32;
|
cycle.state.a_reg[2] = INIT_ADDR as u32;
|
||||||
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
|
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
assert_eq!(cpu.state.a_reg[2], (INIT_ADDR as u32) + 4);
|
assert_eq!(cycle.state.a_reg[2], (INIT_ADDR as u32) + 4);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_value_indirect_a_dec() {
|
fn target_value_indirect_a_dec() {
|
||||||
let (mut cpu, _) = init_execute_test(M68kType::MC68010);
|
run_execute_test(M68kType::MC68010, |mut cycle| {
|
||||||
|
|
||||||
let size = Size::Long;
|
let size = Size::Long;
|
||||||
let expected = 0x12345678;
|
let expected = 0x12345678;
|
||||||
let target = Target::IndirectARegDec(2);
|
let target = Target::IndirectARegDec(2);
|
||||||
cpu.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||||
|
|
||||||
cpu.state.a_reg[2] = (INIT_ADDR as u32) + 4;
|
cycle.state.a_reg[2] = (INIT_ADDR as u32) + 4;
|
||||||
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
|
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
assert_eq!(cpu.state.a_reg[2], INIT_ADDR as u32);
|
assert_eq!(cycle.state.a_reg[2], INIT_ADDR as u32);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn target_value_immediate() {
|
fn target_value_immediate() {
|
||||||
let (mut cpu, _) = init_execute_test(M68kType::MC68010);
|
run_execute_test(M68kType::MC68010, |mut cycle| {
|
||||||
|
|
||||||
let size = Size::Word;
|
let size = Size::Word;
|
||||||
let expected = 0x1234;
|
let expected = 0x1234;
|
||||||
|
|
||||||
let target = Target::Immediate(expected);
|
let target = Target::Immediate(expected);
|
||||||
|
|
||||||
let result = cpu.get_target_value(target, size, Used::Once).unwrap();
|
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device};
|
|||||||
use moa_m68k::{M68k, M68kType};
|
use moa_m68k::{M68k, M68kType};
|
||||||
use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction};
|
use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction};
|
||||||
use moa_m68k::assembler::M68kAssembler;
|
use moa_m68k::assembler::M68kAssembler;
|
||||||
|
use moa_m68k::execute::M68kCycle;
|
||||||
|
|
||||||
const INIT_STACK: Address = 0x00002000;
|
const INIT_STACK: Address = 0x00002000;
|
||||||
const INIT_ADDR: Address = 0x00000010;
|
const INIT_ADDR: Address = 0x00000010;
|
||||||
@ -63,7 +64,7 @@ const DECODE_TESTS: &'static [TestCase] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
fn init_decode_test(cputype: M68kType) -> (M68k, System) {
|
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
|
||||||
let mut system = System::default();
|
let mut system = System::default();
|
||||||
|
|
||||||
// Insert basic initialization
|
// Insert basic initialization
|
||||||
@ -75,14 +76,14 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
|
|||||||
|
|
||||||
// Initialize the CPU and make sure it's in the expected state
|
// Initialize the CPU and make sure it's in the expected state
|
||||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
||||||
cpu.reset_cpu().unwrap();
|
//cpu.reset_cpu().unwrap();
|
||||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||||
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
||||||
|
|
||||||
cpu.decoder.init(true, INIT_ADDR as u32);
|
let cycle = M68kCycle::new(cpu, system.clock);
|
||||||
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
|
assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
|
||||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||||
(cpu, system)
|
(cpu, cycle, system)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_memory(system: &System, data: &[u16]) {
|
fn load_memory(system: &System, data: &[u16]) {
|
||||||
@ -94,15 +95,17 @@ fn load_memory(system: &System, data: &[u16]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_decode_test(case: &TestCase) {
|
fn run_decode_test(case: &TestCase) {
|
||||||
let (mut cpu, system) = init_decode_test(case.cpu);
|
let (mut cpu, mut cycle, system) = init_decode_test(case.cpu);
|
||||||
load_memory(&system, case.data);
|
load_memory(&system, case.data);
|
||||||
match &case.ins {
|
match &case.ins {
|
||||||
Some(ins) => {
|
Some(ins) => {
|
||||||
cpu.decode_next().unwrap();
|
let mut execution = cycle.begin(cpu);
|
||||||
|
execution.decode_next().unwrap();
|
||||||
assert_eq!(cpu.decoder.instruction, ins.clone());
|
assert_eq!(cpu.decoder.instruction, ins.clone());
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let next = cpu.decode_next();
|
let mut execution = cycle.begin(cpu);
|
||||||
|
let next = execution.decode_next();
|
||||||
println!("{:?}", cpu.decoder.instruction);
|
println!("{:?}", cpu.decoder.instruction);
|
||||||
assert!(next.is_err());
|
assert!(next.is_err());
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,7 @@ use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, De
|
|||||||
|
|
||||||
use moa_m68k::{M68k, M68kType};
|
use moa_m68k::{M68k, M68kType};
|
||||||
use moa_m68k::state::M68kState;
|
use moa_m68k::state::M68kState;
|
||||||
|
use moa_m68k::execute::M68kCycle;
|
||||||
use moa_m68k::instructions::{Instruction, Target, Size, Sign, Direction, Condition};
|
use moa_m68k::instructions::{Instruction, Target, Size, Sign, Direction, Condition};
|
||||||
|
|
||||||
const INIT_STACK: Address = 0x00002000;
|
const INIT_STACK: Address = 0x00002000;
|
||||||
@ -34,7 +35,10 @@ struct TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn init_execute_test(cputype: M68kType) -> (M68k, System) {
|
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
|
||||||
|
where
|
||||||
|
F: FnMut(M68kCycle, System),
|
||||||
|
{
|
||||||
let mut system = System::default();
|
let mut system = System::default();
|
||||||
|
|
||||||
// Insert basic initialization
|
// Insert basic initialization
|
||||||
@ -46,11 +50,13 @@ fn init_execute_test(cputype: M68kType) -> (M68k, System) {
|
|||||||
|
|
||||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
||||||
cpu.step(&system).unwrap();
|
cpu.step(&system).unwrap();
|
||||||
cpu.decoder.init(true, cpu.state.pc);
|
|
||||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
let cycle = M68kCycle::new(cpu);
|
||||||
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
assert_eq!(cycle.state.pc, INIT_ADDR as u32);
|
||||||
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
assert_eq!(cycle.state.ssp, INIT_STACK as u32);
|
||||||
(cpu, system)
|
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||||
|
|
||||||
|
test_func(cycle, system)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_state(state: &TestState) -> M68kState {
|
fn build_state(state: &TestState) -> M68kState {
|
||||||
@ -73,23 +79,23 @@ fn load_memory(system: &System, data: &[u16]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_test(case: &TestCase) {
|
fn run_test(case: &TestCase) {
|
||||||
let (mut cpu, system) = init_execute_test(case.cputype);
|
run_execute_test(case.cputype, |mut cycle, system| {
|
||||||
|
|
||||||
let init_state = build_state(&case.init);
|
let init_state = build_state(&case.init);
|
||||||
let expected_state = build_state(&case.fini);
|
let expected_state = build_state(&case.fini);
|
||||||
system.get_bus().write_beu32(system.clock, MEM_ADDR as Address, case.init.mem).unwrap();
|
system.get_bus().write_beu32(system.clock, MEM_ADDR as Address, case.init.mem).unwrap();
|
||||||
|
|
||||||
load_memory(&system, case.data);
|
load_memory(&system, case.data);
|
||||||
cpu.state = init_state;
|
*cycle.state = init_state;
|
||||||
|
|
||||||
cpu.decode_next().unwrap();
|
cycle.decode_next().unwrap();
|
||||||
assert_eq!(cpu.decoder.instruction, case.ins);
|
assert_eq!(cycle.decoder.instruction, case.ins);
|
||||||
|
|
||||||
cpu.execute_current().unwrap();
|
cycle.execute_current().unwrap();
|
||||||
assert_eq!(cpu.state, expected_state);
|
assert_eq!(*cycle.state, expected_state);
|
||||||
|
|
||||||
let mem = system.get_bus().read_beu32(system.clock, MEM_ADDR as Address).unwrap();
|
let mem = system.get_bus().read_beu32(system.clock, MEM_ADDR as Address).unwrap();
|
||||||
assert_eq!(mem, case.fini.mem);
|
assert_eq!(mem, case.fini.mem);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -9,3 +9,4 @@ thiserror = "1.0"
|
|||||||
femtos = "0.1"
|
femtos = "0.1"
|
||||||
moa-core = { path = "../../core" }
|
moa-core = { path = "../../core" }
|
||||||
moa-signals = { path = "../../libraries/signals" }
|
moa-signals = { path = "../../libraries/signals" }
|
||||||
|
emulator-hal = { path = "/media/work/projects/emulator-hal/emulator-hal" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
use moa_core::{System, Error, Address, Debuggable};
|
use moa_core::{System, Error, Address, Debuggable};
|
||||||
|
|
||||||
use crate::state::Z80;
|
use crate::state::{Z80, Z80Error};
|
||||||
use crate::decode::Z80Decoder;
|
use crate::decode::Z80Decoder;
|
||||||
use crate::instructions::Register;
|
use crate::instructions::Register;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ impl Debuggable for Z80 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Z80 {
|
impl Z80 {
|
||||||
pub fn check_breakpoints(&mut self) -> Result<(), Error> {
|
pub fn check_breakpoints(&mut self) -> Result<(), Z80Error> {
|
||||||
for breakpoint in &self.debugger.breakpoints {
|
for breakpoint in &self.debugger.breakpoints {
|
||||||
if *breakpoint == self.state.pc {
|
if *breakpoint == self.state.pc {
|
||||||
if self.debugger.skip_breakpoint > 0 {
|
if self.debugger.skip_breakpoint > 0 {
|
||||||
@ -55,7 +55,7 @@ impl Z80 {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
self.debugger.skip_breakpoint = 1;
|
self.debugger.skip_breakpoint = 1;
|
||||||
return Err(Error::breakpoint(format!("breakpoint reached: {:08x}", *breakpoint)));
|
return Err(Z80Error::Breakpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,18 @@ use moa_core::{Address, Addressable};
|
|||||||
use crate::state::Z80Error;
|
use crate::state::Z80Error;
|
||||||
use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction};
|
use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction};
|
||||||
|
|
||||||
|
use emulator_hal::bus::{BusType, BusAccess};
|
||||||
|
|
||||||
|
struct Z80Bus;
|
||||||
|
|
||||||
|
type Z80Address = (bool, u16);
|
||||||
|
|
||||||
|
impl BusType for Z80Bus {
|
||||||
|
//type Address = (bool, u16);
|
||||||
|
type Error = Z80Error;
|
||||||
|
type Instant = Instant;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Z80Decoder {
|
pub struct Z80Decoder {
|
||||||
pub clock: Instant,
|
pub clock: Instant,
|
||||||
@ -27,6 +39,16 @@ impl Default for Z80Decoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn read_test<B>(&mut self, device: &mut B) -> Result<u8, Z80Error>
|
||||||
|
where
|
||||||
|
B: BusAccess<Z80Address, Instant = Instant>,
|
||||||
|
{
|
||||||
|
device.read_u8(self.clock, (false, self.end as u16))
|
||||||
|
.map_err(|err| Z80Error::BusError(format!("butts")))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
impl Z80Decoder {
|
impl Z80Decoder {
|
||||||
pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: Instant, start: u16) -> Result<(), Z80Error> {
|
pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: Instant, start: u16) -> Result<(), Z80Error> {
|
||||||
self.clock = clock;
|
self.clock = clock;
|
||||||
@ -525,7 +547,6 @@ impl Z80Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Z80Error> {
|
fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result<u8, Z80Error> {
|
||||||
let byte = device.read_u8(self.clock, self.end as Address)?;
|
let byte = device.read_u8(self.clock, self.end as Address)?;
|
||||||
self.end = self.end.wrapping_add(1);
|
self.end = self.end.wrapping_add(1);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use femtos::{Instant, Frequency};
|
use femtos::{Instant, Frequency};
|
||||||
@ -93,7 +94,7 @@ impl Z80State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, thiserror::Error)]
|
#[derive(Clone, Debug, thiserror::Error)]
|
||||||
pub enum Z80Error {
|
pub enum Z80Error /* <B: fmt::Display> */ {
|
||||||
#[error("cpu halted")]
|
#[error("cpu halted")]
|
||||||
Halted,
|
Halted,
|
||||||
#[error("breakpoint reached")]
|
#[error("breakpoint reached")]
|
||||||
@ -101,7 +102,7 @@ pub enum Z80Error {
|
|||||||
#[error("unimplemented instruction {0:?}")]
|
#[error("unimplemented instruction {0:?}")]
|
||||||
Unimplemented(Instruction),
|
Unimplemented(Instruction),
|
||||||
#[error("bus error: {0}")]
|
#[error("bus error: {0}")]
|
||||||
BusError(String),
|
BusError(String /* B */),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
143
emulator/frontends/pixels/Cargo.lock
generated
143
emulator/frontends/pixels/Cargo.lock
generated
@ -35,9 +35,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.9"
|
version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
|
checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -191,7 +191,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"shlex",
|
"shlex",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -286,9 +286,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.87"
|
version = "1.0.88"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3286b845d0fccbdd15af433f61c5970e711987036cb468f437ff6badd70f4e24"
|
checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -328,7 +328,7 @@ checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.1",
|
"libloading 0.8.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -499,7 +499,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.8.1",
|
"libloading 0.8.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -514,6 +514,10 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "emulator-hal"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@ -722,9 +726,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.3"
|
version = "2.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
|
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.3",
|
"hashbrown 0.14.3",
|
||||||
@ -827,12 +831,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
checksum = "2caa5afb8bf9f3a2652760ce7d4f62d21c4d5a423e68466fca30df82f2330164"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-sys 0.48.0",
|
"windows-targets 0.52.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -858,9 +862,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.20"
|
version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mach"
|
name = "mach"
|
||||||
@ -936,9 +940,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.10"
|
version = "0.8.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -958,24 +962,38 @@ dependencies = [
|
|||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
|
"moa-host",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moa-core"
|
name = "moa-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emulator-hal",
|
||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
|
"moa-host",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "moa-host"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"femtos",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moa-m68k"
|
name = "moa-m68k"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emulator-hal",
|
||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
"moa-parsing",
|
"moa-parsing",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -994,6 +1012,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"moa-audio",
|
"moa-audio",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
|
"moa-host",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1008,6 +1027,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"moa-common",
|
"moa-common",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
|
"moa-host",
|
||||||
"moa-systems-genesis",
|
"moa-systems-genesis",
|
||||||
"pixels",
|
"pixels",
|
||||||
"pollster",
|
"pollster",
|
||||||
@ -1018,6 +1038,13 @@ dependencies = [
|
|||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "moa-signals"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"femtos",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moa-systems-genesis"
|
name = "moa-systems-genesis"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1025,8 +1052,10 @@ dependencies = [
|
|||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
|
"moa-host",
|
||||||
"moa-m68k",
|
"moa-m68k",
|
||||||
"moa-peripherals-yamaha",
|
"moa-peripherals-yamaha",
|
||||||
|
"moa-signals",
|
||||||
"moa-z80",
|
"moa-z80",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1034,9 +1063,12 @@ dependencies = [
|
|||||||
name = "moa-z80"
|
name = "moa-z80"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emulator-hal",
|
||||||
"femtos",
|
"femtos",
|
||||||
"log",
|
"log",
|
||||||
"moa-core",
|
"moa-core",
|
||||||
|
"moa-signals",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1217,7 +1249,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1590,7 +1622,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1749,9 +1781,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.50"
|
version = "2.0.52"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1784,7 +1816,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1824,7 +1856,7 @@ version = "0.19.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.3",
|
"indexmap 2.2.5",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
@ -1876,9 +1908,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.4.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file",
|
"same-file",
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
@ -1911,7 +1943,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1945,7 +1977,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@ -2256,6 +2288,21 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.48.5",
|
"windows_x86_64_msvc 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.4",
|
||||||
|
"windows_aarch64_msvc 0.52.4",
|
||||||
|
"windows_i686_gnu 0.52.4",
|
||||||
|
"windows_i686_msvc 0.52.4",
|
||||||
|
"windows_x86_64_gnu 0.52.4",
|
||||||
|
"windows_x86_64_gnullvm 0.52.4",
|
||||||
|
"windows_x86_64_msvc 0.52.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -2268,6 +2315,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
@ -2286,6 +2339,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
@ -2304,6 +2363,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
@ -2322,6 +2387,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
@ -2340,6 +2411,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -2352,6 +2429,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
@ -2370,6 +2453,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.28.7"
|
version = "0.28.7"
|
||||||
@ -2454,5 +2543,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.50",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
@ -18,7 +18,7 @@ moa-systems-genesis = { path = "../../systems/genesis" }
|
|||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
console_log = "1.0"
|
console_log = "1.0"
|
||||||
wasm-bindgen = "0.2.91"
|
wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
web-sys = "0.3"
|
web-sys = "0.3"
|
||||||
wgpu = { version = "0.15", features = ["webgl"] }
|
wgpu = { version = "0.15", features = ["webgl"] }
|
||||||
|
12
todo.txt
12
todo.txt
@ -1,4 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
* the idea would be, instead of argument drilling, you create an object that is short lived, that lasts one instruction, or possibly even parts of one instruction, and
|
||||||
|
it has some references instead of "moving" data (or if you move, you move and move out without cloning), such that you can bundle everything up, call a method on the
|
||||||
|
bundle, with the execution context and state all part of or reference by the bundle, all instructions would be implemented on the bundle and not the state alone, and
|
||||||
|
after the instruction, or when transitioning from one phase to the next, you'd decompose the bundle back into its parts, and return before being called again to
|
||||||
|
repeat the process with the next instruction
|
||||||
|
|
||||||
|
|
||||||
|
* it doesn't work when using debug due to math checks, so fix them
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* change all the inspection and debugging things to return a struct which can then be printed by the frontend
|
* change all the inspection and debugging things to return a struct which can then be printed by the frontend
|
||||||
|
|
||||||
* there are many issues with the coprocessor address space, and the VDP
|
* there are many issues with the coprocessor address space, and the VDP
|
||||||
|
Loading…
Reference in New Issue
Block a user