Refactored memory access a bit to try to isolate it
This commit is contained in:
parent
d87319b605
commit
8c1a89a1fe
|
@ -6,7 +6,7 @@ use std::cell::RefCell;
|
|||
use std::fmt::Write;
|
||||
|
||||
use crate::info;
|
||||
use crate::error::{Error, EmulatorErrorKind};
|
||||
use crate::error::Error;
|
||||
use crate::clock::ClockTime;
|
||||
use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_beu16};
|
||||
|
||||
|
@ -275,7 +275,6 @@ pub struct BusPort {
|
|||
offset: Address,
|
||||
address_mask: Address,
|
||||
data_width: u8,
|
||||
error_on_alignment: bool,
|
||||
subdevice: Rc<RefCell<Bus>>,
|
||||
}
|
||||
|
||||
|
@ -285,7 +284,6 @@ impl BusPort {
|
|||
offset,
|
||||
address_mask: (1 << address_bits) - 1,
|
||||
data_width: data_bits / 8,
|
||||
error_on_alignment: false,
|
||||
subdevice: bus,
|
||||
}
|
||||
}
|
||||
|
@ -294,10 +292,12 @@ impl BusPort {
|
|||
self.subdevice.borrow_mut().dump_memory(clock, self.offset + (addr & self.address_mask), count)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn address_mask(&self) -> Address {
|
||||
self.address_mask
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn data_width(&self) -> u8 {
|
||||
self.data_width
|
||||
}
|
||||
|
@ -309,10 +309,6 @@ impl Addressable for BusPort {
|
|||
}
|
||||
|
||||
fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
||||
if self.error_on_alignment && addr % self.data_width as Address != 0 {
|
||||
return Err(Error::emulator(EmulatorErrorKind::MemoryAlignment, format!("misaligned memory access at {:x}", addr)));
|
||||
}
|
||||
|
||||
let addr = self.offset + (addr & self.address_mask);
|
||||
let mut subdevice = self.subdevice.borrow_mut();
|
||||
for i in (0..data.len()).step_by(self.data_width as usize) {
|
||||
|
@ -324,10 +320,6 @@ impl Addressable for BusPort {
|
|||
}
|
||||
|
||||
fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> {
|
||||
if self.error_on_alignment && addr % self.data_width as Address != 0 {
|
||||
return Err(Error::emulator(EmulatorErrorKind::MemoryAlignment, format!("misaligned memory access at {:x}", addr)));
|
||||
}
|
||||
|
||||
let addr = self.offset + (addr & self.address_mask);
|
||||
let mut subdevice = self.subdevice.borrow_mut();
|
||||
for i in (0..data.len()).step_by(self.data_width as usize) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use moa_core::{System, Error, ClockTime, Address, Addressable, Debuggable};
|
||||
use moa_core::{System, Error, Address, Addressable, Debuggable};
|
||||
|
||||
use super::state::M68k;
|
||||
use super::decode::M68kDecoder;
|
||||
|
@ -50,15 +50,15 @@ impl Debuggable for M68k {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
|
||||
self.decoder.decode_at(&mut self.port, system.clock, self.state.pc)?;
|
||||
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
|
||||
self.decoder.decode_at(&mut self.port, true, self.state.pc)?;
|
||||
self.decoder.dump_decoded(&mut self.port);
|
||||
self.dump_state(system.clock);
|
||||
self.dump_state();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
||||
let mut decoder = M68kDecoder::new(self.cputype, ClockTime::START, 0);
|
||||
let mut decoder = M68kDecoder::new(self.cputype, true, 0);
|
||||
decoder.dump_disassembly(&mut self.port, addr as u32, count as u32);
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ impl Debuggable for M68k {
|
|||
"ds" | "stack" | "dumpstack" => {
|
||||
println!("Stack:");
|
||||
for addr in &self.debugger.stack_tracer.calls {
|
||||
println!(" {:08x}", self.port.read_beu32(system.clock, *addr as Address)?);
|
||||
println!(" {:08x}", self.port.port.read_beu32(system.clock, *addr as Address)?);
|
||||
}
|
||||
},
|
||||
"so" | "stepout" => {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
|
||||
use moa_core::{Error, ClockTime, Address, Addressable};
|
||||
use moa_core::{Error, Address, Addressable};
|
||||
|
||||
use super::state::{M68kType, Exceptions};
|
||||
use super::instructions::{
|
||||
use crate::state::{M68kType, Exceptions};
|
||||
use crate::memory::M68kBusPort;
|
||||
use crate::instructions::{
|
||||
Size,
|
||||
Sign,
|
||||
Direction,
|
||||
|
@ -39,7 +40,7 @@ const OPCG_FLINE: u8 = 0xF;
|
|||
#[derive(Clone)]
|
||||
pub struct M68kDecoder {
|
||||
pub cputype: M68kType,
|
||||
pub clock: ClockTime,
|
||||
pub is_supervisor: bool,
|
||||
pub start: u32,
|
||||
pub end: u32,
|
||||
pub instruction_word: u16,
|
||||
|
@ -47,10 +48,10 @@ pub struct M68kDecoder {
|
|||
}
|
||||
|
||||
impl M68kDecoder {
|
||||
pub fn new(cputype: M68kType, clock: ClockTime, start: u32) -> M68kDecoder {
|
||||
pub fn new(cputype: M68kType, is_supervisor: bool, start: u32) -> M68kDecoder {
|
||||
M68kDecoder {
|
||||
cputype,
|
||||
clock,
|
||||
is_supervisor,
|
||||
start,
|
||||
end: start,
|
||||
instruction_word: 0,
|
||||
|
@ -59,19 +60,19 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn init(&mut self, clock: ClockTime, start: u32) {
|
||||
self.clock = clock;
|
||||
pub fn init(&mut self, is_supervisor: bool, start: u32) {
|
||||
self.is_supervisor = is_supervisor;
|
||||
self.start = start;
|
||||
self.end = start;
|
||||
}
|
||||
|
||||
pub fn decode_at(&mut self, memory: &mut dyn Addressable, clock: ClockTime, start: u32) -> Result<(), Error> {
|
||||
self.init(clock, start);
|
||||
self.instruction = self.decode_one(memory)?;
|
||||
pub fn decode_at(&mut self, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), Error> {
|
||||
self.init(is_supervisor, start);
|
||||
self.instruction = self.decode_next(memory)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_one(&mut self, memory: &mut dyn Addressable) -> Result<Instruction, Error> {
|
||||
pub fn decode_next(&mut self, memory: &mut M68kBusPort) -> Result<Instruction, Error> {
|
||||
let ins = self.read_instruction_word(memory)?;
|
||||
self.instruction_word = ins;
|
||||
|
||||
|
@ -97,7 +98,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_bit_ops(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_bit_ops(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let optype = (ins & 0x0F00) >> 8;
|
||||
|
||||
if (ins & 0x13F) == 0x03C {
|
||||
|
@ -172,14 +173,14 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_move_byte(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_move_byte(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let src = self.decode_lower_effective_address(memory, ins, Some(Size::Byte))?;
|
||||
let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Byte))?;
|
||||
Ok(Instruction::MOVE(src, dest, Size::Byte))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_move_long(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_move_long(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let src = self.decode_lower_effective_address(memory, ins, Some(Size::Long))?;
|
||||
let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Long))?;
|
||||
if let Target::DirectAReg(reg) = dest {
|
||||
|
@ -190,7 +191,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_move_word(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_move_word(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let src = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
||||
let dest = self.decode_upper_effective_address(memory, ins, Some(Size::Word))?;
|
||||
if let Target::DirectAReg(reg) = dest {
|
||||
|
@ -201,7 +202,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_misc(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_misc(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let ins_0f00 = ins & 0xF00;
|
||||
let ins_00f0 = ins & 0x0F0;
|
||||
|
||||
|
@ -372,7 +373,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_addq_subq(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_addq_subq(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
match get_size(ins) {
|
||||
Some(size) => {
|
||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
||||
|
@ -410,7 +411,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_branch(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_branch(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let mut disp = ((ins & 0xFF) as i8) as i32;
|
||||
if disp == 0 {
|
||||
disp = (self.read_instruction_word(memory)? as i16) as i32;
|
||||
|
@ -426,7 +427,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_moveq(&mut self, _memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_moveq(&mut self, _memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
if (ins & 0x0100) != 0 {
|
||||
return Err(Error::processor(Exceptions::IllegalInstruction as u32));
|
||||
}
|
||||
|
@ -436,7 +437,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_div_or(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_div_or(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let size = get_size(ins);
|
||||
|
||||
if (ins & 0x1F0) == 0x100 {
|
||||
|
@ -460,7 +461,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_sub(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_sub(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let reg = get_high_reg(ins);
|
||||
let dir = (ins & 0x0100) >> 8;
|
||||
let size = get_size(ins);
|
||||
|
@ -491,7 +492,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_cmp_eor(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_cmp_eor(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let reg = get_high_reg(ins);
|
||||
let optype = (ins & 0x0100) >> 8;
|
||||
let size = get_size(ins);
|
||||
|
@ -518,7 +519,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_mul_and(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_mul_and(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let size = get_size(ins);
|
||||
|
||||
if (ins & 0b0001_1111_0000) == 0b0001_0000_0000 {
|
||||
|
@ -551,7 +552,7 @@ impl M68kDecoder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn decode_group_add(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_add(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
let reg = get_high_reg(ins);
|
||||
let dir = (ins & 0x0100) >> 8;
|
||||
let size = get_size(ins);
|
||||
|
@ -581,7 +582,7 @@ impl M68kDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
fn decode_group_shift(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
|
||||
fn decode_group_shift(&mut self, memory: &mut M68kBusPort, ins: u16) -> Result<Instruction, Error> {
|
||||
match get_size(ins) {
|
||||
Some(size) => {
|
||||
let target = Target::DirectDReg(get_low_reg(ins));
|
||||
|
@ -667,31 +668,31 @@ impl M68kDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_instruction_word(&mut self, memory: &mut dyn Addressable) -> Result<u16, Error> {
|
||||
let word = memory.read_beu16(self.clock, self.end as Address)?;
|
||||
fn read_instruction_word(&mut self, memory: &mut M68kBusPort) -> Result<u16, Error> {
|
||||
let word = memory.read_instruction_word(self.is_supervisor, self.end)?;
|
||||
self.end += 2;
|
||||
Ok(word)
|
||||
}
|
||||
|
||||
fn read_instruction_long(&mut self, memory: &mut dyn Addressable) -> Result<u32, Error> {
|
||||
let word = memory.read_beu32(self.clock, self.end as Address)?;
|
||||
fn read_instruction_long(&mut self, memory: &mut M68kBusPort) -> Result<u32, Error> {
|
||||
let word = memory.read_instruction_long(self.is_supervisor, self.end)?;
|
||||
self.end += 4;
|
||||
Ok(word)
|
||||
}
|
||||
|
||||
fn decode_lower_effective_address(&mut self, memory: &mut dyn Addressable, ins: u16, size: Option<Size>) -> Result<Target, Error> {
|
||||
fn decode_lower_effective_address(&mut self, memory: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, Error> {
|
||||
let reg = get_low_reg(ins);
|
||||
let mode = get_low_mode(ins);
|
||||
self.get_mode_as_target(memory, mode, reg, size)
|
||||
}
|
||||
|
||||
fn decode_upper_effective_address(&mut self, memory: &mut dyn Addressable, ins: u16, size: Option<Size>) -> Result<Target, Error> {
|
||||
fn decode_upper_effective_address(&mut self, memory: &mut M68kBusPort, ins: u16, size: Option<Size>) -> Result<Target, Error> {
|
||||
let reg = get_high_reg(ins);
|
||||
let mode = get_high_mode(ins);
|
||||
self.get_mode_as_target(memory, mode, reg, size)
|
||||
}
|
||||
|
||||
fn get_extension_displacement(&mut self, memory: &mut dyn Addressable, select: u16) -> Result<i32, Error> {
|
||||
fn get_extension_displacement(&mut self, memory: &mut M68kBusPort, select: u16) -> Result<i32, Error> {
|
||||
let result = match select {
|
||||
0b00 | 0b01 => 0,
|
||||
0b10 => sign_extend_to_long(self.read_instruction_word(memory)? as u32, Size::Word),
|
||||
|
@ -701,7 +702,7 @@ impl M68kDecoder {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
fn decode_extension_word(&mut self, memory: &mut dyn Addressable, areg: Option<u8>) -> Result<Target, Error> {
|
||||
fn decode_extension_word(&mut self, memory: &mut M68kBusPort, areg: Option<u8>) -> Result<Target, Error> {
|
||||
let brief_extension = self.read_instruction_word(memory)?;
|
||||
|
||||
let use_brief = (brief_extension & 0x0100) == 0;
|
||||
|
@ -754,7 +755,7 @@ impl M68kDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_mode_as_target(&mut self, memory: &mut dyn Addressable, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
|
||||
pub(super) fn get_mode_as_target(&mut self, memory: &mut M68kBusPort, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
|
||||
let value = match mode {
|
||||
0b000 => Target::DirectDReg(reg),
|
||||
0b001 => Target::DirectAReg(reg),
|
||||
|
@ -801,10 +802,10 @@ impl M68kDecoder {
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn dump_disassembly(&mut self, memory: &mut dyn Addressable, start: u32, length: u32) {
|
||||
pub fn dump_disassembly(&mut self, memory: &mut M68kBusPort, start: u32, length: u32) {
|
||||
let mut next = start;
|
||||
while next < (start + length) {
|
||||
match self.decode_at(memory, self.clock, next) {
|
||||
match self.decode_at(memory, self.is_supervisor, next) {
|
||||
Ok(()) => {
|
||||
self.dump_decoded(memory);
|
||||
next = self.end;
|
||||
|
@ -813,7 +814,7 @@ impl M68kDecoder {
|
|||
println!("{:?}", err);
|
||||
match err {
|
||||
Error { native, .. } if native == Exceptions::IllegalInstruction as u32 => {
|
||||
println!(" at {:08x}: {:04x}", self.start, memory.read_beu16(self.clock, self.start as Address).unwrap());
|
||||
println!(" at {:08x}: {:04x}", self.start, memory.port.read_beu16(memory.current_clock, self.start as Address).unwrap());
|
||||
},
|
||||
_ => { },
|
||||
}
|
||||
|
@ -823,10 +824,10 @@ impl M68kDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dump_decoded(&mut self, memory: &mut dyn Addressable) {
|
||||
pub fn dump_decoded(&mut self, memory: &mut M68kBusPort) {
|
||||
let ins_data: Result<String, Error> =
|
||||
(0..((self.end - self.start) / 2)).map(|offset|
|
||||
Ok(format!("{:04x} ", memory.read_beu16(self.clock, (self.start + (offset * 2)) as Address).unwrap()))
|
||||
Ok(format!("{:04x} ", memory.port.read_beu16(memory.current_clock, (self.start + (offset * 2)) as Address).unwrap()))
|
||||
).collect();
|
||||
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
|
||||
use moa_core::debug;
|
||||
use moa_core::{System, Error, ErrorType, ClockDuration, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
||||
use moa_core::{System, Error, ErrorType, ClockTime, ClockDuration, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
||||
|
||||
use crate::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority, FunctionCode, MemType, MemAccess};
|
||||
use crate::state::{M68k, M68kType, ClockCycles, Status, Flags, Exceptions, InterruptPriority};
|
||||
use crate::memory::{MemType, MemAccess};
|
||||
use crate::decode::M68kDecoder;
|
||||
use crate::timing::M68kInstructionTiming;
|
||||
use crate::instructions::{
|
||||
Register,
|
||||
Size,
|
||||
|
@ -30,11 +33,12 @@ pub enum Used {
|
|||
|
||||
impl Steppable for M68k {
|
||||
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
self.step_internal(system)
|
||||
let clocks = self.step_internal(system)?;
|
||||
Ok(self.frequency.period_duration() * clocks as u64)
|
||||
}
|
||||
|
||||
fn on_error(&mut self, system: &System) {
|
||||
self.dump_state(system.clock);
|
||||
fn on_error(&mut self, _system: &System) {
|
||||
self.dump_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,15 +60,11 @@ impl Transmutable for M68k {
|
|||
|
||||
|
||||
impl M68k {
|
||||
#[allow(dead_code)]
|
||||
pub fn is_running(&self) -> bool {
|
||||
self.state.status != Status::Stopped
|
||||
}
|
||||
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
self.current_clock = system.clock;
|
||||
pub fn step_internal(&mut self, system: &System) -> Result<ClockCycles, Error> {
|
||||
//self.current_clock = system.clock;
|
||||
self.init_cycle(system.clock);
|
||||
match self.state.status {
|
||||
Status::Init => self.init(),
|
||||
Status::Init => self.reset_cpu(),
|
||||
Status::Stopped => Err(Error::new("CPU stopped")),
|
||||
Status::Running => {
|
||||
match self.cycle_one(system) {
|
||||
|
@ -73,7 +73,7 @@ impl M68k {
|
|||
// TODO match arm conditional is temporary: illegal instructions generate a top level error in order to debug and fix issues with decode
|
||||
//Err(Error { err: ErrorType::Processor, native, .. }) if native != Exceptions::IllegalInstruction as u32 => {
|
||||
self.exception(native as u8, false)?;
|
||||
Ok(self.frequency.period_duration() * 4)
|
||||
Ok(4)
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
|
@ -81,20 +81,27 @@ impl M68k {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) -> Result<ClockDuration, Error> {
|
||||
self.state.ssp = self.port.read_beu32(self.current_clock, 0)?;
|
||||
self.state.pc = self.port.read_beu32(self.current_clock, 4)?;
|
||||
self.state.status = Status::Running;
|
||||
Ok(self.frequency.period_duration() * 16)
|
||||
pub fn init_cycle(&mut self, clock: ClockTime) {
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn cycle_one(&mut self, system: &System) -> Result<ClockDuration, Error> {
|
||||
pub fn reset_cpu(&mut self) -> Result<ClockCycles, Error> {
|
||||
self.state.ssp = self.get_address_sized(0, Size::Long)?;
|
||||
self.state.pc = self.get_address_sized(4, Size::Long)?;
|
||||
self.state.status = Status::Running;
|
||||
Ok(16)
|
||||
}
|
||||
|
||||
pub fn cycle_one(&mut self, system: &System) -> Result<ClockCycles, Error> {
|
||||
self.decode_next()?;
|
||||
self.execute_current()?;
|
||||
|
||||
self.check_pending_interrupts(system)?;
|
||||
self.check_breakpoints(system);
|
||||
Ok(self.frequency.period_duration() * self.timing.calculate_clocks(false, 1) as u64)
|
||||
Ok(self.timing.calculate_clocks(false, 1))
|
||||
}
|
||||
|
||||
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), Error> {
|
||||
|
@ -144,9 +151,9 @@ impl M68k {
|
|||
pub fn setup_group0_exception(&mut self, number: u8) -> Result<(), Error> {
|
||||
let sr = self.state.sr;
|
||||
let ins_word = self.decoder.instruction_word;
|
||||
let extra_code = self.state.request.get_type_code();
|
||||
let fault_size = self.state.request.size.in_bytes();
|
||||
let fault_address = self.state.request.address;
|
||||
let extra_code = self.port.request.get_type_code();
|
||||
let fault_size = self.port.request.size.in_bytes();
|
||||
let fault_address = self.port.request.address;
|
||||
|
||||
// Changes to the flags must happen after the previous value has been pushed to the stack
|
||||
self.set_flag(Flags::Supervisor, true);
|
||||
|
@ -164,7 +171,7 @@ impl M68k {
|
|||
self.push_word((ins_word & 0xFFF0) | extra_code)?;
|
||||
|
||||
let vector = self.state.vbr + offset as u32;
|
||||
let addr = self.port.read_beu32(self.current_clock, vector as Address)?;
|
||||
let addr = self.get_address_sized(vector as Address, Size::Long)?;
|
||||
self.set_pc(addr)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -172,7 +179,7 @@ impl M68k {
|
|||
|
||||
pub fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), Error> {
|
||||
let sr = self.state.sr;
|
||||
self.state.request.i_n_bit = true;
|
||||
self.port.request.i_n_bit = true;
|
||||
|
||||
// Changes to the flags must happen after the previous value has been pushed to the stack
|
||||
self.set_flag(Flags::Supervisor, true);
|
||||
|
@ -189,7 +196,7 @@ impl M68k {
|
|||
self.push_word(sr)?;
|
||||
|
||||
let vector = self.state.vbr + offset as u32;
|
||||
let addr = self.port.read_beu32(self.current_clock, vector as Address)?;
|
||||
let addr = self.get_address_sized(vector as Address, Size::Long)?;
|
||||
self.set_pc(addr)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -198,8 +205,8 @@ impl M68k {
|
|||
pub fn decode_next(&mut self) -> Result<(), Error> {
|
||||
self.timing.reset();
|
||||
|
||||
self.start_instruction_request(self.state.pc)?;
|
||||
self.decoder.decode_at(&mut self.port, self.current_clock, self.state.pc)?;
|
||||
let is_supervisor = self.is_supervisor();
|
||||
self.decoder.decode_at(&mut self.port, is_supervisor, self.state.pc)?;
|
||||
|
||||
self.timing.add_instruction(&self.decoder.instruction);
|
||||
|
||||
|
@ -281,7 +288,7 @@ impl M68k {
|
|||
Instruction::PEA(target) => self.execute_pea(target),
|
||||
Instruction::RESET => self.execute_reset(),
|
||||
Instruction::ROL(count, target, size) => self.execute_rol(count, target, size),
|
||||
Instruction::ROR(count, target, size) => self.execute_rol(count, target, size),
|
||||
Instruction::ROR(count, target, size) => self.execute_ror(count, target, size),
|
||||
Instruction::ROXL(count, target, size) => self.execute_roxl(count, target, size),
|
||||
Instruction::ROXR(count, target, size) => self.execute_roxr(count, target, size),
|
||||
Instruction::RTE => self.execute_rte(),
|
||||
|
@ -400,7 +407,7 @@ impl M68k {
|
|||
let mut pair = (value, false);
|
||||
let mut previous_msb = get_msb(pair.0, size);
|
||||
for _ in 0..count {
|
||||
pair = shift_left(pair.0, size, true);
|
||||
pair = shift_left(pair.0, size);
|
||||
if get_msb(pair.0, size) != previous_msb {
|
||||
overflow = true;
|
||||
}
|
||||
|
@ -798,7 +805,7 @@ impl M68k {
|
|||
let count = self.get_target_value(count, size, Used::Once)? % 64;
|
||||
let mut pair = (self.get_target_value(target, size, Used::Twice)?, false);
|
||||
for _ in 0..count {
|
||||
pair = shift_left(pair.0, size, false);
|
||||
pair = shift_left(pair.0, size);
|
||||
}
|
||||
self.set_target_value(target, pair.0, size, Used::Twice)?;
|
||||
|
||||
|
@ -989,8 +996,8 @@ impl M68k {
|
|||
let mut shift = (size.in_bits() as i32) - 8;
|
||||
let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address;
|
||||
while shift >= 0 {
|
||||
let byte = (self.state.d_reg[dreg as usize] >> shift) as u8;
|
||||
self.port.write_u8(self.current_clock, addr, byte)?;
|
||||
let byte = self.state.d_reg[dreg as usize] >> shift;
|
||||
self.set_address_sized(addr, byte, Size::Byte)?;
|
||||
addr += 2;
|
||||
shift -= 8;
|
||||
}
|
||||
|
@ -999,7 +1006,7 @@ impl M68k {
|
|||
let mut shift = (size.in_bits() as i32) - 8;
|
||||
let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address;
|
||||
while shift >= 0 {
|
||||
let byte = self.port.read_u8(self.current_clock, addr)?;
|
||||
let byte = self.get_address_sized(addr, Size::Byte)?;
|
||||
self.state.d_reg[dreg as usize] |= (byte as u32) << shift;
|
||||
addr += 2;
|
||||
shift -= 8;
|
||||
|
@ -1506,60 +1513,24 @@ impl M68k {
|
|||
}
|
||||
|
||||
fn get_address_sized(&mut self, addr: Address, size: Size) -> Result<u32, Error> {
|
||||
self.start_request(addr as u32, size, MemAccess::Read, MemType::Data, false)?;
|
||||
match size {
|
||||
Size::Byte => self.port.read_u8(self.current_clock, addr).map(|value| value as u32),
|
||||
Size::Word => self.port.read_beu16(self.current_clock, addr).map(|value| value as u32),
|
||||
Size::Long => self.port.read_beu32(self.current_clock, addr),
|
||||
}
|
||||
self.port.read_data_sized(self.is_supervisor(), addr, size)
|
||||
}
|
||||
|
||||
fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), Error> {
|
||||
self.start_request(addr as u32, size, MemAccess::Write, MemType::Data, false)?;
|
||||
match size {
|
||||
Size::Byte => self.port.write_u8(self.current_clock, addr, value as u8),
|
||||
Size::Word => self.port.write_beu16(self.current_clock, addr, value as u16),
|
||||
Size::Long => self.port.write_beu32(self.current_clock, addr, value),
|
||||
}
|
||||
}
|
||||
|
||||
fn start_instruction_request(&mut self, addr: u32) -> Result<u32, Error> {
|
||||
self.state.request.i_n_bit = false;
|
||||
self.state.request.code = FunctionCode::program(self.state.sr);
|
||||
self.state.request.access = MemAccess::Read;
|
||||
self.state.request.address = addr;
|
||||
|
||||
validate_address(addr)
|
||||
}
|
||||
|
||||
fn start_request(&mut self, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, Error> {
|
||||
self.state.request.i_n_bit = i_n_bit;
|
||||
self.state.request.code = match mtype {
|
||||
MemType::Program => FunctionCode::program(self.state.sr),
|
||||
MemType::Data => FunctionCode::data(self.state.sr),
|
||||
};
|
||||
|
||||
self.state.request.access = access;
|
||||
self.state.request.address = addr;
|
||||
|
||||
if size == Size::Byte {
|
||||
Ok(addr)
|
||||
} else {
|
||||
validate_address(addr)
|
||||
}
|
||||
self.port.write_data_sized(self.is_supervisor(), addr, value, size)
|
||||
}
|
||||
|
||||
fn push_word(&mut self, value: u16) -> Result<(), Error> {
|
||||
*self.get_stack_pointer_mut() -= 2;
|
||||
let addr = *self.get_stack_pointer_mut();
|
||||
self.start_request(addr, Size::Word, MemAccess::Write, MemType::Data, false)?;
|
||||
self.port.write_beu16(self.current_clock, addr as Address, value)
|
||||
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)
|
||||
}
|
||||
|
||||
fn pop_word(&mut self) -> Result<u16, Error> {
|
||||
let addr = *self.get_stack_pointer_mut();
|
||||
let value = self.port.read_beu16(self.current_clock, addr as Address)?;
|
||||
self.start_request(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)?;
|
||||
*self.get_stack_pointer_mut() += 2;
|
||||
Ok(value)
|
||||
}
|
||||
|
@ -1567,21 +1538,21 @@ impl M68k {
|
|||
fn push_long(&mut self, value: u32) -> Result<(), Error> {
|
||||
*self.get_stack_pointer_mut() -= 4;
|
||||
let addr = *self.get_stack_pointer_mut();
|
||||
self.start_request(addr, Size::Long, MemAccess::Write, MemType::Data, false)?;
|
||||
self.port.write_beu32(self.current_clock, addr as Address, value)
|
||||
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)
|
||||
}
|
||||
|
||||
fn pop_long(&mut self) -> Result<u32, Error> {
|
||||
let addr = *self.get_stack_pointer_mut();
|
||||
let value = self.port.read_beu32(self.current_clock, addr as Address)?;
|
||||
self.start_request(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)?;
|
||||
*self.get_stack_pointer_mut() += 4;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn set_pc(&mut self, value: u32) -> Result<(), Error> {
|
||||
self.state.pc = value;
|
||||
self.start_request(self.state.pc, Size::Word, MemAccess::Read, MemType::Program, true)?;
|
||||
self.port.start_request(self.is_supervisor(), self.state.pc, Size::Word, MemAccess::Read, MemType::Program, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1751,14 +1722,6 @@ impl M68k {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_address(addr: u32) -> Result<u32, Error> {
|
||||
if addr & 0x1 == 0 {
|
||||
Ok(addr)
|
||||
} else {
|
||||
Err(Error::processor(Exceptions::AddressError as u32))
|
||||
}
|
||||
}
|
||||
|
||||
fn overflowing_add_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) {
|
||||
match size {
|
||||
Size::Byte => {
|
||||
|
@ -1804,7 +1767,7 @@ fn overflowing_sub_signed_sized(operand1: u32, operand2: u32, size: Size) -> (u3
|
|||
}
|
||||
}
|
||||
|
||||
fn shift_left(value: u32, size: Size, arithmetic: bool) -> (u32, bool) {
|
||||
fn shift_left(value: u32, size: Size) -> (u32, bool) {
|
||||
let bit = get_msb(value, size);
|
||||
match size {
|
||||
Size::Byte => (((value as u8) << 1) as u32, bit),
|
||||
|
|
|
@ -5,6 +5,7 @@ pub mod decode;
|
|||
pub mod execute;
|
||||
pub mod debugger;
|
||||
pub mod instructions;
|
||||
pub mod memory;
|
||||
pub mod timing;
|
||||
pub mod tests;
|
||||
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
|
||||
use moa_core::{Error, ClockTime, Address, Addressable, BusPort};
|
||||
|
||||
use crate::state::{M68k, Exceptions};
|
||||
use crate::instructions::{Target, Size};
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FunctionCode {
|
||||
Reserved0 = 0,
|
||||
UserData = 1,
|
||||
UserProgram = 2,
|
||||
Reserved3 = 3,
|
||||
Reserved4 = 4,
|
||||
SupervisorData = 5,
|
||||
SupervisorProgram = 6,
|
||||
CpuSpace = 7,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MemType {
|
||||
Program,
|
||||
Data,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MemAccess {
|
||||
Read,
|
||||
Write,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
// TODO change to MemoryState or RequestState or AccessState or maybe even BusState
|
||||
pub struct MemoryRequest {
|
||||
pub i_n_bit: bool,
|
||||
pub access: MemAccess,
|
||||
pub code: FunctionCode,
|
||||
pub size: Size,
|
||||
pub address: u32,
|
||||
}
|
||||
|
||||
impl FunctionCode {
|
||||
pub fn program(is_supervisor: bool) -> Self {
|
||||
if is_supervisor {
|
||||
FunctionCode::SupervisorProgram
|
||||
} else {
|
||||
FunctionCode::UserProgram
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(is_supervisor: bool) -> Self {
|
||||
if is_supervisor {
|
||||
FunctionCode::SupervisorData
|
||||
} else {
|
||||
FunctionCode::UserData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MemoryRequest {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
i_n_bit: false,
|
||||
access: MemAccess::Read,
|
||||
code: FunctionCode::Reserved0,
|
||||
size: Size::Word,
|
||||
address: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryRequest {
|
||||
pub fn get_type_code(&self) -> u16 {
|
||||
let ins = match self.i_n_bit {
|
||||
false => 0x0000,
|
||||
true => 0x0008,
|
||||
};
|
||||
|
||||
let rw = match self.access {
|
||||
MemAccess::Write => 0x0000,
|
||||
MemAccess::Read => 0x0010,
|
||||
};
|
||||
|
||||
ins | rw | (self.code as u16)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct M68kBusPort {
|
||||
pub port: BusPort,
|
||||
pub request: MemoryRequest,
|
||||
pub cycle_start_clock: ClockTime,
|
||||
pub current_clock: ClockTime,
|
||||
}
|
||||
|
||||
|
||||
impl M68k {
|
||||
// TODO should some of the ones from execute.rs move here
|
||||
}
|
||||
|
||||
impl M68kBusPort {
|
||||
pub fn new(port: BusPort) -> Self {
|
||||
Self {
|
||||
port,
|
||||
request: Default::default(),
|
||||
cycle_start_clock: ClockTime::START,
|
||||
current_clock: ClockTime::START,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_width(&self) -> u8 {
|
||||
self.port.data_width()
|
||||
}
|
||||
|
||||
pub fn init_cycle(&mut self, clock: ClockTime) {
|
||||
self.cycle_start_clock = clock;
|
||||
self.current_clock = clock;
|
||||
}
|
||||
|
||||
pub(crate) fn read_instruction_word(&mut self, is_supervisor: bool, addr: u32) -> Result<u16, Error> {
|
||||
self.start_instruction_request(is_supervisor, addr)?;
|
||||
self.port.read_beu16(self.current_clock, addr as Address)
|
||||
}
|
||||
|
||||
pub(crate) fn read_instruction_long(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, Error> {
|
||||
self.start_instruction_request(is_supervisor, addr)?;
|
||||
self.port.read_beu32(self.current_clock, addr as Address)
|
||||
}
|
||||
|
||||
pub(crate) fn read_data_sized(&mut self, is_supervisor: bool, addr: Address, size: Size) -> Result<u32, Error> {
|
||||
self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?;
|
||||
match size {
|
||||
Size::Byte => self.port.read_u8(self.current_clock, addr).map(|value| value as u32),
|
||||
Size::Word => self.port.read_beu16(self.current_clock, addr).map(|value| value as u32),
|
||||
Size::Long => self.port.read_beu32(self.current_clock, addr),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_data_sized(&mut self, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), Error> {
|
||||
self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?;
|
||||
match size {
|
||||
Size::Byte => self.port.write_u8(self.current_clock, addr, value as u8),
|
||||
Size::Word => self.port.write_beu16(self.current_clock, addr, value as u16),
|
||||
Size::Long => self.port.write_beu32(self.current_clock, addr, value),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn start_instruction_request(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, Error> {
|
||||
self.request.i_n_bit = false;
|
||||
self.request.code = FunctionCode::program(is_supervisor);
|
||||
self.request.access = MemAccess::Read;
|
||||
self.request.address = addr;
|
||||
|
||||
validate_address(addr)
|
||||
}
|
||||
|
||||
pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, Error> {
|
||||
self.request.i_n_bit = i_n_bit;
|
||||
self.request.code = match mtype {
|
||||
MemType::Program => FunctionCode::program(is_supervisor),
|
||||
MemType::Data => FunctionCode::data(is_supervisor),
|
||||
};
|
||||
|
||||
self.request.access = access;
|
||||
self.request.address = addr;
|
||||
|
||||
if size == Size::Byte {
|
||||
Ok(addr)
|
||||
} else {
|
||||
validate_address(addr)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dump_memory(&mut self, addr: u32, length: usize) {
|
||||
self.port.dump_memory(self.current_clock, addr as Address, length as u64);
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_address(addr: u32) -> Result<u32, Error> {
|
||||
if addr & 0x1 == 0 {
|
||||
Ok(addr)
|
||||
} else {
|
||||
Err(Error::processor(Exceptions::AddressError as u32))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
pub(crate) struct TargetAccess {
|
||||
must_read: bool,
|
||||
must_write: bool,
|
||||
size: Size,
|
||||
target: Target,
|
||||
}
|
||||
|
||||
impl TargetAccess {
|
||||
pub(crate) fn read_only(size: Size) -> Self {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn read_update(size: Size) -> Self {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn updated_only(size: Size) -> Self {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn get(&mut self, cpu: &M68k) -> Result<u32, Error> {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn set(&mut self, cpu: &M68k, value: u32) -> Result<(), Error> {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn complete(&self) -> Result<Self, Error> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Target {
|
||||
pub(crate) fn read_once(self, size: Size) -> ReadOnceAccess {
|
||||
ReadOnceAccess {
|
||||
size,
|
||||
target: self,
|
||||
accessed: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_update(self, size: Size) -> ReadUpdateAccess {
|
||||
ReadUpdateAccess {
|
||||
size,
|
||||
target: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_once(self, size: Size) -> WriteOnceAccess {
|
||||
WriteOnceAccess {
|
||||
size,
|
||||
target: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub(crate) struct ReadOnceAccess {
|
||||
size: Size,
|
||||
target: Target,
|
||||
accessed: bool,
|
||||
}
|
||||
|
||||
impl ReadOnceAccess {
|
||||
pub(crate) fn get(&mut self, cpu: &M68k) -> Result<u32, Error> {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn complete(&self) -> Result<Self, Error> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ReadUpdateAccess {
|
||||
size: Size,
|
||||
target: Target,
|
||||
}
|
||||
|
||||
impl ReadUpdateAccess {
|
||||
pub(crate) fn get(&mut self, cpu: &M68k) -> Result<u32, Error> {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn set(&mut self, cpu: &M68k, value: u32) -> Result<(), Error> {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn complete(&self) -> Result<Self, Error> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WriteOnceAccess {
|
||||
size: Size,
|
||||
target: Target,
|
||||
}
|
||||
|
||||
impl WriteOnceAccess {
|
||||
pub(crate) fn set(&mut self, cpu: &M68k, value: u32) -> Result<(), Error> {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) fn complete(&self) -> Result<Self, Error> {
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -1,12 +1,14 @@
|
|||
|
||||
use moa_core::{ClockTime, Address, BusPort, Frequency};
|
||||
use moa_core::{ClockTime, BusPort, Frequency};
|
||||
|
||||
use crate::instructions::Size;
|
||||
use crate::decode::M68kDecoder;
|
||||
use crate::debugger::M68kDebugger;
|
||||
use crate::memory::M68kBusPort;
|
||||
use crate::timing::M68kInstructionTiming;
|
||||
|
||||
|
||||
pub type ClockCycles = u16;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum M68kType {
|
||||
|
@ -49,20 +51,6 @@ pub enum Exceptions {
|
|||
LineFEmulator = 11,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FunctionCode {
|
||||
Reserved0 = 0,
|
||||
UserData = 1,
|
||||
UserProgram = 2,
|
||||
Reserved3 = 3,
|
||||
Reserved4 = 4,
|
||||
SupervisorData = 5,
|
||||
SupervisorProgram = 6,
|
||||
CpuSpace = 7,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Status {
|
||||
Init,
|
||||
|
@ -83,31 +71,9 @@ pub enum InterruptPriority {
|
|||
Level7 = 7,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MemType {
|
||||
Program,
|
||||
Data,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MemAccess {
|
||||
Read,
|
||||
Write,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct MemoryRequest {
|
||||
pub i_n_bit: bool,
|
||||
pub access: MemAccess,
|
||||
pub code: FunctionCode,
|
||||
pub size: Size,
|
||||
pub address: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct M68kState {
|
||||
pub status: Status,
|
||||
pub request: MemoryRequest,
|
||||
pub current_ipl: InterruptPriority,
|
||||
pub pending_ipl: InterruptPriority,
|
||||
|
||||
|
@ -129,7 +95,7 @@ pub struct M68k {
|
|||
pub decoder: M68kDecoder,
|
||||
pub timing: M68kInstructionTiming,
|
||||
pub debugger: M68kDebugger,
|
||||
pub port: BusPort,
|
||||
pub port: M68kBusPort,
|
||||
pub current_clock: ClockTime,
|
||||
}
|
||||
|
||||
|
@ -137,7 +103,6 @@ impl Default for M68kState {
|
|||
fn default() -> M68kState {
|
||||
M68kState {
|
||||
status: Status::Init,
|
||||
request: MemoryRequest::default(),
|
||||
current_ipl: InterruptPriority::NoInterrupt,
|
||||
pending_ipl: InterruptPriority::NoInterrupt,
|
||||
|
||||
|
@ -159,23 +124,15 @@ impl M68k {
|
|||
cputype,
|
||||
frequency,
|
||||
state: M68kState::default(),
|
||||
decoder: M68kDecoder::new(cputype, ClockTime::START, 0),
|
||||
decoder: M68kDecoder::new(cputype, true, 0),
|
||||
timing: M68kInstructionTiming::new(cputype, port.data_width()),
|
||||
debugger: M68kDebugger::default(),
|
||||
port,
|
||||
port: M68kBusPort::new(port),
|
||||
current_clock: ClockTime::START,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn reset(&mut self) {
|
||||
self.state = M68kState::default();
|
||||
self.decoder = M68kDecoder::new(self.cputype, ClockTime::START, 0);
|
||||
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
|
||||
self.debugger = M68kDebugger::default();
|
||||
}
|
||||
|
||||
pub fn dump_state(&mut self, clock: ClockTime) {
|
||||
pub fn dump_state(&mut self) {
|
||||
println!("Status: {:?}", self.state.status);
|
||||
println!("PC: {:#010x}", self.state.pc);
|
||||
println!("SR: {:#06x}", self.state.sr);
|
||||
|
@ -187,7 +144,7 @@ impl M68k {
|
|||
|
||||
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
|
||||
println!();
|
||||
self.port.dump_memory(clock, self.state.ssp as Address, 0x40);
|
||||
self.port.dump_memory(self.state.ssp, 0x40);
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
@ -207,49 +164,3 @@ impl InterruptPriority {
|
|||
}
|
||||
}
|
||||
|
||||
impl FunctionCode {
|
||||
pub fn program(sr: u16) -> Self {
|
||||
if sr & Flags::Supervisor as u16 != 0 {
|
||||
FunctionCode::SupervisorProgram
|
||||
} else {
|
||||
FunctionCode::UserProgram
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(sr: u16) -> Self {
|
||||
if sr & Flags::Supervisor as u16 != 0 {
|
||||
FunctionCode::SupervisorData
|
||||
} else {
|
||||
FunctionCode::UserData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MemoryRequest {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
i_n_bit: false,
|
||||
access: MemAccess::Read,
|
||||
code: FunctionCode::Reserved0,
|
||||
size: Size::Word,
|
||||
address: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryRequest {
|
||||
pub fn get_type_code(&self) -> u16 {
|
||||
let ins = match self.i_n_bit {
|
||||
false => 0x0000,
|
||||
true => 0x0008,
|
||||
};
|
||||
|
||||
let rw = match self.access {
|
||||
MemAccess::Write => 0x0000,
|
||||
MemAccess::Read => 0x0010,
|
||||
};
|
||||
|
||||
ins | rw | (self.code as u16)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
use crate::M68kType;
|
||||
use crate::state::ClockCycles;
|
||||
use crate::instructions::{Size, Sign, Direction, Target, Instruction};
|
||||
|
||||
|
||||
|
@ -337,12 +338,12 @@ impl M68kInstructionTiming {
|
|||
self.add_internal(4)
|
||||
}
|
||||
|
||||
pub fn calculate_clocks(&self, branched: bool, reps: u16) -> u16 {
|
||||
pub fn calculate_clocks(&self, branched: bool, reps: u16) -> ClockCycles {
|
||||
//println!("{:?}", self);
|
||||
(self.accesses as u16 * 4)
|
||||
+ self.internal as u16
|
||||
+ (if branched { self.on_branch as u16 } else { 0 })
|
||||
+ self.per_rep as u16 * reps
|
||||
(self.accesses as ClockCycles * 4)
|
||||
+ self.internal as ClockCycles
|
||||
+ (if branched { self.on_branch as ClockCycles } else { 0 })
|
||||
+ self.per_rep as ClockCycles * reps
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
|
@ -46,10 +46,10 @@ const DECODE_TESTS: &'static [TestCase] = &[
|
|||
TestCase { cpu: M68kType::MC68000, data: &[0x0148, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Long, Direction::FromTarget)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x0188, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Word, Direction::ToTarget)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x01C8, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Long, Direction::ToTarget)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE300], ins: Some(Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE200], ins: Some(Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE318], ins: Some(Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE218], ins: Some(Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE300], ins: Some(Instruction::ASL(Target::Immediate(1), Target::DirectDReg(0), Size::Byte)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE200], ins: Some(Instruction::ASR(Target::Immediate(1), Target::DirectDReg(0), Size::Byte)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE318], ins: Some(Instruction::ROL(Target::Immediate(1), Target::DirectDReg(0), Size::Byte)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xE218], ins: Some(Instruction::ROR(Target::Immediate(1), Target::DirectDReg(0), Size::Byte)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xA000], ins: Some(Instruction::UnimplementedA(0xA000)) },
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0xFFFF], ins: Some(Instruction::UnimplementedF(0xFFFF)) },
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
|
|||
BusPort::new(0, 24, 16, system.bus.clone())
|
||||
};
|
||||
let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port);
|
||||
cpu.init().unwrap();
|
||||
cpu.init_cycle().unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
||||
|
||||
|
|
|
@ -829,7 +829,7 @@ impl Ym2612 {
|
|||
pub fn set_register(&mut self, clock: ClockTime, bank: u8, reg: u8, data: u8) {
|
||||
// Keep a copy for debugging purposes, and if the original values are needed
|
||||
self.registers[bank as usize * 256 + reg as usize] = data;
|
||||
//println!("set {:x} to {:x}", bank as usize * 256 + reg as usize, data);
|
||||
println!("set {:x} to {:x}", bank as usize * 256 + reg as usize, data);
|
||||
|
||||
//warn!("{}: set reg {}{:x} to {:x}", DEV_NAME, bank, reg, data);
|
||||
match reg {
|
||||
|
|
|
@ -225,7 +225,7 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(),
|
|||
assert_value(cpu.state.sr, expected.sr, "sr")?;
|
||||
assert_value(cpu.state.pc, expected.pc, "pc")?;
|
||||
|
||||
let addr_mask = cpu.port.address_mask();
|
||||
let addr_mask = cpu.port.port.address_mask();
|
||||
|
||||
// Load instructions into memory
|
||||
for (i, ins) in expected.prefetch.iter().enumerate() {
|
||||
|
@ -268,8 +268,8 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
|
|||
if args.debug {
|
||||
case.dump();
|
||||
println!("");
|
||||
initial_cpu.dump_state(system.clock);
|
||||
cpu.dump_state(system.clock);
|
||||
initial_cpu.dump_state();
|
||||
cpu.dump_state();
|
||||
}
|
||||
println!("FAILED: {}", err.msg);
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@ RESULTS=latest.txt
|
|||
cd $LOCATION
|
||||
echo "Last run on $DATE at commit $COMMIT" | tee $RESULTS
|
||||
echo "" | tee -a $RESULTS
|
||||
cargo run -- -q --testsuite "../jsmoo/misc/tests/GeneratedTests/z80/v1/" --check-timings | tee -a $RESULTS
|
||||
cargo run -- -q --testsuite "../jsmoo/misc/tests/GeneratedTests/z80/v1/" --check-undocumented | tee -a $RESULTS
|
||||
}
|
||||
|
|
4
todo.txt
4
todo.txt
|
@ -1,4 +1,8 @@
|
|||
|
||||
* I want to make some kind of memory transaction object that does everything in a contained but logical way, including handling exception
|
||||
information needed about the last access, and adjusting the pre/post inc/dec
|
||||
|
||||
* the debug dump things should not used the clocked addressing, but use a debugging mode thing of some kind so as not to influence the sim state
|
||||
* the way you're doing debugging is so bad, and something's broken with the Z80
|
||||
* debugger should return a breakpoint error to the frontend, so that the frontend still runs, instead of suspending the current execution
|
||||
* can you make the debugger workable in the web ui in some way? So you can have a debug window open while playing the game or something
|
||||
|
|
Loading…
Reference in New Issue