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-07 16:41:01 +00:00
|
|
|
use crate::memory::{Address, Addressable};
|
2021-10-09 06:11:52 +00:00
|
|
|
use crate::devices::{Clock, Steppable, Interruptable};
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
use super::decode::{
|
|
|
|
Instruction,
|
|
|
|
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
|
|
|
Sign,
|
2021-10-02 15:47:20 +00:00
|
|
|
Direction,
|
|
|
|
Condition,
|
|
|
|
ShiftDirection,
|
|
|
|
ControlRegister,
|
2021-10-15 21:37:31 +00:00
|
|
|
XRegister,
|
2021-10-02 15:47:20 +00:00
|
|
|
sign_extend_to_long
|
|
|
|
};
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-15 04:53:42 +00:00
|
|
|
const DEV_NAME: &'static str = "m68k-cpu";
|
|
|
|
|
2021-10-11 22:16:04 +00:00
|
|
|
use super::state::{M68k, Status, Flags, Exceptions, InterruptPriority};
|
2021-10-02 16:35:25 +00:00
|
|
|
|
2021-10-10 21:26:54 +00:00
|
|
|
impl Steppable for M68k {
|
2021-10-07 18:35:15 +00:00
|
|
|
fn step(&mut self, system: &System) -> Result<Clock, Error> {
|
|
|
|
self.step_internal(system)?;
|
|
|
|
Ok(1)
|
|
|
|
}
|
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-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(()),
|
|
|
|
Err(Error { err: ErrorType::Processor, native, .. }) => {
|
|
|
|
self.exception(system, native as u8)?;
|
|
|
|
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> {
|
|
|
|
self.state.msp = system.get_bus().read_beu32(0)?;
|
|
|
|
self.state.pc = system.get_bus().read_beu32(4)?;
|
|
|
|
self.state.status = Status::Running;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-16 17:01:14 +00:00
|
|
|
pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> {
|
|
|
|
let timer = self.timer.cycle.start();
|
|
|
|
self.decode_next(system)?;
|
|
|
|
self.execute_current(system)?;
|
|
|
|
self.timer.cycle.end(timer);
|
|
|
|
|
|
|
|
//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;
|
|
|
|
self.exception(system, self.state.ipl_ack_num)?;
|
|
|
|
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-06 23:14:56 +00:00
|
|
|
pub fn exception(&mut self, system: &System, number: u8) -> 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-07 16:41:01 +00:00
|
|
|
self.state.pc = system.get_bus().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-04 03:45:50 +00:00
|
|
|
let timer = self.timer.decode.start();
|
2021-10-10 21:26:54 +00:00
|
|
|
self.decoder.decode_at(system, self.state.pc)?;
|
2021-10-04 03:45:50 +00:00
|
|
|
self.timer.decode.end(timer);
|
2021-10-02 22:35:08 +00:00
|
|
|
|
2021-10-02 16:35:25 +00:00
|
|
|
if self.debugger.use_tracing {
|
2021-10-11 22:16:04 +00:00
|
|
|
self.decoder.dump_decoded(system);
|
2021-10-15 21:37:31 +00:00
|
|
|
// TODO for debugging temporarily
|
|
|
|
self.dump_state(system);
|
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-04 03:45:50 +00:00
|
|
|
let timer = self.timer.decode.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-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 {
|
|
|
|
let next = (get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16 - 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::DIV(src, dest, size, sign) => {
|
|
|
|
if size == Size::Long {
|
|
|
|
return Err(Error::new("Unsupported multiplication size"));
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
let value = self.get_target_value(system, src, size)?;
|
2021-10-11 22:16:04 +00:00
|
|
|
if value == 0 {
|
|
|
|
self.exception(system, Exceptions::ZeroDivide as u8)?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
let existing = self.get_target_value(system, dest, 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-10 00:35:23 +00:00
|
|
|
Sign::Signed => {
|
|
|
|
let value = sign_extend_to_long(value, size) as u32;
|
|
|
|
((existing % value) << 16) | (0xFFFF & (existing / value))
|
|
|
|
},
|
|
|
|
Sign::Unsigned => ((existing % value) << 16) | (0xFFFF & (existing / 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
|
|
|
};
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, Size::Long)?;
|
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-02 16:48:21 +00:00
|
|
|
self.state.pc = self.get_target_address(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-02 16:48:21 +00:00
|
|
|
self.state.pc = self.get_target_address(target)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Instruction::LEA(target, reg) => {
|
|
|
|
let value = self.get_target_address(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-09-30 19:58:11 +00:00
|
|
|
Instruction::MOVEM(target, size, dir, mask) => {
|
|
|
|
// TODO moving words requires a sign extension to 32 bits
|
2021-09-30 22:15:23 +00:00
|
|
|
if size != Size::Long { return Err(Error::new("Unsupported size in MOVEM instruction")); }
|
2021-09-30 19:58:11 +00:00
|
|
|
|
2021-10-05 23:22:21 +00:00
|
|
|
let mut addr = self.get_target_address(target)?;
|
2021-09-30 19:58:11 +00:00
|
|
|
if dir == Direction::ToTarget {
|
|
|
|
let mut mask = mask;
|
2021-10-02 05:06:53 +00:00
|
|
|
for i in (0..8).rev() {
|
2021-09-30 19:58:11 +00:00
|
|
|
if (mask & 0x01) != 0 {
|
2021-10-02 05:06:53 +00:00
|
|
|
let value = *self.get_a_reg_mut(i);
|
2021-10-05 23:22:21 +00:00
|
|
|
addr -= size.in_bytes();
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, addr as Address, value, size)?;
|
2021-09-30 19:58:11 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
2021-10-02 05:06:53 +00:00
|
|
|
for i in (0..8).rev() {
|
2021-09-30 19:58:11 +00:00
|
|
|
if (mask & 0x01) != 0 {
|
2021-10-05 23:22:21 +00:00
|
|
|
addr -= size.in_bytes();
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, addr as Address, self.state.d_reg[i], size)?;
|
2021-09-30 19:58:11 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let mut mask = mask;
|
2021-10-02 05:06:53 +00:00
|
|
|
for i in 0..8 {
|
2021-09-30 19:58:11 +00:00
|
|
|
if (mask & 0x01) != 0 {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.state.d_reg[i] = get_address_sized(system, addr as Address, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
addr += size.in_bytes();
|
2021-09-30 19:58:11 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
2021-10-02 05:06:53 +00:00
|
|
|
for i in 0..8 {
|
2021-09-30 19:58:11 +00:00
|
|
|
if (mask & 0x01) != 0 {
|
2021-10-06 23:14:56 +00:00
|
|
|
*self.get_a_reg_mut(i) = get_address_sized(system, addr as Address, size)?;
|
2021-10-05 23:22:21 +00:00
|
|
|
addr += size.in_bytes();
|
2021-09-30 19:58:11 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
|
|
|
}
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
_ => { },
|
|
|
|
}
|
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);
|
|
|
|
},
|
|
|
|
Instruction::MUL(src, dest, size, sign) => {
|
|
|
|
if size == Size::Long {
|
|
|
|
return Err(Error::new("Unsupported multiplication 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 = match sign {
|
|
|
|
Sign::Signed => (sign_extend_to_long(existing, Size::Word) * sign_extend_to_long(value, Size::Word)) as u32,
|
|
|
|
Sign::Unsigned => existing as u32 * value as u32,
|
|
|
|
};
|
2021-10-06 23:14:56 +00:00
|
|
|
self.set_target_value(system, dest, result, Size::Long)?;
|
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) => {
|
|
|
|
let value = self.get_target_address(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 {
|
|
|
|
pair = rotate_operation(pair.0, size, shift_dir);
|
|
|
|
}
|
|
|
|
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-09-30 00:11:48 +00:00
|
|
|
//Instruction::ROXd(Target, Target, Size, ShiftDirection) => {
|
|
|
|
//},
|
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-06 23:14:56 +00:00
|
|
|
self.exception(system, 32 + number)?;
|
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-11 22:16:04 +00:00
|
|
|
self.exception(system, Exceptions::TrapvInstruction as u8)?;
|
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-04 03:45:50 +00:00
|
|
|
self.timer.execute.end(timer);
|
2021-09-30 00:11:48 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn push_word(&mut self, system: &System, value: u16) -> Result<(), Error> {
|
2021-10-06 04:53:18 +00:00
|
|
|
let reg = self.get_stack_pointer_mut();
|
|
|
|
*reg -= 2;
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(*reg 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-06 04:53:18 +00:00
|
|
|
let reg = self.get_stack_pointer_mut();
|
2021-10-07 16:41:01 +00:00
|
|
|
let value = system.get_bus().read_beu16(*reg as Address)?;
|
2021-10-06 04:53:18 +00:00
|
|
|
*reg += 2;
|
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn push_long(&mut self, system: &System, value: u32) -> Result<(), Error> {
|
2021-10-02 15:47:20 +00:00
|
|
|
let reg = self.get_stack_pointer_mut();
|
|
|
|
*reg -= 4;
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu32(*reg 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-02 15:47:20 +00:00
|
|
|
let reg = self.get_stack_pointer_mut();
|
2021-10-07 16:41:01 +00:00
|
|
|
let value = system.get_bus().read_beu32(*reg as Address)?;
|
2021-10-02 15:47:20 +00:00
|
|
|
*reg += 4;
|
|
|
|
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-06 23:14:56 +00:00
|
|
|
Target::IndirectAReg(reg) => get_address_sized(system, *self.get_a_reg_mut(reg) as Address, size),
|
2021-09-30 00:11:48 +00:00
|
|
|
Target::IndirectARegInc(reg) => {
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = get_address_sized(system, *addr as Address, size);
|
2021-09-30 00:11:48 +00:00
|
|
|
*addr += size.in_bytes();
|
2021-09-30 04:52:38 +00:00
|
|
|
result
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegDec(reg) => {
|
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 -= size.in_bytes();
|
2021-10-06 23:14:56 +00:00
|
|
|
get_address_sized(system, *addr as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegOffset(reg, offset) => {
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-06 23:14:56 +00:00
|
|
|
get_address_sized(system, (*addr).wrapping_add(offset as u32) as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-15 21:37:31 +00:00
|
|
|
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, target_size) => {
|
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(xreg), target_size);
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-15 21:37:31 +00:00
|
|
|
get_address_sized(system, ((*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) << scale) as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectMemory(addr) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
get_address_sized(system, addr as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectPCOffset(offset) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
get_address_sized(system, (self.decoder.start + 2).wrapping_add(offset as u32) as Address, size)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-15 21:37:31 +00:00
|
|
|
Target::IndirectPCXRegOffset(xreg, offset, scale, target_size) => {
|
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(xreg), target_size);
|
|
|
|
get_address_sized(system, ((self.decoder.start + 2).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) << scale) 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-06 23:14:56 +00:00
|
|
|
set_address_sized(system, *self.get_a_reg_mut(reg) as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegInc(reg) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, *addr as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
*addr += size.in_bytes();
|
|
|
|
},
|
|
|
|
Target::IndirectARegDec(reg) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
*addr -= size.in_bytes();
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, *addr as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Target::IndirectARegOffset(reg, offset) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, (*addr).wrapping_add(offset as u32) as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
2021-10-15 21:37:31 +00:00
|
|
|
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, target_size) => {
|
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(xreg), target_size);
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-15 21:37:31 +00:00
|
|
|
set_address_sized(system, ((*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) << scale) as Address, value, size)?;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Target::IndirectMemory(addr) => {
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, 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-05 23:22:21 +00:00
|
|
|
pub fn get_target_address(&mut self, 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-09-30 00:11:48 +00:00
|
|
|
Target::IndirectARegOffset(reg, offset) => {
|
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).wrapping_add(offset as u32)
|
|
|
|
},
|
2021-10-15 21:37:31 +00:00
|
|
|
Target::IndirectARegXRegOffset(reg, xreg, offset, scale, target_size) => {
|
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(xreg), target_size);
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-15 21:37:31 +00:00
|
|
|
(*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) << scale
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Target::IndirectMemory(addr) => {
|
|
|
|
addr
|
|
|
|
},
|
|
|
|
Target::IndirectPCOffset(offset) => {
|
2021-10-02 16:48:21 +00:00
|
|
|
(self.decoder.start + 2).wrapping_add(offset as u32)
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-10-15 21:37:31 +00:00
|
|
|
Target::IndirectPCXRegOffset(xreg, offset, scale, target_size) => {
|
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(xreg), target_size);
|
|
|
|
(self.decoder.start + 2).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) << scale
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
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-09-30 04:52:38 +00:00
|
|
|
fn get_a_reg_mut(&mut self, reg: u8) -> &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-15 21:37:31 +00:00
|
|
|
fn get_x_reg_value(&self, xreg: XRegister) -> u32 {
|
|
|
|
match xreg {
|
|
|
|
XRegister::Data(reg) => self.state.d_reg[reg as usize],
|
|
|
|
XRegister::Address(reg) => self.state.a_reg[reg as usize],
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-30 04:52:38 +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-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-05 23:22:21 +00:00
|
|
|
fn rotate_operation(value: u32, size: Size, dir: ShiftDirection) -> (u32, bool) {
|
|
|
|
match dir {
|
|
|
|
ShiftDirection::Left => {
|
|
|
|
let bit = get_msb(value, size);
|
|
|
|
let mask = if 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 bit { get_msb_mask(0xffffffff, size) } else { 0x0 };
|
|
|
|
((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 },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn get_address_sized(system: &System, addr: Address, size: Size) -> Result<u32, Error> {
|
2021-09-30 00:11:48 +00:00
|
|
|
match size {
|
2021-10-07 16:41:01 +00:00
|
|
|
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),
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
fn set_address_sized(system: &System, addr: Address, value: u32, size: Size) -> Result<(), Error> {
|
2021-09-30 00:11:48 +00:00
|
|
|
match size {
|
2021-10-07 16:41:01 +00:00
|
|
|
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),
|
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 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
|
|
|
|