2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-09 06:11:52 +00:00
|
|
|
use crate::system::System;
|
2021-10-16 17:01:14 +00:00
|
|
|
use crate::error::{ErrorType, Error};
|
2021-10-26 19:17:59 +00:00
|
|
|
use crate::devices::{ClockElapsed, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-18 19:05:10 +00:00
|
|
|
use super::instructions::{
|
|
|
|
Register,
|
2021-10-02 15:47:20 +00:00
|
|
|
Size,
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
Sign,
|
2021-10-02 15:47:20 +00:00
|
|
|
Direction,
|
|
|
|
ShiftDirection,
|
2021-10-15 21:37:31 +00:00
|
|
|
XRegister,
|
2021-10-18 22:44:42 +00:00
|
|
|
BaseRegister,
|
|
|
|
IndexRegister,
|
2021-10-18 04:18:59 +00:00
|
|
|
RegOrImmediate,
|
2021-10-18 19:05:10 +00:00
|
|
|
ControlRegister,
|
|
|
|
Condition,
|
|
|
|
Target,
|
|
|
|
Instruction,
|
|
|
|
sign_extend_to_long,
|
2021-10-02 15:47:20 +00:00
|
|
|
};
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-18 19:05:10 +00:00
|
|
|
|
2021-10-15 04:53:42 +00:00
|
|
|
const DEV_NAME: &'static str = "m68k-cpu";
|
|
|
|
|
2021-10-19 04:22:57 +00:00
|
|
|
use super::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority};
|
2021-10-02 16:35:25 +00:00
|
|
|
|
2021-10-17 17:39:43 +00:00
|
|
|
|
2021-10-10 21:26:54 +00:00
|
|
|
impl Steppable for M68k {
|
2021-10-24 05:22:02 +00:00
|
|
|
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
2021-10-07 18:35:15 +00:00
|
|
|
self.step_internal(system)?;
|
2021-10-25 17:29:13 +00:00
|
|
|
Ok((1_000_000_000 / self.frequency as u64) * 4)
|
2021-10-07 18:35:15 +00:00
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-07 18:35:15 +00:00
|
|
|
fn on_error(&mut self, system: &System) {
|
|
|
|
self.dump_state(system);
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
2021-10-15 04:53:42 +00:00
|
|
|
|
|
|
|
fn on_debug(&mut self) {
|
|
|
|
self.enable_debugging();
|
|
|
|
}
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2021-10-10 21:26:54 +00:00
|
|
|
impl Interruptable for M68k {
|
2021-10-09 18:00:32 +00:00
|
|
|
fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error> {
|
2021-10-08 17:52:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2021-10-07 20:57:50 +00:00
|
|
|
Ok(())
|
2021-10-07 18:35:15 +00:00
|
|
|
}
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2021-10-17 17:39:43 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-10-26 19:17:59 +00:00
|
|
|
|
|
|
|
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
|
|
|
|
Some(self)
|
|
|
|
}
|
2021-10-17 17:39:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-10-10 21:26:54 +00:00
|
|
|
impl M68k {
|
2021-10-11 22:16:04 +00:00
|
|
|
#[allow(dead_code)]
|
2021-09-30 00:11:48 +00:00
|
|
|
pub fn is_running(&self) -> bool {
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.status != Status::Stopped
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 18:35:15 +00:00
|
|
|
pub fn step_internal(&mut self, system: &System) -> Result<(), Error> {
|
2021-10-02 15:47:20 +00:00
|
|
|
match self.state.status {
|
2021-10-06 23:14:56 +00:00
|
|
|
Status::Init => self.init(system),
|
2021-10-11 22:16:04 +00:00
|
|
|
Status::Stopped => Err(Error::new("CPU stopped")),
|
2021-10-02 15:47:20 +00:00
|
|
|
Status::Running => {
|
2021-10-16 17:01:14 +00:00
|
|
|
match self.cycle_one(system) {
|
|
|
|
Ok(()) => Ok(()),
|
2021-10-18 04:18:59 +00:00
|
|
|
//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 => {
|
2021-10-24 05:22:02 +00:00
|
|
|
self.exception(system, native as u8, false)?;
|
2021-10-16 17:01:14 +00:00
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
Err(err) => Err(err),
|
|
|
|
}
|
2021-10-02 15:47:20 +00:00
|
|
|
},
|
2021-10-08 17:52:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 22:16:04 +00:00
|
|
|
pub fn init(&mut self, system: &System) -> Result<(), Error> {
|
2021-10-27 04:32:25 +00:00
|
|
|
self.state.msp = self.port.read_beu32(0)?;
|
|
|
|
self.state.pc = self.port.read_beu32(4)?;
|
2021-10-11 22:16:04 +00:00
|
|
|
self.state.status = Status::Running;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-16 17:01:14 +00:00
|
|
|
pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> {
|
2021-10-26 02:29:39 +00:00
|
|
|
self.timer.cycle.start();
|
2021-10-16 17:01:14 +00:00
|
|
|
self.decode_next(system)?;
|
|
|
|
self.execute_current(system)?;
|
2021-10-26 02:29:39 +00:00
|
|
|
self.timer.cycle.end();
|
2021-10-16 17:01:14 +00:00
|
|
|
|
|
|
|
//if (self.timer.cycle.events % 500) == 0 {
|
|
|
|
// println!("{}", self.timer);
|
|
|
|
//}
|
|
|
|
|
|
|
|
self.check_pending_interrupts(system)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-08 17:52:15 +00:00
|
|
|
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 {
|
2021-10-10 21:26:54 +00:00
|
|
|
let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8;
|
2021-10-08 17:52:15 +00:00
|
|
|
|
|
|
|
if (pending_ipl >= priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl {
|
2021-10-15 04:53:42 +00:00
|
|
|
debug!("{} interrupt: {} {}", DEV_NAME, pending_ipl, priority_mask);
|
2021-10-08 17:52:15 +00:00
|
|
|
self.state.current_ipl = self.state.pending_ipl;
|
2021-10-24 05:22:02 +00:00
|
|
|
self.exception(system, self.state.ipl_ack_num, true)?;
|
2021-10-08 17:52:15 +00:00
|
|
|
return Ok(());
|
2021-10-07 20:57:50 +00:00
|
|
|
}
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
2021-10-08 17:52:15 +00:00
|
|
|
|
|
|
|
if pending_ipl < current_ipl {
|
|
|
|
self.state.current_ipl = self.state.pending_ipl;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 05:22:02 +00:00
|
|
|
pub fn exception(&mut self, system: &System, number: u8, update_ipl: bool) -> Result<(), Error> {
|
2021-10-15 04:53:42 +00:00
|
|
|
debug!("{}: raising exception {}", DEV_NAME, number);
|
2021-10-06 04:53:18 +00:00
|
|
|
let offset = (number as u16) << 2;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.push_word(system, offset)?;
|
|
|
|
self.push_long(system, self.state.pc)?;
|
|
|
|
self.push_word(system, self.state.sr)?;
|
2021-10-07 18:35:15 +00:00
|
|
|
self.set_flag(Flags::Supervisor, true);
|
|
|
|
self.set_flag(Flags::Tracing, false);
|
2021-10-24 05:22:02 +00:00
|
|
|
if update_ipl {
|
|
|
|
self.state.sr = (self.state.sr & !(Flags::IntMask as u16)) | ((self.state.current_ipl as u16) << 8);
|
|
|
|
}
|
2021-10-27 04:32:25 +00:00
|
|
|
self.state.pc = self.port.read_beu32((self.state.vbr + offset as u32) as Address)?;
|
2021-10-06 04:53:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
pub fn decode_next(&mut self, system: &System) -> Result<(), Error> {
|
2021-10-02 16:35:25 +00:00
|
|
|
self.check_breakpoints();
|
2021-09-30 22:15:23 +00:00
|
|
|
|
2021-10-26 02:29:39 +00:00
|
|
|
self.timer.decode.start();
|
2021-10-27 04:32:25 +00:00
|
|
|
self.decoder.decode_at(&mut self.port, self.state.pc)?;
|
2021-10-26 02:29:39 +00:00
|
|
|
self.timer.decode.end();
|
2021-10-02 22:35:08 +00:00
|
|
|
|
2021-10-02 16:35:25 +00:00
|
|
|
if self.debugger.use_tracing {
|
2021-10-27 04:32:25 +00:00
|
|
|
self.decoder.dump_decoded(&mut self.port);
|
2021-10-01 03:27:01 +00:00
|
|
|
}
|
2021-09-30 22:15:23 +00:00
|
|
|
|
2021-10-02 16:35:25 +00:00
|
|
|
if self.debugger.use_debugger {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.run_debugger(system);
|
2021-09-30 22:15:23 +00:00
|
|
|
}
|
2021-10-02 22:35:08 +00:00
|
|
|
|
|
|
|
self.state.pc = self.decoder.end;
|
2021-09-30 19:58:11 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2021-09-30 06:21:11 +00:00
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
pub fn execute_current(&mut self, system: &System) -> Result<(), Error> {
|
2021-10-26 02:29:39 +00:00
|
|
|
self.timer.execute.start();
|
2021-10-02 15:47:20 +00:00
|
|
|
match self.decoder.instruction {
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::ADD(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
|
|
|
let existing = self.get_target_value(system, dest, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
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)),
|
|
|
|
}
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Instruction::AND(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
|
|
|
let existing = self.get_target_value(system, dest, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
let result = get_value_sized(existing & value, size);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
self.set_logic_flags(result, size);
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Instruction::ANDtoCCR(value) => {
|
2021-10-15 05:04:14 +00:00
|
|
|
self.state.sr = self.state.sr & (value as u16);
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Instruction::ANDtoSR(value) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-15 05:04:14 +00:00
|
|
|
self.state.sr = self.state.sr & value;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-10-02 22:35:08 +00:00
|
|
|
Instruction::ASd(count, target, size, shift_dir) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let count = self.get_target_value(system, count, size)? % 64;
|
|
|
|
let mut pair = (self.get_target_value(system, target, size)?, false);
|
2021-10-02 22:35:08 +00:00
|
|
|
let original = pair.0;
|
|
|
|
for _ in 0..count {
|
|
|
|
pair = shift_operation(pair.0, size, shift_dir, true);
|
|
|
|
}
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.set_logic_flags(pair.0, size);
|
2021-10-02 22:35:08 +00:00
|
|
|
if pair.1 {
|
2021-10-07 18:35:15 +00:00
|
|
|
self.set_flag(Flags::Carry, true);
|
|
|
|
self.set_flag(Flags::Extend, true);
|
2021-10-02 22:35:08 +00:00
|
|
|
}
|
|
|
|
if get_msb(pair.0, size) != get_msb(original, size) {
|
2021-10-07 18:35:15 +00:00
|
|
|
self.set_flag(Flags::Overflow, true);
|
2021-10-02 22:35:08 +00:00
|
|
|
}
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, pair.0, size)?;
|
2021-10-02 22:35:08 +00:00
|
|
|
},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::Bcc(cond, offset) => {
|
|
|
|
let should_branch = self.get_current_condition(cond);
|
|
|
|
if should_branch {
|
2021-10-02 16:48:21 +00:00
|
|
|
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::BRA(offset) => {
|
2021-10-02 16:48:21 +00:00
|
|
|
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Instruction::BSR(offset) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.push_long(system, self.state.pc)?;
|
2021-10-04 18:13:10 +00:00
|
|
|
let sp = *self.get_stack_pointer_mut();
|
|
|
|
self.debugger.stack_tracer.push_return(sp);
|
2021-10-02 16:48:21 +00:00
|
|
|
self.state.pc = (self.decoder.start + 2).wrapping_add(offset as u32);
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-01 03:27:01 +00:00
|
|
|
Instruction::BTST(bitnum, target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
|
|
|
let value = self.get_target_value(system, target, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
},
|
|
|
|
Instruction::BCHG(bitnum, target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
|
|
|
let mut value = self.get_target_value(system, target, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
value = (value & !mask) | (!(value & mask) & mask);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, value, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
|
|
|
Instruction::BCLR(bitnum, target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
|
|
|
let mut value = self.get_target_value(system, target, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
value = value & !mask;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, value, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
|
|
|
Instruction::BSET(bitnum, target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let bitnum = self.get_target_value(system, bitnum, Size::Byte)?;
|
|
|
|
let mut value = self.get_target_value(system, target, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
value = value | mask;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, value, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
2021-10-18 04:18:59 +00:00
|
|
|
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;
|
2021-10-18 23:34:55 +00:00
|
|
|
for _ in 0..(offset + right_offset) {
|
2021-10-18 04:18:59 +00:00
|
|
|
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) => {
|
|
|
|
//},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::CLR(target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, 0, size)?;
|
2021-10-01 03:27:01 +00:00
|
|
|
// Clear flags except Zero flag
|
2021-10-07 18:35:15 +00:00
|
|
|
self.state.sr = (self.state.sr & 0xFFF0) | (Flags::Zero as u16);
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-09-30 19:58:11 +00:00
|
|
|
Instruction::CMP(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
|
|
|
let existing = self.get_target_value(system, dest, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
let (result, carry) = overflowing_sub_sized(existing, value, size);
|
|
|
|
self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size));
|
2021-09-30 19:58:11 +00:00
|
|
|
},
|
2021-10-02 05:06:53 +00:00
|
|
|
Instruction::CMPA(src, reg, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = sign_extend_to_long(self.get_target_value(system, src, size)?, size) as u32;
|
2021-10-04 18:13:10 +00:00
|
|
|
let existing = *self.get_a_reg_mut(reg);
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
let (result, carry) = overflowing_sub_sized(existing, value, Size::Long);
|
2021-10-04 18:13:10 +00:00
|
|
|
self.set_compare_flags(result, Size::Long, carry, get_overflow(existing, value, result, Size::Long));
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
},
|
|
|
|
Instruction::DBcc(cond, reg, offset) => {
|
|
|
|
let condition_true = self.get_current_condition(cond);
|
|
|
|
if !condition_true {
|
2021-10-26 02:29:39 +00:00
|
|
|
let next = ((get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16).wrapping_sub(1);
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2021-10-19 04:22:57 +00:00
|
|
|
Instruction::DIVW(src, dest, sign) => {
|
|
|
|
let value = self.get_target_value(system, src, Size::Word)?;
|
|
|
|
if value == 0 {
|
2021-10-24 05:22:02 +00:00
|
|
|
self.exception(system, Exceptions::ZeroDivide as u8, false)?;
|
2021-10-19 04:22:57 +00:00
|
|
|
return Ok(());
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
}
|
|
|
|
|
2021-10-20 02:50:42 +00:00
|
|
|
let existing = get_value_sized(self.state.d_reg[dest as usize], Size::Long);
|
2021-10-19 04:22:57 +00:00
|
|
|
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)?;
|
2021-10-11 22:16:04 +00:00
|
|
|
if value == 0 {
|
2021-10-24 05:22:02 +00:00
|
|
|
self.exception(system, Exceptions::ZeroDivide as u8, false)?;
|
2021-10-11 22:16:04 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2021-10-19 04:22:57 +00:00
|
|
|
let existing_l = self.state.d_reg[dest_l as usize];
|
|
|
|
let (remainder, quotient) = match sign {
|
2021-10-10 00:35:23 +00:00
|
|
|
Sign::Signed => {
|
2021-10-19 04:22:57 +00:00
|
|
|
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)
|
2021-10-10 00:35:23 +00:00
|
|
|
},
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
};
|
2021-10-19 04:22:57 +00:00
|
|
|
|
|
|
|
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;
|
2021-10-02 05:06:53 +00:00
|
|
|
},
|
2021-10-01 03:27:01 +00:00
|
|
|
Instruction::EOR(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
|
|
|
let existing = self.get_target_value(system, dest, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
let result = get_value_sized(existing ^ value, size);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
self.set_logic_flags(result, size);
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
|
|
|
Instruction::EORtoCCR(value) => {
|
2021-10-08 17:52:15 +00:00
|
|
|
self.state.sr = self.state.sr ^ (value as u16);
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
|
|
|
Instruction::EORtoSR(value) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.sr = self.state.sr ^ value;
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::EXG(Target, Target) => {
|
|
|
|
//},
|
2021-10-15 21:37:31 +00:00
|
|
|
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"),
|
2021-10-01 19:25:23 +00:00
|
|
|
};
|
2021-10-15 21:37:31 +00:00
|
|
|
set_value_sized(&mut self.state.d_reg[reg as usize], result, to_size);
|
|
|
|
self.set_logic_flags(result, to_size);
|
2021-09-30 22:15:23 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::ILLEGAL => {
|
|
|
|
//},
|
|
|
|
Instruction::JMP(target) => {
|
2021-10-18 22:44:42 +00:00
|
|
|
self.state.pc = self.get_target_address(system, target)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Instruction::JSR(target) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.push_long(system, self.state.pc)?;
|
2021-10-04 18:13:10 +00:00
|
|
|
let sp = *self.get_stack_pointer_mut();
|
|
|
|
self.debugger.stack_tracer.push_return(sp);
|
2021-10-18 22:44:42 +00:00
|
|
|
self.state.pc = self.get_target_address(system, target)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Instruction::LEA(target, reg) => {
|
2021-10-18 22:44:42 +00:00
|
|
|
let value = self.get_target_address(system, target)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-09-30 00:11:48 +00:00
|
|
|
*addr = value;
|
|
|
|
},
|
2021-10-02 22:35:08 +00:00
|
|
|
Instruction::LINK(reg, offset) => {
|
|
|
|
let value = *self.get_a_reg_mut(reg);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.push_long(system, value)?;
|
2021-10-02 22:35:08 +00:00
|
|
|
let sp = *self.get_stack_pointer_mut();
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
*addr = sp;
|
2021-10-04 20:02:58 +00:00
|
|
|
*self.get_stack_pointer_mut() = sp.wrapping_add((offset as i32) as u32);
|
2021-10-02 22:35:08 +00:00
|
|
|
},
|
2021-10-01 22:38:21 +00:00
|
|
|
Instruction::LSd(count, target, size, shift_dir) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let count = self.get_target_value(system, count, size)? % 64;
|
|
|
|
let mut pair = (self.get_target_value(system, target, size)?, false);
|
2021-10-01 22:38:21 +00:00
|
|
|
for _ in 0..count {
|
|
|
|
pair = shift_operation(pair.0, size, shift_dir, false);
|
|
|
|
}
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.set_logic_flags(pair.0, size);
|
2021-10-01 22:38:21 +00:00
|
|
|
if pair.1 {
|
2021-10-07 18:35:15 +00:00
|
|
|
self.set_flag(Flags::Carry, true);
|
|
|
|
self.set_flag(Flags::Extend, true);
|
2021-10-01 22:38:21 +00:00
|
|
|
}
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, pair.0, size)?;
|
2021-10-01 22:38:21 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::MOVE(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.set_logic_flags(value, size);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, value, size)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-01 19:25:23 +00:00
|
|
|
Instruction::MOVEA(src, reg, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
let value = sign_extend_to_long(value, size) as u32;
|
2021-10-01 19:25:23 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
*addr = value;
|
2021-10-01 19:25:23 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::MOVEfromSR(target) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, self.state.sr as u32, Size::Word)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Instruction::MOVEtoSR(target) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.state.sr = self.get_target_value(system, target, Size::Word)? as u16;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-09-30 22:15:23 +00:00
|
|
|
Instruction::MOVEtoCCR(target) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, target, Size::Word)? as u16;
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.sr = (self.state.sr & 0xFF00) | (value & 0x00FF);
|
2021-09-30 22:15:23 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::MOVEC(target, control_reg, dir) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-09-30 00:11:48 +00:00
|
|
|
match dir {
|
|
|
|
Direction::FromTarget => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, target, Size::Long)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
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;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, value, Size::Long)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
2021-10-02 22:35:08 +00:00
|
|
|
Instruction::MOVEUSP(target, dir) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-02 22:35:08 +00:00
|
|
|
match dir {
|
2021-10-06 23:14:56 +00:00
|
|
|
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)?; },
|
2021-10-02 22:35:08 +00:00
|
|
|
}
|
|
|
|
},
|
2021-10-19 18:33:51 +00:00
|
|
|
Instruction::MOVEM(target, size, dir, mask) => {
|
|
|
|
self.execute_movem(system, target, size, dir, mask)?;
|
2021-09-30 19:58:11 +00:00
|
|
|
},
|
|
|
|
Instruction::MOVEQ(data, reg) => {
|
2021-10-01 19:25:23 +00:00
|
|
|
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.d_reg[reg as usize] = value;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.set_logic_flags(value, Size::Long);
|
|
|
|
},
|
2021-10-19 04:22:57 +00:00
|
|
|
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,
|
|
|
|
};
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
|
2021-10-19 04:22:57 +00:00
|
|
|
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);
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
let result = match sign {
|
2021-10-19 04:22:57 +00:00
|
|
|
Sign::Signed => (((existing as i32) as i64) * ((value as i32) as i64)) as u64,
|
|
|
|
Sign::Unsigned => existing as u64 * value as u64,
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
};
|
2021-10-19 04:22:57 +00:00
|
|
|
|
|
|
|
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;
|
2021-09-30 19:58:11 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::NBCD(Target) => {
|
|
|
|
//},
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
Instruction::NEG(target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let original = self.get_target_value(system, target, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
let (value, _) = (0 as u32).overflowing_sub(original);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, value, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.set_compare_flags(value, size, value != 0, get_overflow(0, original, value, size));
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::NEGX(Target, Size) => {
|
|
|
|
//},
|
|
|
|
Instruction::NOP => { },
|
2021-10-02 22:35:08 +00:00
|
|
|
Instruction::NOT(target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let mut value = self.get_target_value(system, target, size)?;
|
2021-10-02 22:35:08 +00:00
|
|
|
value = get_value_sized(!value, size);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, value, size)?;
|
2021-10-02 22:35:08 +00:00
|
|
|
self.set_logic_flags(value, size);
|
|
|
|
},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::OR(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
|
|
|
let existing = self.get_target_value(system, dest, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
let result = get_value_sized(existing | value, size);
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
self.set_logic_flags(result, size);
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Instruction::ORtoCCR(value) => {
|
2021-10-08 17:52:15 +00:00
|
|
|
self.state.sr = self.state.sr | (value as u16);
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::ORtoSR(value) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.sr = self.state.sr | value;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::PEA(target) => {
|
2021-10-18 22:44:42 +00:00
|
|
|
let value = self.get_target_address(system, target)?;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.push_long(system, value)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::RESET => {
|
2021-10-16 17:01:14 +00:00
|
|
|
// self.require_supervisor()?;
|
2021-09-30 00:11:48 +00:00
|
|
|
//},
|
2021-10-05 23:22:21 +00:00
|
|
|
Instruction::ROd(count, target, size, shift_dir) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let count = self.get_target_value(system, count, size)? % 64;
|
|
|
|
let mut pair = (self.get_target_value(system, target, size)?, false);
|
2021-10-05 23:22:21 +00:00
|
|
|
for _ in 0..count {
|
2021-10-20 02:50:42 +00:00
|
|
|
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);
|
2021-10-05 23:22:21 +00:00
|
|
|
}
|
|
|
|
self.set_logic_flags(pair.0, size);
|
|
|
|
if pair.1 {
|
2021-10-07 18:35:15 +00:00
|
|
|
self.set_flag(Flags::Carry, true);
|
2021-10-05 23:22:21 +00:00
|
|
|
}
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, pair.0, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
},
|
2021-10-06 04:53:18 +00:00
|
|
|
Instruction::RTE => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-06 23:14:56 +00:00
|
|
|
self.state.sr = self.pop_word(system)?;
|
|
|
|
self.state.pc = self.pop_long(system)?;
|
|
|
|
let _ = self.pop_word(system)?;
|
2021-10-06 04:53:18 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::RTR => {
|
|
|
|
//},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::RTS => {
|
2021-10-04 18:13:10 +00:00
|
|
|
self.debugger.stack_tracer.pop_return();
|
2021-10-06 23:14:56 +00:00
|
|
|
self.state.pc = self.pop_long(system)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
Instruction::Scc(cond, target) => {
|
|
|
|
let condition_true = self.get_current_condition(cond);
|
|
|
|
if condition_true {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, 0xFF, Size::Byte)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
} else {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, target, 0x00, Size::Byte)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
}
|
|
|
|
},
|
2021-10-06 04:53:18 +00:00
|
|
|
Instruction::STOP(flags) => {
|
2021-10-16 17:01:14 +00:00
|
|
|
self.require_supervisor()?;
|
2021-10-06 04:53:18 +00:00
|
|
|
self.state.sr = flags;
|
|
|
|
self.state.status = Status::Stopped;
|
|
|
|
},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::SUB(src, dest, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
|
|
|
let existing = self.get_target_value(system, dest, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
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)),
|
|
|
|
}
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-10-01 03:27:01 +00:00
|
|
|
Instruction::SWAP(reg) => {
|
2021-10-02 15:47:20 +00:00
|
|
|
let value = self.state.d_reg[reg as usize];
|
|
|
|
self.state.d_reg[reg as usize] = ((value & 0x0000FFFF) << 16) | ((value & 0xFFFF0000) >> 16);
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::TAS(Target) => {
|
|
|
|
//},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::TST(target, size) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, target, size)?;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.set_logic_flags(value, size);
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-10-06 04:53:18 +00:00
|
|
|
Instruction::TRAP(number) => {
|
2021-10-24 05:22:02 +00:00
|
|
|
self.exception(system, 32 + number, false)?;
|
2021-10-06 04:53:18 +00:00
|
|
|
},
|
|
|
|
Instruction::TRAPV => {
|
2021-10-07 18:35:15 +00:00
|
|
|
if self.get_flag(Flags::Overflow) {
|
2021-10-24 05:22:02 +00:00
|
|
|
self.exception(system, Exceptions::TrapvInstruction as u8, false)?;
|
2021-10-06 04:53:18 +00:00
|
|
|
}
|
|
|
|
},
|
2021-10-02 22:35:08 +00:00
|
|
|
Instruction::UNLK(reg) => {
|
|
|
|
let value = *self.get_a_reg_mut(reg);
|
|
|
|
*self.get_stack_pointer_mut() = value;
|
2021-10-06 23:14:56 +00:00
|
|
|
let new_value = self.pop_long(system)?;
|
2021-10-02 22:35:08 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
*addr = new_value;
|
|
|
|
},
|
2021-10-03 16:55:20 +00:00
|
|
|
_ => { return Err(Error::new("Unsupported instruction")); },
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-26 02:29:39 +00:00
|
|
|
self.timer.execute.end();
|
2021-09-30 00:11:48 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-19 18:33:51 +00:00
|
|
|
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();
|
2021-10-27 04:32:25 +00:00
|
|
|
self.set_address_sized(addr as Address, value, size)?;
|
2021-10-19 18:33:51 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
|
|
|
for i in (0..8).rev() {
|
|
|
|
if (mask & 0x01) != 0 {
|
|
|
|
addr -= size.in_bytes();
|
2021-10-27 04:32:25 +00:00
|
|
|
self.set_address_sized(addr as Address, self.state.d_reg[i], size)?;
|
2021-10-19 18:33:51 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let mut mask = mask;
|
|
|
|
for i in 0..8 {
|
|
|
|
if (mask & 0x01) != 0 {
|
2021-10-27 04:32:25 +00:00
|
|
|
self.state.d_reg[i] = sign_extend_to_long(self.get_address_sized(addr as Address, size)?, size) as u32;
|
2021-10-19 18:33:51 +00:00
|
|
|
addr += size.in_bytes();
|
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
|
|
|
for i in 0..8 {
|
|
|
|
if (mask & 0x01) != 0 {
|
2021-10-27 04:32:25 +00:00
|
|
|
*self.get_a_reg_mut(i) = sign_extend_to_long(self.get_address_sized(addr as Address, size)?, size) as u32;
|
2021-10-19 18:33:51 +00:00
|
|
|
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(())
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn push_word(&mut self, system: &System, value: u16) -> Result<(), Error> {
|
2021-10-27 04:32:25 +00:00
|
|
|
*self.get_stack_pointer_mut() -= 2;
|
|
|
|
let addr = *self.get_stack_pointer_mut();
|
|
|
|
self.port.write_beu16(addr as Address, value)
|
2021-10-06 04:53:18 +00:00
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn pop_word(&mut self, system: &System) -> Result<u16, Error> {
|
2021-10-27 04:32:25 +00:00
|
|
|
let addr = *self.get_stack_pointer_mut();
|
|
|
|
let value = self.port.read_beu16(addr as Address)?;
|
|
|
|
*self.get_stack_pointer_mut() += 2;
|
2021-10-06 04:53:18 +00:00
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn push_long(&mut self, system: &System, value: u32) -> Result<(), Error> {
|
2021-10-27 04:32:25 +00:00
|
|
|
*self.get_stack_pointer_mut() -= 4;
|
|
|
|
let addr = *self.get_stack_pointer_mut();
|
|
|
|
self.port.write_beu32(addr as Address, value)
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn pop_long(&mut self, system: &System) -> Result<u32, Error> {
|
2021-10-27 04:32:25 +00:00
|
|
|
let addr = *self.get_stack_pointer_mut();
|
|
|
|
let value = self.port.read_beu32(addr as Address)?;
|
|
|
|
*self.get_stack_pointer_mut() += 4;
|
2021-10-02 15:47:20 +00:00
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
pub fn get_target_value(&mut self, system: &System, target: Target, size: Size) -> Result<u32, Error> {
|
2021-09-30 00:11:48 +00:00
|
|
|
match target {
|
|
|
|
Target::Immediate(value) => Ok(value),
|
2021-10-02 15:47:20 +00:00
|
|
|
Target::DirectDReg(reg) => Ok(get_value_sized(self.state.d_reg[reg as usize], size)),
|
2021-09-30 04:52:38 +00:00
|
|
|
Target::DirectAReg(reg) => Ok(get_value_sized(*self.get_a_reg_mut(reg), size)),
|
2021-10-27 04:32:25 +00:00
|
|
|
Target::IndirectAReg(reg) => {
|
|
|
|
let addr = *self.get_a_reg_mut(reg);
|
|
|
|
self.get_address_sized(addr as Address, size)
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Target::IndirectARegInc(reg) => {
|
2021-10-27 04:32:25 +00:00
|
|
|
let addr = *self.get_a_reg_mut(reg);
|
|
|
|
let result = self.get_address_sized(addr as Address, size);
|
|
|
|
*self.get_a_reg_mut(reg) += size.in_bytes();
|
2021-09-30 04:52:38 +00:00
|
|
|
result
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegDec(reg) => {
|
2021-10-27 04:32:25 +00:00
|
|
|
*self.get_a_reg_mut(reg) -= size.in_bytes();
|
|
|
|
let addr = *self.get_a_reg_mut(reg);
|
|
|
|
self.get_address_sized(addr as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-18 22:44:42 +00:00
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
self.get_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-18 22:44:42 +00:00
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
|
|
|
|
self.get_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, size)
|
2021-10-18 22:44:42 +00:00
|
|
|
},
|
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
|
|
|
|
self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectMemory(addr) => {
|
2021-10-27 04:32:25 +00:00
|
|
|
self.get_address_sized(addr as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
pub fn set_target_value(&mut self, system: &System, target: Target, value: u32, size: Size) -> Result<(), Error> {
|
2021-09-30 00:11:48 +00:00
|
|
|
match target {
|
|
|
|
Target::DirectDReg(reg) => {
|
2021-10-02 15:47:20 +00:00
|
|
|
set_value_sized(&mut self.state.d_reg[reg as usize], value, size);
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::DirectAReg(reg) => {
|
2021-09-30 04:52:38 +00:00
|
|
|
set_value_sized(self.get_a_reg_mut(reg), value, size);
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectAReg(reg) => {
|
2021-10-27 04:32:25 +00:00
|
|
|
let addr = *self.get_a_reg_mut(reg);
|
|
|
|
self.set_address_sized(addr as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegInc(reg) => {
|
2021-10-27 04:32:25 +00:00
|
|
|
let addr = *self.get_a_reg_mut(reg);
|
|
|
|
self.set_address_sized(addr as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-20 02:50:42 +00:00
|
|
|
*addr = (*addr).wrapping_add(size.in_bytes());
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegDec(reg) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-20 02:50:42 +00:00
|
|
|
*addr = (*addr).wrapping_sub(size.in_bytes());
|
2021-10-27 04:32:25 +00:00
|
|
|
let addr = *self.get_a_reg_mut(reg);
|
|
|
|
self.set_address_sized(addr as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-10-18 22:44:42 +00:00
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
self.set_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-10-18 22:44:42 +00:00
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
|
|
|
|
self.set_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, value, size)?;
|
2021-10-18 22:44:42 +00:00
|
|
|
},
|
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
|
|
|
|
self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Target::IndirectMemory(addr) => {
|
2021-10-27 04:32:25 +00:00
|
|
|
self.set_address_sized(addr as Address, value, size)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
_ => return Err(Error::new(&format!("Unimplemented addressing target: {:?}", target))),
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-18 22:44:42 +00:00
|
|
|
pub fn get_target_address(&mut self, system: &System, target: Target) -> Result<u32, Error> {
|
2021-09-30 00:11:48 +00:00
|
|
|
let addr = match target {
|
2021-10-05 23:22:21 +00:00
|
|
|
Target::IndirectAReg(reg) | Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => *self.get_a_reg_mut(reg),
|
2021-10-18 22:44:42 +00:00
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?;
|
2021-10-18 22:44:42 +00:00
|
|
|
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);
|
2021-10-27 04:32:25 +00:00
|
|
|
let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?;
|
2021-10-18 22:44:42 +00:00
|
|
|
intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectMemory(addr) => {
|
|
|
|
addr
|
|
|
|
},
|
2021-09-30 04:52:38 +00:00
|
|
|
_ => return Err(Error::new(&format!("Invalid addressing target: {:?}", target))),
|
2021-09-30 00:11:48 +00:00
|
|
|
};
|
|
|
|
Ok(addr)
|
|
|
|
}
|
|
|
|
|
2021-10-27 04:32:25 +00:00
|
|
|
pub fn get_address_sized(&mut self, addr: Address, size: Size) -> Result<u32, Error> {
|
|
|
|
match size {
|
|
|
|
Size::Byte => self.port.read_u8(addr).map(|value| value as u32),
|
|
|
|
Size::Word => self.port.read_beu16(addr).map(|value| value as u32),
|
|
|
|
Size::Long => self.port.read_beu32(addr),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), Error> {
|
|
|
|
match size {
|
|
|
|
Size::Byte => self.port.write_u8(addr, value as u8),
|
|
|
|
Size::Word => self.port.write_beu16(addr, value as u16),
|
|
|
|
Size::Long => self.port.write_beu32(addr, value),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-18 04:18:59 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-18 22:44:42 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-30 00:11:48 +00:00
|
|
|
fn get_control_reg_mut(&mut self, control_reg: ControlRegister) -> &mut u32 {
|
|
|
|
match control_reg {
|
2021-10-02 15:47:20 +00:00
|
|
|
ControlRegister::VBR => &mut self.state.vbr,
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2021-09-30 04:52:38 +00:00
|
|
|
fn get_stack_pointer_mut(&mut self) -> &mut u32 {
|
2021-10-02 15:47:20 +00:00
|
|
|
if self.is_supervisor() { &mut self.state.msp } else { &mut self.state.usp }
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2021-10-18 04:18:59 +00:00
|
|
|
fn get_a_reg_mut(&mut self, reg: Register) -> &mut u32 {
|
2021-09-30 00:11:48 +00:00
|
|
|
if reg == 7 {
|
2021-10-02 15:47:20 +00:00
|
|
|
if self.is_supervisor() { &mut self.state.msp } else { &mut self.state.usp }
|
2021-09-30 00:11:48 +00:00
|
|
|
} else {
|
2021-10-02 15:47:20 +00:00
|
|
|
&mut self.state.a_reg[reg as usize]
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 17:01:14 +00:00
|
|
|
#[inline(always)]
|
2021-10-02 15:47:20 +00:00
|
|
|
fn is_supervisor(&self) -> bool {
|
2021-10-07 18:35:15 +00:00
|
|
|
self.state.sr & (Flags:: Supervisor as u16) != 0
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2021-10-16 17:01:14 +00:00
|
|
|
#[inline(always)]
|
|
|
|
fn require_supervisor(&self) -> Result<(), Error> {
|
|
|
|
if self.is_supervisor() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(Error::processor(Exceptions::PrivilegeViolation as u32))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-07 18:35:15 +00:00
|
|
|
#[inline(always)]
|
|
|
|
fn get_flag(&self, flag: Flags) -> bool {
|
|
|
|
(self.state.sr & (flag as u16)) != 0
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 18:35:15 +00:00
|
|
|
#[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 });
|
2021-10-05 23:22:21 +00:00
|
|
|
}
|
|
|
|
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
fn set_compare_flags(&mut self, value: u32, size: Size, carry: bool, overflow: bool) {
|
2021-10-01 19:25:23 +00:00
|
|
|
let value = sign_extend_to_long(value, size);
|
2021-10-01 03:27:01 +00:00
|
|
|
|
2021-09-30 04:52:38 +00:00
|
|
|
let mut flags = 0x0000;
|
|
|
|
if value < 0 {
|
2021-10-07 18:35:15 +00:00
|
|
|
flags |= Flags::Negative as u16;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
if value == 0 {
|
2021-10-07 18:35:15 +00:00
|
|
|
flags |= Flags::Zero as u16;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
if carry {
|
2021-10-07 18:35:15 +00:00
|
|
|
flags |= Flags::Carry as u16;
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
}
|
|
|
|
if overflow {
|
2021-10-07 18:35:15 +00:00
|
|
|
flags |= Flags::Overflow as u16;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.sr = (self.state.sr & 0xFFF0) | flags;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_logic_flags(&mut self, value: u32, size: Size) {
|
|
|
|
let mut flags = 0x0000;
|
2021-10-01 22:38:21 +00:00
|
|
|
if get_msb(value, size) {
|
2021-10-07 18:35:15 +00:00
|
|
|
flags |= Flags::Negative as u16;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
if value == 0 {
|
2021-10-07 18:35:15 +00:00
|
|
|
flags |= Flags::Zero as u16;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
self.state.sr = (self.state.sr & 0xFFF0) | flags;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
|
2021-10-01 03:27:01 +00:00
|
|
|
fn set_bit_test_flags(&mut self, value: u32, bitnum: u32, size: Size) -> u32 {
|
|
|
|
let mask = 0x1 << (bitnum % size.in_bits());
|
2021-10-07 18:35:15 +00:00
|
|
|
self.set_flag(Flags::Zero, (value & mask) == 0);
|
2021-10-01 03:27:01 +00:00
|
|
|
mask
|
|
|
|
}
|
|
|
|
|
2021-10-18 04:18:59 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-09-30 04:52:38 +00:00
|
|
|
|
|
|
|
fn get_current_condition(&self, cond: Condition) -> bool {
|
|
|
|
match cond {
|
2021-09-30 19:58:11 +00:00
|
|
|
Condition::True => true,
|
|
|
|
Condition::False => false,
|
2021-10-07 18:35:15 +00:00
|
|
|
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)),
|
2021-09-30 19:58:11 +00:00
|
|
|
Condition::GreaterThan =>
|
2021-10-07 18:35:15 +00:00
|
|
|
(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)),
|
2021-09-30 19:58:11 +00:00
|
|
|
Condition::LessThanOrEqual =>
|
2021-10-07 18:35:15 +00:00
|
|
|
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)),
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
|
|
|
|
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 => {
|
2021-10-05 23:22:21 +00:00
|
|
|
let bit = get_msb(value, size);
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
match size {
|
2021-10-05 23:22:21 +00:00
|
|
|
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),
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
ShiftDirection::Right => {
|
|
|
|
let mask = if arithmetic { get_msb_mask(value, size) } else { 0 };
|
|
|
|
((value >> 1) | mask, (value & 0x1) != 0)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-20 02:50:42 +00:00
|
|
|
fn rotate_operation(value: u32, size: Size, dir: ShiftDirection, use_extend: Option<bool>) -> (u32, bool) {
|
2021-10-05 23:22:21 +00:00
|
|
|
match dir {
|
|
|
|
ShiftDirection::Left => {
|
|
|
|
let bit = get_msb(value, size);
|
2021-10-20 02:50:42 +00:00
|
|
|
let mask = if use_extend.unwrap_or(bit) { 0x01 } else { 0x00 };
|
2021-10-05 23:22:21 +00:00
|
|
|
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 };
|
2021-10-20 02:50:42 +00:00
|
|
|
let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 };
|
2021-10-05 23:22:21 +00:00
|
|
|
((value >> 1) | mask, bit)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
|
2021-09-30 00:11:48 +00:00
|
|
|
fn get_value_sized(value: u32, size: Size) -> u32 {
|
|
|
|
match size {
|
|
|
|
Size::Byte => { 0x000000FF & value },
|
|
|
|
Size::Word => { 0x0000FFFF & value },
|
|
|
|
Size::Long => { value },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
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
|
2021-09-30 22:15:23 +00:00
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-01 22:38:21 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-01 22:38:21 +00:00
|
|
|
fn get_msb_mask(value: u32, size: Size) -> u32 {
|
|
|
|
match size {
|
|
|
|
Size::Byte => value & 0x00000080,
|
|
|
|
Size::Word => value & 0x00008000,
|
|
|
|
Size::Long => value & 0x80000000,
|
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
2021-10-01 22:38:21 +00:00
|
|
|
|
2021-10-18 04:18:59 +00:00
|
|
|
fn get_bit_field_mask(offset: u32, width: u32) -> u32 {
|
|
|
|
let mut mask = 0;
|
2021-10-18 23:34:55 +00:00
|
|
|
for _ in 0..width {
|
2021-10-18 04:18:59 +00:00
|
|
|
mask = (mask >> 1) | 0x80000000;
|
|
|
|
}
|
|
|
|
mask >> offset
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_bit_field_msb(offset: u32) -> u32 {
|
|
|
|
0x80000000 >> offset
|
|
|
|
}
|
|
|
|
|
|
|
|
|