mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-21 19:30:52 +00:00
Fixed tests failing due to wrapping into past the end of memory
This commit is contained in:
parent
aaa7952dd0
commit
f205e231b6
@ -2,11 +2,18 @@
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ErrorType {
|
||||
Assertion,
|
||||
Emulator,
|
||||
Emulator(EmulatorErrorKind),
|
||||
Processor,
|
||||
Breakpoint,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum EmulatorErrorKind {
|
||||
Misc,
|
||||
MemoryAlignment,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
pub err: ErrorType,
|
||||
@ -15,11 +22,25 @@ pub struct Error {
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(msg: &str) -> Error {
|
||||
pub fn new<S>(msg: S) -> Error
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Error {
|
||||
err: ErrorType::Emulator,
|
||||
err: ErrorType::Emulator(EmulatorErrorKind::Misc),
|
||||
native: 0,
|
||||
msg: msg.to_string(),
|
||||
msg: msg.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emulator<S>(kind: EmulatorErrorKind, msg: S) -> Error
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Error {
|
||||
err: ErrorType::Emulator(kind),
|
||||
native: 0,
|
||||
msg: msg.into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,19 +52,25 @@ impl Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn breakpoint(msg: &str) -> Error {
|
||||
pub fn breakpoint<S>(msg: S) -> Error
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Error {
|
||||
err: ErrorType::Breakpoint,
|
||||
native: 0,
|
||||
msg: msg.to_string(),
|
||||
msg: msg.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assertion(msg: &str) -> Error {
|
||||
pub fn assertion<S>(msg: S) -> Error
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Error {
|
||||
err: ErrorType::Assertion,
|
||||
native: 0,
|
||||
msg: msg.to_string(),
|
||||
msg: msg.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
|
||||
use std::fs;
|
||||
use std::cmp;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::info;
|
||||
use crate::error::Error;
|
||||
use crate::error::{Error, EmulatorErrorKind};
|
||||
use crate::clock::ClockTime;
|
||||
use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_beu16};
|
||||
|
||||
@ -274,20 +275,17 @@ pub struct BusPort {
|
||||
offset: Address,
|
||||
address_mask: Address,
|
||||
data_width: u8,
|
||||
error_on_alignment: bool,
|
||||
subdevice: Rc<RefCell<Bus>>,
|
||||
}
|
||||
|
||||
impl BusPort {
|
||||
pub fn new(offset: Address, address_bits: u8, data_bits: u8, bus: Rc<RefCell<Bus>>) -> Self {
|
||||
let mut address_mask = 0;
|
||||
for _ in 0..address_bits {
|
||||
address_mask = (address_mask << 1) | 0x01;
|
||||
}
|
||||
|
||||
Self {
|
||||
offset,
|
||||
address_mask,
|
||||
address_mask: (1 << address_bits) - 1,
|
||||
data_width: data_bits / 8,
|
||||
error_on_alignment: false,
|
||||
subdevice: bus,
|
||||
}
|
||||
}
|
||||
@ -311,21 +309,31 @@ 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) {
|
||||
let end = std::cmp::min(i + self.data_width as usize, data.len());
|
||||
subdevice.read(clock, addr + i as Address, &mut data[i..end])?;
|
||||
let addr_index = (addr + i as Address) & self.address_mask;
|
||||
let end = cmp::min(i + self.data_width as usize, data.len());
|
||||
subdevice.read(clock, addr_index, &mut data[i..end])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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) {
|
||||
let addr_index = (addr + i as Address) & self.address_mask;
|
||||
let end = std::cmp::min(i + self.data_width as usize, data.len());
|
||||
subdevice.write(clock, addr + i as Address, &data[i..end])?;
|
||||
subdevice.write(clock, addr_index, &data[i..end])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -305,7 +305,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_abcd(&mut self, src: Target, dest: Target) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, Size::Byte, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, Size::Byte, Used::Twice)?;
|
||||
@ -330,7 +329,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_add(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -342,7 +340,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_adda(&mut self, src: Target, dest: Register, size: Size) -> Result<(), Error> {
|
||||
let src_val = sign_extend_to_long(self.get_target_value(src, size, Used::Once)?, size) as u32;
|
||||
let dest_val = *self.get_a_reg_mut(dest);
|
||||
@ -351,7 +348,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_addx(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -373,7 +369,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_and(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -383,20 +378,17 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_and_to_ccr(&mut self, value: u8) -> Result<(), Error> {
|
||||
self.state.sr = (self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) & (value as u16));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_and_to_sr(&mut self, value: u16) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
self.set_sr(self.state.sr & value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_asd(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> {
|
||||
let count = self.get_target_value(count, size, Used::Once)? % 64;
|
||||
let value = self.get_target_value(target, size, Used::Twice)?;
|
||||
@ -430,7 +422,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), Error> {
|
||||
let should_branch = self.get_current_condition(cond);
|
||||
if should_branch {
|
||||
@ -442,7 +433,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bra(&mut self, offset: i32) -> Result<(), Error> {
|
||||
if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) {
|
||||
self.state.pc -= 2;
|
||||
@ -451,7 +441,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bsr(&mut self, offset: i32) -> Result<(), Error> {
|
||||
self.push_long(self.state.pc)?;
|
||||
let sp = *self.get_stack_pointer_mut();
|
||||
@ -463,7 +452,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bchg(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), Error> {
|
||||
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
||||
let mut src_val = self.get_target_value(target, size, Used::Twice)?;
|
||||
@ -473,7 +461,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bclr(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), Error> {
|
||||
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
||||
let mut src_val = self.get_target_value(target, size, Used::Twice)?;
|
||||
@ -483,7 +470,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bset(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), Error> {
|
||||
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
||||
let mut value = self.get_target_value(target, size, Used::Twice)?;
|
||||
@ -493,7 +479,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_btst(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), Error> {
|
||||
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
||||
let value = self.get_target_value(target, size, Used::Once)?;
|
||||
@ -501,7 +486,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bfchg(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), Error> {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -512,7 +496,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bfclr(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), Error> {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -523,7 +506,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bfexts(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), Error> {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -540,7 +522,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bfextu(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), Error> {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -551,7 +532,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bfset(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), Error> {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -562,7 +542,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_bftst(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), Error> {
|
||||
let (offset, width) = self.get_bit_field_args(offset, width);
|
||||
let mask = get_bit_field_mask(offset, width);
|
||||
@ -572,7 +551,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_chk(&mut self, target: Target, reg: Register, size: Size) -> Result<(), Error> {
|
||||
let upper_bound = sign_extend_to_long(self.get_target_value(target, size, Used::Once)?, size);
|
||||
let dreg = sign_extend_to_long(self.state.d_reg[reg as usize], size);
|
||||
@ -589,7 +567,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_clr(&mut self, target: Target, size: Size) -> Result<(), Error> {
|
||||
if self.cputype == M68kType::MC68000 {
|
||||
self.get_target_value(target, size, Used::Twice)?;
|
||||
@ -602,7 +579,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_cmp(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Once)?;
|
||||
@ -612,7 +588,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_cmpa(&mut self, src: Target, reg: Register, size: Size) -> Result<(), Error> {
|
||||
let src_val = sign_extend_to_long(self.get_target_value(src, size, Used::Once)?, size) as u32;
|
||||
let dest_val = *self.get_a_reg_mut(reg);
|
||||
@ -622,7 +597,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_dbcc(&mut self, cond: Condition, reg: Register, offset: i16) -> Result<(), Error> {
|
||||
let condition_true = self.get_current_condition(cond);
|
||||
if !condition_true {
|
||||
@ -638,7 +612,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_divw(&mut self, src: Target, dest: Register, sign: Sign) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, Size::Word, Used::Once)?;
|
||||
if src_val == 0 {
|
||||
@ -679,7 +652,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_divl(&mut self, src: Target, dest_h: Option<Register>, dest_l: Register, sign: Sign) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, Size::Long, Used::Once)?;
|
||||
if src_val == 0 {
|
||||
@ -713,7 +685,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_eor(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -723,20 +694,17 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_eor_to_ccr(&mut self, value: u8) -> Result<(), Error> {
|
||||
self.set_sr((self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) ^ (value as u16)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_eor_to_sr(&mut self, value: u16) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
self.set_sr(self.state.sr ^ value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_exg(&mut self, target1: Target, target2: Target) -> Result<(), Error> {
|
||||
let value1 = self.get_target_value(target1, Size::Long, Used::Twice)?;
|
||||
let value2 = self.get_target_value(target2, Size::Long, Used::Twice)?;
|
||||
@ -745,7 +713,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_ext(&mut self, reg: Register, from_size: Size, to_size: Size) -> Result<(), Error> {
|
||||
let input = get_value_sized(self.state.d_reg[reg as usize], from_size);
|
||||
let result = match (from_size, to_size) {
|
||||
@ -759,13 +726,11 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_illegal(&mut self) -> Result<(), Error> {
|
||||
self.exception(Exceptions::IllegalInstruction as u8, false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_jmp(&mut self, target: Target) -> Result<(), Error> {
|
||||
let addr = self.get_target_address(target)?;
|
||||
if let Err(err) = self.set_pc(addr) {
|
||||
@ -775,7 +740,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_jsr(&mut self, target: Target) -> Result<(), Error> {
|
||||
let previous_pc = self.state.pc;
|
||||
let addr = self.get_target_address(target)?;
|
||||
@ -791,7 +755,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_lea(&mut self, target: Target, reg: Register) -> Result<(), Error> {
|
||||
let value = self.get_target_address(target)?;
|
||||
let addr = self.get_a_reg_mut(reg);
|
||||
@ -799,7 +762,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_link(&mut self, reg: Register, offset: i32) -> Result<(), Error> {
|
||||
*self.get_stack_pointer_mut() -= 4;
|
||||
let sp = *self.get_stack_pointer_mut();
|
||||
@ -810,7 +772,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_lsd(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> {
|
||||
let count = self.get_target_value(count, size, Used::Once)? % 64;
|
||||
let mut pair = (self.get_target_value(target, size, Used::Twice)?, false);
|
||||
@ -831,7 +792,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_move(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
self.set_logic_flags(src_val, size);
|
||||
@ -839,7 +799,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_movea(&mut self, src: Target, reg: Register, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let src_val = sign_extend_to_long(src_val, size) as u32;
|
||||
@ -848,14 +807,12 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_move_from_sr(&mut self, target: Target) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
self.set_target_value(target, self.state.sr as u32, Size::Word, Used::Once)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_move_to_sr(&mut self, target: Target) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
let value = self.get_target_value(target, Size::Word, Used::Once)? as u16;
|
||||
@ -863,14 +820,12 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_move_to_ccr(&mut self, target: Target) -> Result<(), Error> {
|
||||
let value = self.get_target_value(target, Size::Word, Used::Once)? as u16;
|
||||
self.set_sr((self.state.sr & 0xFF00) | (value & 0x00FF));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_movec(&mut self, target: Target, control_reg: ControlRegister, dir: Direction) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
match dir {
|
||||
@ -888,7 +843,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_movem(&mut self, target: Target, size: Size, dir: Direction, mask: u16) -> Result<(), Error> {
|
||||
let addr = self.get_target_address(target)?;
|
||||
|
||||
@ -936,7 +890,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn move_memory_to_registers(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, Error> {
|
||||
for i in 0..8 {
|
||||
if (mask & 0x01) != 0 {
|
||||
@ -955,7 +908,6 @@ impl M68k {
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn move_registers_to_memory(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, Error> {
|
||||
for i in 0..8 {
|
||||
if (mask & 0x01) != 0 {
|
||||
@ -975,7 +927,6 @@ impl M68k {
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn move_registers_to_memory_reverse(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result<u32, Error> {
|
||||
for i in (0..8).rev() {
|
||||
if (mask & 0x01) != 0 {
|
||||
@ -995,7 +946,6 @@ impl M68k {
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_movep(&mut self, dreg: Register, areg: Register, offset: i16, size: Size, dir: Direction) -> Result<(), Error> {
|
||||
match dir {
|
||||
Direction::ToTarget => {
|
||||
@ -1022,7 +972,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_moveq(&mut self, data: u8, reg: Register) -> Result<(), Error> {
|
||||
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
|
||||
self.state.d_reg[reg as usize] = value;
|
||||
@ -1030,7 +979,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_moveusp(&mut self, target: Target, dir: Direction) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
match dir {
|
||||
@ -1040,7 +988,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_mulw(&mut self, src: Target, dest: Register, sign: Sign) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, Size::Word, Used::Once)?;
|
||||
let dest_val = get_value_sized(self.state.d_reg[dest as usize], Size::Word);
|
||||
@ -1054,7 +1001,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_mull(&mut self, src: Target, dest_h: Option<Register>, dest_l: Register, sign: Sign) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, Size::Long, Used::Once)?;
|
||||
let dest_val = get_value_sized(self.state.d_reg[dest_l as usize], Size::Long);
|
||||
@ -1071,7 +1017,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_nbcd(&mut self, dest: Target) -> Result<(), Error> {
|
||||
let dest_val = self.get_target_value(dest, Size::Byte, Used::Twice)?;
|
||||
let result = self.execute_sbcd_val(dest_val, 0)?;
|
||||
@ -1079,7 +1024,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_neg(&mut self, target: Target, size: Size) -> Result<(), Error> {
|
||||
let original = self.get_target_value(target, size, Used::Twice)?;
|
||||
let (result, overflow) = overflowing_sub_signed_sized(0, original, size);
|
||||
@ -1090,7 +1034,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_negx(&mut self, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
let extend = self.get_flag(Flags::Extend) as u32;
|
||||
@ -1111,7 +1054,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_not(&mut self, target: Target, size: Size) -> Result<(), Error> {
|
||||
let mut value = self.get_target_value(target, size, Used::Twice)?;
|
||||
value = get_value_sized(!value, size);
|
||||
@ -1120,7 +1062,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_or(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -1130,34 +1071,29 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_or_to_ccr(&mut self, value: u8) -> Result<(), Error> {
|
||||
self.set_sr((self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) | (value as u16)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_or_to_sr(&mut self, value: u16) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
self.set_sr(self.state.sr | value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_pea(&mut self, target: Target) -> Result<(), Error> {
|
||||
let value = self.get_target_address(target)?;
|
||||
self.push_long(value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_reset(&mut self) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
// TODO this only resets external devices and not internal ones
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_rod(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> {
|
||||
let count = self.get_target_value(count, size, Used::Once)? % 64;
|
||||
let mut pair = (self.get_target_value(target, size, Used::Twice)?, false);
|
||||
@ -1174,7 +1110,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_roxd(&mut self, count: Target, target: Target, size: Size, shift_dir: ShiftDirection) -> Result<(), Error> {
|
||||
let count = self.get_target_value(count, size, Used::Once)? % 64;
|
||||
let mut pair = (self.get_target_value(target, size, Used::Twice)?, false);
|
||||
@ -1192,7 +1127,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_rte(&mut self) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
let sr = self.pop_word()?;
|
||||
@ -1210,7 +1144,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_rtr(&mut self) -> Result<(), Error> {
|
||||
let ccr = self.pop_word()?;
|
||||
let addr = self.pop_long()?;
|
||||
@ -1222,7 +1155,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_rts(&mut self) -> Result<(), Error> {
|
||||
self.debugger.stack_tracer.pop_return();
|
||||
let addr = self.pop_long()?;
|
||||
@ -1233,7 +1165,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_scc(&mut self, cond: Condition, target: Target) -> Result<(), Error> {
|
||||
let condition_true = self.get_current_condition(cond);
|
||||
if condition_true {
|
||||
@ -1244,7 +1175,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_stop(&mut self, flags: u16) -> Result<(), Error> {
|
||||
self.require_supervisor()?;
|
||||
self.set_sr(flags);
|
||||
@ -1252,7 +1182,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_sbcd(&mut self, src: Target, dest: Target) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, Size::Byte, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, Size::Byte, Used::Twice)?;
|
||||
@ -1261,7 +1190,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_sbcd_val(&mut self, src_val: u32, dest_val: u32) -> Result<u32, Error> {
|
||||
let extend_flag = self.get_flag(Flags::Extend) as u32;
|
||||
let src_parts = get_nibbles_from_byte(src_val);
|
||||
@ -1283,7 +1211,6 @@ impl M68k {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_sub(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -1295,7 +1222,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_suba(&mut self, src: Target, dest: Register, size: Size) -> Result<(), Error> {
|
||||
let src_val = sign_extend_to_long(self.get_target_value(src, size, Used::Once)?, size) as u32;
|
||||
let dest_val = *self.get_a_reg_mut(dest);
|
||||
@ -1304,7 +1230,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_subx(&mut self, src: Target, dest: Target, size: Size) -> Result<(), Error> {
|
||||
let src_val = self.get_target_value(src, size, Used::Once)?;
|
||||
let dest_val = self.get_target_value(dest, size, Used::Twice)?;
|
||||
@ -1326,7 +1251,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_swap(&mut self, reg: Register) -> Result<(), Error> {
|
||||
let value = self.state.d_reg[reg as usize];
|
||||
self.state.d_reg[reg as usize] = ((value & 0x0000FFFF) << 16) | ((value & 0xFFFF0000) >> 16);
|
||||
@ -1334,7 +1258,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_tas(&mut self, target: Target) -> Result<(), Error> {
|
||||
let value = self.get_target_value(target, Size::Byte, Used::Twice)?;
|
||||
self.set_flag(Flags::Negative, (value & 0x80) != 0);
|
||||
@ -1345,20 +1268,17 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_tst(&mut self, target: Target, size: Size) -> Result<(), Error> {
|
||||
let value = self.get_target_value(target, size, Used::Once)?;
|
||||
self.set_logic_flags(value, size);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_trap(&mut self, number: u8) -> Result<(), Error> {
|
||||
self.exception(32 + number, false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_trapv(&mut self) -> Result<(), Error> {
|
||||
if self.get_flag(Flags::Overflow) {
|
||||
self.exception(Exceptions::TrapvInstruction as u8, false)?;
|
||||
@ -1366,7 +1286,6 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_unlk(&mut self, reg: Register) -> Result<(), Error> {
|
||||
let value = *self.get_a_reg_mut(reg);
|
||||
*self.get_stack_pointer_mut() = value;
|
||||
@ -1376,14 +1295,12 @@ impl M68k {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_unimplemented_a(&mut self, _: u16) -> Result<(), Error> {
|
||||
self.state.pc -= 2;
|
||||
self.exception(Exceptions::LineAEmulator as u8, false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn execute_unimplemented_f(&mut self, _: u16) -> Result<(), Error> {
|
||||
self.state.pc -= 2;
|
||||
self.exception(Exceptions::LineFEmulator as u8, false)?;
|
||||
@ -1658,12 +1575,10 @@ impl M68k {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_stack_pointer_mut(&mut self) -> &mut u32 {
|
||||
if self.is_supervisor() { &mut self.state.ssp } else { &mut self.state.usp }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_a_reg(&self, reg: Register) -> u32 {
|
||||
if reg == 7 {
|
||||
if self.is_supervisor() { self.state.ssp } else { self.state.usp }
|
||||
@ -1672,7 +1587,6 @@ impl M68k {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_a_reg_mut(&mut self, reg: Register) -> &mut u32 {
|
||||
if reg == 7 {
|
||||
if self.is_supervisor() { &mut self.state.ssp } else { &mut self.state.usp }
|
||||
@ -1681,12 +1595,10 @@ impl M68k {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_supervisor(&self) -> bool {
|
||||
self.state.sr & (Flags:: Supervisor as u16) != 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn require_supervisor(&self) -> Result<(), Error> {
|
||||
if self.is_supervisor() {
|
||||
Ok(())
|
||||
@ -1700,12 +1612,10 @@ impl M68k {
|
||||
self.state.sr = value & mask;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_flag(&self, flag: Flags) -> bool {
|
||||
(self.state.sr & (flag as u16)) != 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_flag(&mut self, flag: Flags, value: bool) {
|
||||
self.state.sr = (self.state.sr & !(flag as u16)) | (if value { flag as u16 } else { 0 });
|
||||
}
|
||||
@ -1909,7 +1819,6 @@ fn get_sub_overflow(operand1: u32, operand2: u32, result: u32, size: Size) -> bo
|
||||
(msb1 && msb2 && !msb_res) || (!msb1 && !msb2 && msb_res)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_msb(value: u32, size: Size) -> bool {
|
||||
match size {
|
||||
Size::Byte => (value & 0x00000080) != 0,
|
||||
@ -1918,7 +1827,6 @@ fn get_msb(value: u32, size: Size) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_msb_mask(value: u32, size: Size) -> u32 {
|
||||
match size {
|
||||
Size::Byte => value & 0x00000080,
|
||||
|
@ -479,7 +479,7 @@ impl Z80 {
|
||||
fn execute_ini(&mut self) -> Result<(), Error> {
|
||||
let b = self.get_register_value(Register::B);
|
||||
let c = self.get_register_value(Register::C);
|
||||
let value = self.get_ioport_value(b, c)?;
|
||||
let value = self.read_ioport_value(b, c)?;
|
||||
|
||||
self.set_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL), value as u16)?;
|
||||
let hl = self.get_register_pair_value(RegisterPair::HL).wrapping_add(1);
|
||||
@ -495,7 +495,7 @@ impl Z80 {
|
||||
fn execute_inic(&mut self, reg: Register) -> Result<(), Error> {
|
||||
let b = self.get_register_value(Register::B);
|
||||
let c = self.get_register_value(Register::C);
|
||||
let value = self.get_ioport_value(b, c)?;
|
||||
let value = self.read_ioport_value(b, c)?;
|
||||
|
||||
self.set_register_value(reg, value);
|
||||
self.set_numeric_flags(value as u16, Size::Byte);
|
||||
@ -510,7 +510,7 @@ impl Z80 {
|
||||
|
||||
fn execute_inx(&mut self, n: u8) -> Result<(), Error> {
|
||||
let a = self.get_register_value(Register::A);
|
||||
let value = self.get_ioport_value(a, n)?;
|
||||
let value = self.read_ioport_value(a, n)?;
|
||||
self.set_register_value(Register::A, value);
|
||||
Ok(())
|
||||
}
|
||||
@ -630,7 +630,7 @@ impl Z80 {
|
||||
let b = self.get_register_value(Register::B);
|
||||
let c = self.get_register_value(Register::C);
|
||||
let value = self.get_register_value(reg);
|
||||
self.set_ioport_value(b, c, value)?;
|
||||
self.write_ioport_value(b, c, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -640,7 +640,7 @@ impl Z80 {
|
||||
fn execute_outx(&mut self, n: u8) -> Result<(), Error> {
|
||||
let a = self.get_register_value(Register::A);
|
||||
let value = self.get_register_value(Register::A);
|
||||
self.set_ioport_value(a, n, value)?;
|
||||
self.write_ioport_value(a, n, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1101,7 +1101,7 @@ impl Z80 {
|
||||
self.port.write_leu16(self.current_clock, addr as Address, value)
|
||||
}
|
||||
|
||||
fn get_ioport_value(&mut self, upper: u8, lower: u8) -> Result<u8, Error> {
|
||||
fn read_ioport_value(&mut self, upper: u8, lower: u8) -> Result<u8, Error> {
|
||||
let addr = ((upper as Address) << 8) | (lower as Address);
|
||||
if let Some(io) = self.ioport.as_mut() {
|
||||
Ok(io.read_u8(self.current_clock, addr)?)
|
||||
@ -1110,7 +1110,7 @@ impl Z80 {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ioport_value(&mut self, upper: u8, lower: u8, value: u8) -> Result<(), Error> {
|
||||
fn write_ioport_value(&mut self, upper: u8, lower: u8, value: u8) -> Result<(), Error> {
|
||||
let addr = ((upper as Address) << 8) | (lower as Address);
|
||||
if let Some(io) = self.ioport.as_mut() {
|
||||
io.write_u8(self.current_clock, addr, value)?
|
||||
@ -1221,12 +1221,10 @@ impl Z80 {
|
||||
self.set_flags(FLAGS_CARRY_HALF_CARRY, carry_flag | half_carry_flag);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_flag(&self, flag: Flags) -> bool {
|
||||
self.get_flags() & (flag as u8) != 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_flag(&mut self, flag: Flags, value: bool) {
|
||||
self.state.reg[Register::F as usize] &= !(flag as u8);
|
||||
if value {
|
||||
@ -1234,12 +1232,10 @@ impl Z80 {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_flags(&self) -> u8 {
|
||||
self.state.reg[Register::F as usize]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_flags(&mut self, mask: u8, values: u8) {
|
||||
self.state.reg[Register::F as usize] = (self.state.reg[Register::F as usize] & !mask) | values;
|
||||
}
|
||||
@ -1273,7 +1269,6 @@ fn sub_words(operand1: u16, operand2: u16) -> (u16, bool, bool, bool) {
|
||||
(result, carry, overflow, half_carry)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_msb(value: u16, size: Size) -> bool {
|
||||
match size {
|
||||
Size::Byte => (value & 0x0080) != 0,
|
||||
|
@ -1,4 +1,4 @@
|
||||
Last run on 2023-05-14 at commit 7e62a2691c552f3a628ac18b3eaba2a45265abde
|
||||
Last run on 2023-05-14 at commit aaa7952dd0cf0ab6e33946ce0ae1aa91920e5405
|
||||
|
||||
00.json completed, all passed!
|
||||
01.json completed, all passed!
|
||||
@ -36,7 +36,7 @@ Last run on 2023-05-14 at commit 7e62a2691c552f3a628ac18b3eaba2a45265abde
|
||||
1f.json completed, all passed!
|
||||
20.json completed, all passed!
|
||||
21.json completed, all passed!
|
||||
22.json completed: 999 passed, 1 FAILED
|
||||
22.json completed, all passed!
|
||||
23.json completed, all passed!
|
||||
24.json completed, all passed!
|
||||
25.json completed, all passed!
|
||||
@ -636,12 +636,12 @@ fd ae.json completed, all passed!
|
||||
fd b6.json completed, all passed!
|
||||
fd be.json completed, all passed!
|
||||
fd e1.json completed, all passed!
|
||||
fd e3.json completed: 999 passed, 1 FAILED
|
||||
fd e3.json completed, all passed!
|
||||
fd e5.json completed, all passed!
|
||||
fd e9.json completed, all passed!
|
||||
fd f9.json completed, all passed!
|
||||
fe.json completed, all passed!
|
||||
ff.json completed, all passed!
|
||||
|
||||
passed: 629558, failed: 12442, total 98%
|
||||
passed: 629560, failed: 12440, total 98%
|
||||
completed in 0m 32s
|
||||
|
@ -9,7 +9,7 @@ use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
use std::fs::{self, File};
|
||||
|
||||
use clap::{Parser, ArgEnum};
|
||||
use clap::Parser;
|
||||
use flate2::read::GzDecoder;
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
@ -20,13 +20,6 @@ use moa_z80::instructions::InterruptMode;
|
||||
use moa_z80::state::Flags;
|
||||
use moa_z80::state::Status;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ArgEnum)]
|
||||
enum Selection {
|
||||
Include,
|
||||
Exclude,
|
||||
ExcludeAddr,
|
||||
Only,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
@ -47,11 +40,12 @@ struct Args {
|
||||
/// Check undocumented instructions
|
||||
#[clap(short = 'u', long)]
|
||||
check_undocumented: bool,
|
||||
/// Check instruction timings
|
||||
#[clap(short = 't', long)]
|
||||
check_timings: bool,
|
||||
/// Directory to the test suite to run
|
||||
#[clap(long, default_value = DEFAULT_RAD_TESTS)]
|
||||
testsuite: String,
|
||||
#[clap(long, short, arg_enum, default_value_t = Selection::Include)]
|
||||
exceptions: Selection,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -90,6 +84,9 @@ struct TestState {
|
||||
ram: Vec<(u16, u8)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct TestCycle(u16, Option<u8>, String);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct TestPort {
|
||||
addr: u16,
|
||||
@ -105,6 +102,8 @@ struct TestCase {
|
||||
#[serde(rename(deserialize = "final"))]
|
||||
final_state: TestState,
|
||||
#[serde(default)]
|
||||
cycles: Vec<TestCycle>,
|
||||
#[serde(default)]
|
||||
ports: Vec<TestPort>,
|
||||
}
|
||||
|
||||
@ -279,10 +278,16 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc<RefCell<Bus>>, expected:
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn step_cpu_and_assert(cpu: &mut Z80, system: &System, io_bus: Rc<RefCell<Bus>>, case: &TestCase, check_extra_flags: bool) -> Result<(), Error> {
|
||||
let _clock_elapsed = cpu.step(&system)?;
|
||||
fn step_cpu_and_assert(cpu: &mut Z80, system: &System, io_bus: Rc<RefCell<Bus>>, case: &TestCase, args: &Args) -> Result<(), Error> {
|
||||
let clock_elapsed = cpu.step(&system)?;
|
||||
|
||||
assert_state(&cpu, &system, io_bus, &case.final_state, check_extra_flags, &case.ports)?;
|
||||
assert_state(&cpu, &system, io_bus, &case.final_state, args.check_extra_flags, &case.ports)?;
|
||||
if args.check_timings {
|
||||
let cycles = clock_elapsed / cpu.frequency.period_duration();
|
||||
if cycles != case.cycles.len() as Address {
|
||||
return Err(Error::assertion(&format!("expected instruction to take {} cycles, but took {}", case.cycles.len(), cycles)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -291,7 +296,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
|
||||
let (mut cpu, system, io_bus) = init_execute_test(Z80Type::Z80, &case.initial_state, &case.ports).unwrap();
|
||||
let mut initial_cpu = cpu.clone();
|
||||
|
||||
let result = step_cpu_and_assert(&mut cpu, &system, io_bus, case, args.check_extra_flags);
|
||||
let result = step_cpu_and_assert(&mut cpu, &system, io_bus, case, args);
|
||||
|
||||
match result {
|
||||
Ok(()) => Ok(()),
|
||||
|
3
todo.txt
3
todo.txt
@ -7,10 +7,13 @@
|
||||
|
||||
* go through flags on m68k and see if you can fix the remaining ones and/or clean up the implementation
|
||||
|
||||
* you could possibly make a Z80MemoryPort type that wraps the BusPort type and which impls Addressable, which can be passed into the decoder
|
||||
to auto-insert things like the refresh counter, as well as the record all bus timings whenever any mem access is performed
|
||||
* should you make Address a newtype and add From impls for each type of numeric, and add utils to wrap address at certain boundaries and such
|
||||
* should you make a means of storing different kinds of buses?
|
||||
* should you make buses hide their RcRefCell?
|
||||
|
||||
|
||||
* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used
|
||||
* sound doesn't work on a lot of games... is it a problem with the Z80 accessing the YM2612, or the lack of YM timers? or something else?
|
||||
* make the ym generate audio in sync so the DAC timings can be more accurate
|
||||
|
Loading…
Reference in New Issue
Block a user