moa/src/cpus/m68k/execute.rs
2021-10-26 12:17:59 -07:00

1166 lines
50 KiB
Rust

use crate::system::System;
use crate::error::{ErrorType, Error};
use crate::devices::{ClockElapsed, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
use super::instructions::{
Register,
Size,
Sign,
Direction,
ShiftDirection,
XRegister,
BaseRegister,
IndexRegister,
RegOrImmediate,
ControlRegister,
Condition,
Target,
Instruction,
sign_extend_to_long,
};
const DEV_NAME: &'static str = "m68k-cpu";
use super::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority};
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
self.step_internal(system)?;
Ok((1_000_000_000 / self.frequency as u64) * 4)
}
fn on_error(&mut self, system: &System) {
self.dump_state(system);
}
fn on_debug(&mut self) {
self.enable_debugging();
}
}
impl Interruptable for M68k {
fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error> {
let ipl = if state {
InterruptPriority::from_u8(priority)
} else {
InterruptPriority::NoInterrupt
};
if ipl != self.state.pending_ipl {
self.state.pending_ipl = ipl;
if ipl != InterruptPriority::NoInterrupt {
self.state.ipl_ack_num = number;
}
}
Ok(())
}
}
impl Transmutable for M68k {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
Some(self)
}
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
Some(self)
}
}
impl M68k {
#[allow(dead_code)]
pub fn is_running(&self) -> bool {
self.state.status != Status::Stopped
}
pub fn step_internal(&mut self, system: &System) -> Result<(), Error> {
match self.state.status {
Status::Init => self.init(system),
Status::Stopped => Err(Error::new("CPU stopped")),
Status::Running => {
match self.cycle_one(system) {
Ok(()) => Ok(()),
//Err(Error { err: ErrorType::Processor, native, .. }) => {
// TODO temporary: we are passing illegal instructions upward in order to fix them
Err(Error { err: ErrorType::Processor, native, .. }) if native != Exceptions::IllegalInstruction as u32 => {
self.exception(system, native as u8, false)?;
Ok(())
},
Err(err) => Err(err),
}
},
}
}
pub fn init(&mut self, system: &System) -> Result<(), Error> {
self.state.msp = system.get_bus().read_beu32(0)?;
self.state.pc = system.get_bus().read_beu32(4)?;
self.state.status = Status::Running;
Ok(())
}
pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> {
self.timer.cycle.start();
self.decode_next(system)?;
self.execute_current(system)?;
self.timer.cycle.end();
//if (self.timer.cycle.events % 500) == 0 {
// println!("{}", self.timer);
//}
self.check_pending_interrupts(system)?;
Ok(())
}
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), Error> {
let current_ipl = self.state.current_ipl as u8;
let pending_ipl = self.state.pending_ipl as u8;
if self.state.pending_ipl != InterruptPriority::NoInterrupt {
let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8;
if (pending_ipl >= priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl {
debug!("{} interrupt: {} {}", DEV_NAME, pending_ipl, priority_mask);
self.state.current_ipl = self.state.pending_ipl;
self.exception(system, self.state.ipl_ack_num, true)?;
return Ok(());
}
}
if pending_ipl < current_ipl {
self.state.current_ipl = self.state.pending_ipl;
}
Ok(())
}
pub fn exception(&mut self, system: &System, number: u8, update_ipl: bool) -> Result<(), Error> {
debug!("{}: raising exception {}", DEV_NAME, number);
let offset = (number as u16) << 2;
self.push_word(system, offset)?;
self.push_long(system, self.state.pc)?;
self.push_word(system, self.state.sr)?;
self.set_flag(Flags::Supervisor, true);
self.set_flag(Flags::Tracing, false);
if update_ipl {
self.state.sr = (self.state.sr & !(Flags::IntMask as u16)) | ((self.state.current_ipl as u16) << 8);
}
self.state.pc = system.get_bus().read_beu32((self.state.vbr + offset as u32) as Address)?;
Ok(())
}
pub fn decode_next(&mut self, system: &System) -> Result<(), Error> {
self.check_breakpoints();
self.timer.decode.start();
self.decoder.decode_at(system, self.state.pc)?;
self.timer.decode.end();
if self.debugger.use_tracing {
self.decoder.dump_decoded(system);
}
if self.debugger.use_debugger {
self.run_debugger(system);
}
self.state.pc = self.decoder.end;
Ok(())
}
pub fn execute_current(&mut self, system: &System) -> Result<(), Error> {
self.timer.execute.start();
match self.decoder.instruction {
Instruction::ADD(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let (result, carry) = overflowing_add_sized(existing, value, size);
match dest {
Target::DirectAReg(_) => { },
_ => self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size)),
}
self.set_target_value(system, dest, result, size)?;
},
Instruction::AND(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let result = get_value_sized(existing & value, size);
self.set_target_value(system, dest, result, size)?;
self.set_logic_flags(result, size);
},
Instruction::ANDtoCCR(value) => {
self.state.sr = self.state.sr & (value as u16);
},
Instruction::ANDtoSR(value) => {
self.require_supervisor()?;
self.state.sr = self.state.sr & value;
},
Instruction::ASd(count, target, size, shift_dir) => {
let count = self.get_target_value(system, count, size)? % 64;
let mut pair = (self.get_target_value(system, target, size)?, false);
let original = pair.0;
for _ in 0..count {
pair = shift_operation(pair.0, size, shift_dir, true);
}
self.set_logic_flags(pair.0, size);
if pair.1 {
self.set_flag(Flags::Carry, true);
self.set_flag(Flags::Extend, true);
}
if get_msb(pair.0, size) != get_msb(original, size) {
self.set_flag(Flags::Overflow, true);
}
self.set_target_value(system, target, pair.0, size)?;
},
Instruction::Bcc(cond, offset) => {
let should_branch = self.get_current_condition(cond);
if should_branch {
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
}
},
Instruction::BRA(offset) => {
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
},
Instruction::BSR(offset) => {
self.push_long(system, self.state.pc)?;
let sp = *self.get_stack_pointer_mut();
self.debugger.stack_tracer.push_return(sp);
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
},
Instruction::BTST(bitnum, target, size) => {
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
let value = self.get_target_value(system, target, size)?;
self.set_bit_test_flags(value, bitnum, size);
},
Instruction::BCHG(bitnum, target, size) => {
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
let mut value = self.get_target_value(system, target, size)?;
let mask = self.set_bit_test_flags(value, bitnum, size);
value = (value & !mask) | (!(value & mask) & mask);
self.set_target_value(system, target, value, size)?;
},
Instruction::BCLR(bitnum, target, size) => {
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
let mut value = self.get_target_value(system, target, size)?;
let mask = self.set_bit_test_flags(value, bitnum, size);
value = value & !mask;
self.set_target_value(system, target, value, size)?;
},
Instruction::BSET(bitnum, target, size) => {
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
let mut value = self.get_target_value(system, target, size)?;
let mask = self.set_bit_test_flags(value, bitnum, size);
value = value | mask;
self.set_target_value(system, target, value, size)?;
},
Instruction::BFCHG(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.set_target_value(system, target, (value & !mask) | (!field & mask), Size::Long)?;
},
Instruction::BFCLR(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.set_target_value(system, target, value & !mask, Size::Long)?;
},
Instruction::BFEXTS(target, offset, width, reg) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
let right_offset = 32 - offset - width;
let mut ext = 0;
for _ in 0..(offset + right_offset) {
ext = (ext >> 1) | 0x80000000;
}
self.state.d_reg[reg as usize] = (field >> right_offset) | ext;
},
Instruction::BFEXTU(target, offset, width, reg) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.state.d_reg[reg as usize] = field >> (32 - offset - width);
},
//Instruction::BFFFO(target, offset, width, reg) => {
//},
//Instruction::BFINS(reg, target, offset, width) => {
//},
Instruction::BFSET(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
self.set_target_value(system, target, value | mask, Size::Long)?;
},
Instruction::BFTST(target, offset, width) => {
let (offset, width) = self.get_bit_field_args(offset, width);
let mask = get_bit_field_mask(offset, width);
let value = self.get_target_value(system, target, Size::Long)?;
let field = value & mask;
self.set_bit_field_test_flags(field, get_bit_field_msb(offset));
},
//Instruction::BKPT(u8) => {
//},
Instruction::CLR(target, size) => {
self.set_target_value(system, target, 0, size)?;
// Clear flags except Zero flag
self.state.sr = (self.state.sr & 0xFFF0) | (Flags::Zero as u16);
},
Instruction::CMP(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let (result, carry) = overflowing_sub_sized(existing, value, size);
self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size));
},
Instruction::CMPA(src, reg, size) => {
let value = sign_extend_to_long(self.get_target_value(system, src, size)?, size) as u32;
let existing = *self.get_a_reg_mut(reg);
let (result, carry) = overflowing_sub_sized(existing, value, Size::Long);
self.set_compare_flags(result, Size::Long, carry, get_overflow(existing, value, result, Size::Long));
},
Instruction::DBcc(cond, reg, offset) => {
let condition_true = self.get_current_condition(cond);
if !condition_true {
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);
if next != -1 {
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
}
}
},
Instruction::DIVW(src, dest, sign) => {
let value = self.get_target_value(system, src, Size::Word)?;
if value == 0 {
self.exception(system, Exceptions::ZeroDivide as u8, false)?;
return Ok(());
}
let existing = get_value_sized(self.state.d_reg[dest as usize], Size::Long);
let (remainder, quotient) = match sign {
Sign::Signed => {
let value = sign_extend_to_long(value, Size::Word) as u32;
(existing % value, existing / value)
},
Sign::Unsigned => (existing % value, existing / value),
};
self.set_compare_flags(quotient as u32, Size::Long, false, (quotient & 0xFFFF0000) != 0);
self.state.d_reg[dest as usize] = (remainder << 16) | (0xFFFF & quotient);
},
Instruction::DIVL(src, dest_h, dest_l, sign) => {
let value = self.get_target_value(system, src, Size::Long)?;
if value == 0 {
self.exception(system, Exceptions::ZeroDivide as u8, false)?;
return Ok(());
}
let existing_l = self.state.d_reg[dest_l as usize];
let (remainder, quotient) = match sign {
Sign::Signed => {
let value = (value as i32) as i64;
let existing = match dest_h {
Some(reg) => (((self.state.d_reg[reg as usize] as u64) << 32) | (existing_l as u64)) as i64,
None => (existing_l as i32) as i64,
};
((existing % value) as u64, (existing / value) as u64)
},
Sign::Unsigned => {
let value = value as u64;
let existing_h = dest_h.map(|reg| self.state.d_reg[reg as usize]).unwrap_or(0);
let existing = ((existing_h as u64) << 32) | (existing_l as u64);
(existing % value, existing / value)
},
};
self.set_compare_flags(quotient as u32, Size::Long, false, (quotient & 0xFFFFFFFF00000000) != 0);
if let Some(dest_h) = dest_h {
self.state.d_reg[dest_h as usize] = remainder as u32;
}
self.state.d_reg[dest_l as usize] = quotient as u32;
},
Instruction::EOR(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let result = get_value_sized(existing ^ value, size);
self.set_target_value(system, dest, result, size)?;
self.set_logic_flags(result, size);
},
Instruction::EORtoCCR(value) => {
self.state.sr = self.state.sr ^ (value as u16);
},
Instruction::EORtoSR(value) => {
self.require_supervisor()?;
self.state.sr = self.state.sr ^ value;
},
//Instruction::EXG(Target, Target) => {
//},
Instruction::EXT(reg, from_size, to_size) => {
let input = self.state.d_reg[reg as usize];
let result = match (from_size, to_size) {
(Size::Byte, Size::Word) => ((((input as u8) as i8) as i16) as u16) as u32,
(Size::Word, Size::Long) => (((input as u16) as i16) as i32) as u32,
(Size::Byte, Size::Long) => (((input as u8) as i8) as i32) as u32,
_ => panic!("Unsupported size for EXT instruction"),
};
set_value_sized(&mut self.state.d_reg[reg as usize], result, to_size);
self.set_logic_flags(result, to_size);
},
//Instruction::ILLEGAL => {
//},
Instruction::JMP(target) => {
self.state.pc = self.get_target_address(system, target)?;
},
Instruction::JSR(target) => {
self.push_long(system, self.state.pc)?;
let sp = *self.get_stack_pointer_mut();
self.debugger.stack_tracer.push_return(sp);
self.state.pc = self.get_target_address(system, target)?;
},
Instruction::LEA(target, reg) => {
let value = self.get_target_address(system, target)?;
let addr = self.get_a_reg_mut(reg);
*addr = value;
},
Instruction::LINK(reg, offset) => {
let value = *self.get_a_reg_mut(reg);
self.push_long(system, value)?;
let sp = *self.get_stack_pointer_mut();
let addr = self.get_a_reg_mut(reg);
*addr = sp;
*self.get_stack_pointer_mut() = sp.wrapping_add((offset as i32) as u32);
},
Instruction::LSd(count, target, size, shift_dir) => {
let count = self.get_target_value(system, count, size)? % 64;
let mut pair = (self.get_target_value(system, target, size)?, false);
for _ in 0..count {
pair = shift_operation(pair.0, size, shift_dir, false);
}
self.set_logic_flags(pair.0, size);
if pair.1 {
self.set_flag(Flags::Carry, true);
self.set_flag(Flags::Extend, true);
}
self.set_target_value(system, target, pair.0, size)?;
},
Instruction::MOVE(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
self.set_logic_flags(value, size);
self.set_target_value(system, dest, value, size)?;
},
Instruction::MOVEA(src, reg, size) => {
let value = self.get_target_value(system, src, size)?;
let value = sign_extend_to_long(value, size) as u32;
let addr = self.get_a_reg_mut(reg);
*addr = value;
},
Instruction::MOVEfromSR(target) => {
self.require_supervisor()?;
self.set_target_value(system, target, self.state.sr as u32, Size::Word)?;
},
Instruction::MOVEtoSR(target) => {
self.require_supervisor()?;
self.state.sr = self.get_target_value(system, target, Size::Word)? as u16;
},
Instruction::MOVEtoCCR(target) => {
let value = self.get_target_value(system, target, Size::Word)? as u16;
self.state.sr = (self.state.sr & 0xFF00) | (value & 0x00FF);
},
Instruction::MOVEC(target, control_reg, dir) => {
self.require_supervisor()?;
match dir {
Direction::FromTarget => {
let value = self.get_target_value(system, target, Size::Long)?;
let addr = self.get_control_reg_mut(control_reg);
*addr = value;
},
Direction::ToTarget => {
let addr = self.get_control_reg_mut(control_reg);
let value = *addr;
self.set_target_value(system, target, value, Size::Long)?;
},
}
},
Instruction::MOVEUSP(target, dir) => {
self.require_supervisor()?;
match dir {
Direction::ToTarget => self.set_target_value(system, target, self.state.usp, Size::Long)?,
Direction::FromTarget => { self.state.usp = self.get_target_value(system, target, Size::Long)?; },
}
},
Instruction::MOVEM(target, size, dir, mask) => {
self.execute_movem(system, target, size, dir, mask)?;
},
Instruction::MOVEQ(data, reg) => {
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
self.state.d_reg[reg as usize] = value;
self.set_logic_flags(value, Size::Long);
},
Instruction::MULW(src, dest, sign) => {
let value = self.get_target_value(system, src, Size::Word)?;
let existing = get_value_sized(self.state.d_reg[dest as usize], Size::Word);
let result = match sign {
Sign::Signed => ((((existing as u16) as i16) as i64) * (((value as u16) as i16) as i64)) as u64,
Sign::Unsigned => existing as u64 * value as u64,
};
self.set_compare_flags(result as u32, Size::Long, false, (result & 0xFFFFFFFF00000000) != 0);
self.state.d_reg[dest as usize] = result as u32;
},
Instruction::MULL(src, dest_h, dest_l, sign) => {
let value = self.get_target_value(system, src, Size::Long)?;
let existing = get_value_sized(self.state.d_reg[dest_l as usize], Size::Long);
let result = match sign {
Sign::Signed => (((existing as i32) as i64) * ((value as i32) as i64)) as u64,
Sign::Unsigned => existing as u64 * value as u64,
};
self.set_compare_flags(result as u32, Size::Long, false, false);
if let Some(dest_h) = dest_h {
self.state.d_reg[dest_h as usize] = (result >> 32) as u32;
}
self.state.d_reg[dest_l as usize] = (result & 0x00000000FFFFFFFF) as u32;
},
//Instruction::NBCD(Target) => {
//},
Instruction::NEG(target, size) => {
let original = self.get_target_value(system, target, size)?;
let (value, _) = (0 as u32).overflowing_sub(original);
self.set_target_value(system, target, value, size)?;
self.set_compare_flags(value, size, value != 0, get_overflow(0, original, value, size));
},
//Instruction::NEGX(Target, Size) => {
//},
Instruction::NOP => { },
Instruction::NOT(target, size) => {
let mut value = self.get_target_value(system, target, size)?;
value = get_value_sized(!value, size);
self.set_target_value(system, target, value, size)?;
self.set_logic_flags(value, size);
},
Instruction::OR(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let result = get_value_sized(existing | value, size);
self.set_target_value(system, dest, result, size)?;
self.set_logic_flags(result, size);
},
Instruction::ORtoCCR(value) => {
self.state.sr = self.state.sr | (value as u16);
},
Instruction::ORtoSR(value) => {
self.require_supervisor()?;
self.state.sr = self.state.sr | value;
},
Instruction::PEA(target) => {
let value = self.get_target_address(system, target)?;
self.push_long(system, value)?;
},
//Instruction::RESET => {
// self.require_supervisor()?;
//},
Instruction::ROd(count, target, size, shift_dir) => {
let count = self.get_target_value(system, count, size)? % 64;
let mut pair = (self.get_target_value(system, target, size)?, false);
for _ in 0..count {
pair = rotate_operation(pair.0, size, shift_dir, None);
}
self.set_logic_flags(pair.0, size);
if pair.1 {
self.set_flag(Flags::Carry, true);
}
self.set_target_value(system, target, pair.0, size)?;
},
Instruction::ROXd(count, target, size, shift_dir) => {
let count = self.get_target_value(system, count, size)? % 64;
let mut pair = (self.get_target_value(system, target, size)?, false);
for _ in 0..count {
pair = rotate_operation(pair.0, size, shift_dir, Some(self.get_flag(Flags::Extend)));
self.set_flag(Flags::Extend, pair.1);
}
self.set_logic_flags(pair.0, size);
if pair.1 {
self.set_flag(Flags::Carry, true);
}
self.set_target_value(system, target, pair.0, size)?;
},
Instruction::RTE => {
self.require_supervisor()?;
self.state.sr = self.pop_word(system)?;
self.state.pc = self.pop_long(system)?;
let _ = self.pop_word(system)?;
},
//Instruction::RTR => {
//},
Instruction::RTS => {
self.debugger.stack_tracer.pop_return();
self.state.pc = self.pop_long(system)?;
},
Instruction::Scc(cond, target) => {
let condition_true = self.get_current_condition(cond);
if condition_true {
self.set_target_value(system, target, 0xFF, Size::Byte)?;
} else {
self.set_target_value(system, target, 0x00, Size::Byte)?;
}
},
Instruction::STOP(flags) => {
self.require_supervisor()?;
self.state.sr = flags;
self.state.status = Status::Stopped;
},
Instruction::SUB(src, dest, size) => {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let (result, carry) = overflowing_sub_sized(existing, value, size);
match dest {
Target::DirectAReg(_) => { },
_ => self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size)),
}
self.set_target_value(system, dest, result, size)?;
},
Instruction::SWAP(reg) => {
let value = self.state.d_reg[reg as usize];
self.state.d_reg[reg as usize] = ((value & 0x0000FFFF) << 16) | ((value & 0xFFFF0000) >> 16);
},
//Instruction::TAS(Target) => {
//},
Instruction::TST(target, size) => {
let value = self.get_target_value(system, target, size)?;
self.set_logic_flags(value, size);
},
Instruction::TRAP(number) => {
self.exception(system, 32 + number, false)?;
},
Instruction::TRAPV => {
if self.get_flag(Flags::Overflow) {
self.exception(system, Exceptions::TrapvInstruction as u8, false)?;
}
},
Instruction::UNLK(reg) => {
let value = *self.get_a_reg_mut(reg);
*self.get_stack_pointer_mut() = value;
let new_value = self.pop_long(system)?;
let addr = self.get_a_reg_mut(reg);
*addr = new_value;
},
_ => { return Err(Error::new("Unsupported instruction")); },
}
self.timer.execute.end();
Ok(())
}
fn execute_movem(&mut self, system: &System, target: Target, size: Size, dir: Direction, mut mask: u16) -> Result<(), Error> {
let mut addr = self.get_target_address(system, 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 self.cputype >= M68kType::MC68020 {
match target {
Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => {
let a_reg_mut = self.get_a_reg_mut(reg);
*a_reg_mut = addr + (mask.count_ones() * size.in_bytes());
}
_ => { },
}
}
if dir == Direction::ToTarget {
for i in (0..8).rev() {
if (mask & 0x01) != 0 {
let value = *self.get_a_reg_mut(i);
addr -= size.in_bytes();
set_address_sized(system, addr as Address, value, size)?;
}
mask >>= 1;
}
for i in (0..8).rev() {
if (mask & 0x01) != 0 {
addr -= size.in_bytes();
set_address_sized(system, addr as Address, self.state.d_reg[i], size)?;
}
mask >>= 1;
}
} else {
let mut mask = mask;
for i in 0..8 {
if (mask & 0x01) != 0 {
self.state.d_reg[i] = sign_extend_to_long(get_address_sized(system, addr as Address, size)?, size) as u32;
addr += size.in_bytes();
}
mask >>= 1;
}
for i in 0..8 {
if (mask & 0x01) != 0 {
*self.get_a_reg_mut(i) = sign_extend_to_long(get_address_sized(system, addr as Address, size)?, size) as u32;
addr += size.in_bytes();
}
mask >>= 1;
}
}
// If it was Post-Inc/Pre-Dec target, then update the value
match target {
Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => {
let a_reg_mut = self.get_a_reg_mut(reg);
*a_reg_mut = addr;
}
_ => { },
}
Ok(())
}
fn push_word(&mut self, system: &System, value: u16) -> Result<(), Error> {
let reg = self.get_stack_pointer_mut();
*reg -= 2;
system.get_bus().write_beu16(*reg as Address, value)
}
fn pop_word(&mut self, system: &System) -> Result<u16, Error> {
let reg = self.get_stack_pointer_mut();
let value = system.get_bus().read_beu16(*reg as Address)?;
*reg += 2;
Ok(value)
}
fn push_long(&mut self, system: &System, value: u32) -> Result<(), Error> {
let reg = self.get_stack_pointer_mut();
*reg -= 4;
system.get_bus().write_beu32(*reg as Address, value)
}
fn pop_long(&mut self, system: &System) -> Result<u32, Error> {
let reg = self.get_stack_pointer_mut();
let value = system.get_bus().read_beu32(*reg as Address)?;
*reg += 4;
Ok(value)
}
pub fn get_target_value(&mut self, system: &System, target: Target, size: Size) -> Result<u32, Error> {
match target {
Target::Immediate(value) => Ok(value),
Target::DirectDReg(reg) => Ok(get_value_sized(self.state.d_reg[reg as usize], size)),
Target::DirectAReg(reg) => Ok(get_value_sized(*self.get_a_reg_mut(reg), size)),
Target::IndirectAReg(reg) => get_address_sized(system, *self.get_a_reg_mut(reg) as Address, size),
Target::IndirectARegInc(reg) => {
let addr = self.get_a_reg_mut(reg);
let result = get_address_sized(system, *addr as Address, size);
*addr += size.in_bytes();
result
},
Target::IndirectARegDec(reg) => {
let addr = self.get_a_reg_mut(reg);
*addr -= size.in_bytes();
get_address_sized(system, *addr as Address, size)
},
Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
get_address_sized(system, base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, size)
},
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
get_address_sized(system, intermediate.wrapping_add(outer_disp as u32) as Address, size)
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
get_address_sized(system, intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size)
},
Target::IndirectMemory(addr) => {
get_address_sized(system, addr as Address, size)
},
}
}
pub fn set_target_value(&mut self, system: &System, target: Target, value: u32, size: Size) -> Result<(), Error> {
match target {
Target::DirectDReg(reg) => {
set_value_sized(&mut self.state.d_reg[reg as usize], value, size);
},
Target::DirectAReg(reg) => {
set_value_sized(self.get_a_reg_mut(reg), value, size);
},
Target::IndirectAReg(reg) => {
set_address_sized(system, *self.get_a_reg_mut(reg) as Address, value, size)?;
},
Target::IndirectARegInc(reg) => {
let addr = self.get_a_reg_mut(reg);
set_address_sized(system, *addr as Address, value, size)?;
*addr = (*addr).wrapping_add(size.in_bytes());
},
Target::IndirectARegDec(reg) => {
let addr = self.get_a_reg_mut(reg);
*addr = (*addr).wrapping_sub(size.in_bytes());
set_address_sized(system, *addr as Address, value, size)?;
},
Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
set_address_sized(system, base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, value, size)?;
},
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
set_address_sized(system, intermediate.wrapping_add(outer_disp as u32) as Address, value, size)?;
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
set_address_sized(system, intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size)?;
},
Target::IndirectMemory(addr) => {
set_address_sized(system, addr as Address, value, size)?;
},
_ => return Err(Error::new(&format!("Unimplemented addressing target: {:?}", target))),
}
Ok(())
}
pub fn get_target_address(&mut self, system: &System, target: Target) -> Result<u32, Error> {
let addr = match target {
Target::IndirectAReg(reg) | Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => *self.get_a_reg_mut(reg),
Target::IndirectRegOffset(base_reg, index_reg, displacement) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32)
},
Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
intermediate.wrapping_add(outer_disp as u32)
},
Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => {
let base_value = self.get_base_reg_value(base_reg);
let index_value = self.get_index_reg_value(&index_reg);
let intermediate = get_address_sized(system, base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32)
},
Target::IndirectMemory(addr) => {
addr
},
_ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))),
};
Ok(addr)
}
pub fn get_bit_field_args(&self, offset: RegOrImmediate, width: RegOrImmediate) -> (u32, u32) {
let offset = self.get_reg_or_immediate(offset);
let mut width = self.get_reg_or_immediate(width) % 32;
if width == 0 {
width = 32;
}
(offset, width)
}
fn get_reg_or_immediate(&self, value: RegOrImmediate) -> u32 {
match value {
RegOrImmediate::DReg(reg) => self.state.d_reg[reg as usize],
RegOrImmediate::Immediate(value) => value as u32,
}
}
fn get_x_reg_value(&self, xreg: XRegister) -> u32 {
match xreg {
XRegister::DReg(reg) => self.state.d_reg[reg as usize],
XRegister::AReg(reg) => self.state.a_reg[reg as usize],
}
}
fn get_base_reg_value(&self, base_reg: BaseRegister) -> u32 {
match base_reg {
BaseRegister::None => 0,
BaseRegister::PC => self.decoder.start + 2,
BaseRegister::AReg(reg) if reg == 7 => if self.is_supervisor() { self.state.msp } else { self.state.usp },
BaseRegister::AReg(reg) => self.state.a_reg[reg as usize],
}
}
fn get_index_reg_value(&self, index_reg: &Option<IndexRegister>) -> i32 {
match index_reg {
None => 0,
Some(IndexRegister { xreg, scale, size }) => {
sign_extend_to_long(self.get_x_reg_value(*xreg), *size) << scale
}
}
}
fn get_control_reg_mut(&mut self, control_reg: ControlRegister) -> &mut u32 {
match control_reg {
ControlRegister::VBR => &mut self.state.vbr,
}
}
#[inline(always)]
fn get_stack_pointer_mut(&mut self) -> &mut u32 {
if self.is_supervisor() { &mut self.state.msp } else { &mut self.state.usp }
}
#[inline(always)]
fn get_a_reg_mut(&mut self, reg: Register) -> &mut u32 {
if reg == 7 {
if self.is_supervisor() { &mut self.state.msp } else { &mut self.state.usp }
} else {
&mut self.state.a_reg[reg as usize]
}
}
#[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(())
} else {
Err(Error::processor(Exceptions::PrivilegeViolation as u32))
}
}
#[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 });
}
fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool, overflow: bool) {
let value = sign_extend_to_long(value, size);
let mut flags = 0x0000;
if value < 0 {
flags |= Flags::Negative as u16;
}
if value == 0 {
flags |= Flags::Zero as u16;
}
if carry {
flags |= Flags::Carry as u16;
}
if overflow {
flags |= Flags::Overflow as u16;
}
self.state.sr = (self.state.sr & 0xFFF0) | flags;
}
fn set_logic_flags(&mut self, value: u32, size: Size) {
let mut flags = 0x0000;
if get_msb(value, size) {
flags |= Flags::Negative as u16;
}
if value == 0 {
flags |= Flags::Zero as u16;
}
self.state.sr = (self.state.sr & 0xFFF0) | flags;
}
fn set_bit_test_flags(&mut self, value: u32, bitnum: u32, size: Size) -> u32 {
let mask = 0x1 << (bitnum % size.in_bits());
self.set_flag(Flags::Zero, (value & mask) == 0);
mask
}
fn set_bit_field_test_flags(&mut self, field: u32, msb_mask: u32) {
let mut flags = 0x0000;
if (field & msb_mask) != 0 {
flags |= Flags::Negative as u16;
}
if field == 0 {
flags |= Flags::Zero as u16;
}
self.state.sr = (self.state.sr & 0xFFF0) | flags;
}
fn get_current_condition(&self, cond: Condition) -> bool {
match cond {
Condition::True => true,
Condition::False => false,
Condition::High => !self.get_flag(Flags::Carry) && !self.get_flag(Flags::Zero),
Condition::LowOrSame => self.get_flag(Flags::Carry) || self.get_flag(Flags::Zero),
Condition::CarryClear => !self.get_flag(Flags::Carry),
Condition::CarrySet => self.get_flag(Flags::Carry),
Condition::NotEqual => !self.get_flag(Flags::Zero),
Condition::Equal => self.get_flag(Flags::Zero),
Condition::OverflowClear => !self.get_flag(Flags::Overflow),
Condition::OverflowSet => self.get_flag(Flags::Overflow),
Condition::Plus => !self.get_flag(Flags::Negative),
Condition::Minus => self.get_flag(Flags::Negative),
Condition::GreaterThanOrEqual => (self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)) || (!self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)),
Condition::LessThan => (self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow)) || (!self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)),
Condition::GreaterThan =>
(self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow) && !self.get_flag(Flags::Zero))
|| (!self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow) && !self.get_flag(Flags::Zero)),
Condition::LessThanOrEqual =>
self.get_flag(Flags::Zero)
|| (self.get_flag(Flags::Negative) && !self.get_flag(Flags::Overflow))
|| (!self.get_flag(Flags::Negative) && self.get_flag(Flags::Overflow)),
}
}
}
fn overflowing_add_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) {
match size {
Size::Byte => {
let (result, carry) = (operand1 as u8).overflowing_add(operand2 as u8);
(result as u32, carry)
},
Size::Word => {
let (result, carry) = (operand1 as u16).overflowing_add(operand2 as u16);
(result as u32, carry)
},
Size::Long => operand1.overflowing_add(operand2),
}
}
fn overflowing_sub_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) {
match size {
Size::Byte => {
let (result, carry) = (operand1 as u8).overflowing_sub(operand2 as u8);
(result as u32, carry)
},
Size::Word => {
let (result, carry) = (operand1 as u16).overflowing_sub(operand2 as u16);
(result as u32, carry)
},
Size::Long => operand1.overflowing_sub(operand2),
}
}
fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) {
match dir {
ShiftDirection::Left => {
let bit = get_msb(value, size);
match size {
Size::Byte => (((value as u8) << 1) as u32, bit),
Size::Word => (((value as u16) << 1) as u32, bit),
Size::Long => ((value << 1) as u32, bit),
}
},
ShiftDirection::Right => {
let mask = if arithmetic { get_msb_mask(value, size) } else { 0 };
((value >> 1) | mask, (value & 0x1) != 0)
},
}
}
fn rotate_operation(value: u32, size: Size, dir: ShiftDirection, use_extend: Option<bool>) -> (u32, bool) {
match dir {
ShiftDirection::Left => {
let bit = get_msb(value, size);
let mask = if use_extend.unwrap_or(bit) { 0x01 } else { 0x00 };
match size {
Size::Byte => (mask | ((value as u8) << 1) as u32, bit),
Size::Word => (mask | ((value as u16) << 1) as u32, bit),
Size::Long => (mask | (value << 1) as u32, bit),
}
},
ShiftDirection::Right => {
let bit = if (value & 0x01) != 0 { true } else { false };
let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 };
((value >> 1) | mask, bit)
},
}
}
fn get_value_sized(value: u32, size: Size) -> u32 {
match size {
Size::Byte => { 0x000000FF & value },
Size::Word => { 0x0000FFFF & value },
Size::Long => { value },
}
}
fn get_address_sized(system: &System, addr: Address, size: Size) -> Result<u32, Error> {
match size {
Size::Byte => system.get_bus().read_u8(addr).map(|value| value as u32),
Size::Word => system.get_bus().read_beu16(addr).map(|value| value as u32),
Size::Long => system.get_bus().read_beu32(addr),
}
}
fn set_value_sized(addr: &mut u32, value: u32, size: Size) {
match size {
Size::Byte => { *addr = (*addr & 0xFFFFFF00) | (0x000000FF & value); }
Size::Word => { *addr = (*addr & 0xFFFF0000) | (0x0000FFFF & value); }
Size::Long => { *addr = value; }
}
}
fn set_address_sized(system: &System, addr: Address, value: u32, size: Size) -> Result<(), Error> {
match size {
Size::Byte => system.get_bus().write_u8(addr, value as u8),
Size::Word => system.get_bus().write_beu16(addr, value as u16),
Size::Long => system.get_bus().write_beu32(addr, value),
}
}
fn get_overflow(operand1: u32, operand2: u32, result: u32, size: Size) -> bool {
let msb1 = get_msb(operand1, size);
let msb2 = get_msb(operand2, size);
let msb_res = get_msb(result, size);
msb1 && msb2 && !msb_res
}
fn get_msb(value: u32, size: Size) -> bool {
match size {
Size::Byte => (value & 0x00000080) != 0,
Size::Word => (value & 0x00008000) != 0,
Size::Long => (value & 0x80000000) != 0,
}
}
fn get_msb_mask(value: u32, size: Size) -> u32 {
match size {
Size::Byte => value & 0x00000080,
Size::Word => value & 0x00008000,
Size::Long => value & 0x80000000,
}
}
fn get_bit_field_mask(offset: u32, width: u32) -> u32 {
let mut mask = 0;
for _ in 0..width {
mask = (mask >> 1) | 0x80000000;
}
mask >> offset
}
fn get_bit_field_msb(offset: u32) -> u32 {
0x80000000 >> offset
}