2021-09-30 00:11:48 +00:00
|
|
|
|
|
|
|
use crate::error::Error;
|
2021-10-04 03:45:50 +00:00
|
|
|
use crate::timers::CpuTimer;
|
2021-10-07 16:41:01 +00:00
|
|
|
use crate::memory::{Address, Addressable};
|
2021-10-06 23:14:56 +00:00
|
|
|
use crate::system::System;
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-02 16:35:25 +00:00
|
|
|
use super::debugger::M68kDebugger;
|
2021-10-02 15:47:20 +00:00
|
|
|
use super::decode::{
|
|
|
|
M68kDecoder,
|
|
|
|
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,
|
|
|
|
RegisterType,
|
|
|
|
sign_extend_to_long
|
|
|
|
};
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-02 16:35:25 +00:00
|
|
|
|
2021-10-01 03:27:01 +00:00
|
|
|
const FLAGS_ON_RESET: u16 = 0x2700;
|
|
|
|
|
|
|
|
pub const FLAGS_CARRY: u16 = 0x0001;
|
|
|
|
pub const FLAGS_OVERFLOW: u16 = 0x0002;
|
|
|
|
pub const FLAGS_ZERO: u16 = 0x0004;
|
|
|
|
pub const FLAGS_NEGATIVE: u16 = 0x0008;
|
2021-10-01 22:38:21 +00:00
|
|
|
pub const FLAGS_EXTEND: u16 = 0x0010;
|
2021-10-01 03:27:01 +00:00
|
|
|
pub const FLAGS_SUPERVISOR: u16 = 0x2000;
|
2021-10-06 04:53:18 +00:00
|
|
|
pub const FLAGS_TRACING: u16 = 0x8000;
|
2021-10-01 03:27:01 +00:00
|
|
|
|
|
|
|
pub const ERR_BUS_ERROR: u32 = 2;
|
|
|
|
pub const ERR_ADDRESS_ERROR: u32 = 3;
|
|
|
|
pub const ERR_ILLEGAL_INSTRUCTION: u32 = 4;
|
|
|
|
|
2021-09-30 00:11:48 +00:00
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
2021-10-02 15:47:20 +00:00
|
|
|
pub enum Status {
|
2021-09-30 00:11:48 +00:00
|
|
|
Init,
|
|
|
|
Running,
|
2021-10-02 15:47:20 +00:00
|
|
|
Stopped,
|
2021-10-06 04:53:18 +00:00
|
|
|
Halted,
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
pub struct MC68010State {
|
|
|
|
pub status: Status,
|
2021-09-30 00:11:48 +00:00
|
|
|
|
|
|
|
pub pc: u32,
|
|
|
|
pub sr: u16,
|
|
|
|
pub d_reg: [u32; 8],
|
|
|
|
pub a_reg: [u32; 7],
|
|
|
|
pub msp: u32,
|
|
|
|
pub usp: u32,
|
|
|
|
|
|
|
|
pub vbr: u32,
|
|
|
|
}
|
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
impl MC68010State {
|
|
|
|
pub fn new() -> MC68010State {
|
|
|
|
MC68010State {
|
|
|
|
status: Status::Init,
|
2021-09-30 00:11:48 +00:00
|
|
|
|
|
|
|
pc: 0,
|
|
|
|
sr: FLAGS_ON_RESET,
|
|
|
|
d_reg: [0; 8],
|
|
|
|
a_reg: [0; 7],
|
|
|
|
msp: 0,
|
|
|
|
usp: 0,
|
|
|
|
|
|
|
|
vbr: 0,
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MC68010 {
|
|
|
|
pub state: MC68010State,
|
|
|
|
pub decoder: M68kDecoder,
|
2021-10-02 16:35:25 +00:00
|
|
|
pub debugger: M68kDebugger,
|
2021-10-04 03:45:50 +00:00
|
|
|
pub timer: CpuTimer,
|
2021-10-02 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MC68010 {
|
|
|
|
pub fn new() -> MC68010 {
|
|
|
|
MC68010 {
|
|
|
|
state: MC68010State::new(),
|
2021-10-06 23:14:56 +00:00
|
|
|
decoder: M68kDecoder::new(0, 0),
|
2021-10-02 16:35:25 +00:00
|
|
|
debugger: M68kDebugger::new(),
|
2021-10-04 03:45:50 +00:00
|
|
|
timer: CpuTimer::new(),
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
pub fn dump_state(&self, system: &System) {
|
2021-10-06 04:53:18 +00:00
|
|
|
println!("Status: {:?}", self.state.status);
|
|
|
|
println!("PC: {:#010x}", self.state.pc);
|
|
|
|
println!("SR: {:#06x}", self.state.sr);
|
|
|
|
for i in 0..7 {
|
|
|
|
println!("D{}: {:#010x} A{}: {:#010x}", i, self.state.d_reg[i as usize], i, self.state.a_reg[i as usize]);
|
|
|
|
}
|
|
|
|
println!("D7: {:#010x}", self.state.d_reg[7]);
|
|
|
|
println!("MSP: {:#010x}", self.state.msp);
|
|
|
|
println!("USP: {:#010x}", self.state.usp);
|
|
|
|
|
|
|
|
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
|
|
|
|
println!("");
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().dump_memory(self.state.msp as Address, 0x40);
|
2021-10-06 04:53:18 +00:00
|
|
|
println!("");
|
|
|
|
}
|
|
|
|
|
2021-09-30 00:11:48 +00:00
|
|
|
pub fn reset(&mut self) {
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state = MC68010State::new();
|
2021-10-06 23:14:56 +00:00
|
|
|
self.decoder = M68kDecoder::new(0, 0);
|
2021-10-02 16:35:25 +00:00
|
|
|
self.debugger = M68kDebugger::new();
|
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-06 23:14:56 +00:00
|
|
|
pub fn init(&mut self, system: &System) -> Result<(), Error> {
|
2021-09-30 00:11:48 +00:00
|
|
|
println!("Initializing CPU");
|
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
self.state.msp = system.get_bus().read_beu32(0)?;
|
|
|
|
self.state.pc = system.get_bus().read_beu32(4)?;
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.status = Status::Running;
|
2021-09-30 00:11:48 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
pub fn step(&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-06 04:53:18 +00:00
|
|
|
Status::Stopped | Status::Halted => Err(Error::new("CPU stopped")),
|
2021-10-02 15:47:20 +00:00
|
|
|
Status::Running => {
|
2021-10-04 03:45:50 +00:00
|
|
|
let timer = self.timer.cycle.start();
|
2021-10-06 23:14:56 +00:00
|
|
|
self.decode_next(system)?;
|
|
|
|
self.execute_current(system)?;
|
2021-10-04 03:45:50 +00:00
|
|
|
self.timer.cycle.end(timer);
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
if (self.timer.cycle.events % 500) == 0 {
|
|
|
|
println!("{}", self.timer);
|
|
|
|
}
|
2021-10-04 03:45:50 +00:00
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
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-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-06 04:53:18 +00:00
|
|
|
self.state.sr |= FLAGS_SUPERVISOR;
|
|
|
|
self.state.sr &= !FLAGS_TRACING;
|
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-06 23:14:56 +00:00
|
|
|
self.decoder = M68kDecoder::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-09-30 22:15:23 +00:00
|
|
|
// Print instruction bytes for debugging
|
|
|
|
let ins_data: Result<String, Error> =
|
2021-10-02 22:35:08 +00:00
|
|
|
(0..((self.decoder.end - self.decoder.start) / 2)).map(|offset|
|
2021-10-07 16:41:01 +00:00
|
|
|
Ok(format!("{:04x} ", system.get_bus().read_beu16((self.decoder.start + (offset * 2)) as Address)?))
|
2021-09-30 22:15:23 +00:00
|
|
|
).collect();
|
2021-10-02 15:47:20 +00:00
|
|
|
debug!("{:#010x}: {}\n\t{:?}\n", self.decoder.start, ins_data?, self.decoder.instruction);
|
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-02 15:47:20 +00:00
|
|
|
self.state.sr = self.state.sr | value as u16;
|
2021-09-30 04:52:38 +00:00
|
|
|
},
|
|
|
|
Instruction::ANDtoSR(value) => {
|
2021-10-02 15:47:20 +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 {
|
|
|
|
self.state.sr |= FLAGS_EXTEND | FLAGS_CARRY;
|
|
|
|
}
|
|
|
|
if get_msb(pair.0, size) != get_msb(original, size) {
|
|
|
|
self.state.sr |= FLAGS_OVERFLOW;
|
|
|
|
}
|
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-02 22:35:08 +00:00
|
|
|
self.state.sr = (self.state.sr & 0xFFF0) | FLAGS_ZERO;
|
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)?;
|
|
|
|
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 {
|
|
|
|
Sign::Signed => ((existing as i16 % value as i16) as u32) << 16 | (0xFFFF & (existing as i16 / value as i16) as u32),
|
|
|
|
Sign::Unsigned => ((existing as u16 % value as u16) as u32) << 16 | (0xFFFF & (existing as u16 / value as u16) as u32),
|
|
|
|
};
|
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-02 15:47:20 +00:00
|
|
|
self.state.sr = self.state.sr ^ value as u16;
|
2021-10-01 03:27:01 +00:00
|
|
|
},
|
|
|
|
Instruction::EORtoSR(value) => {
|
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-09-30 22:15:23 +00:00
|
|
|
Instruction::EXT(reg, size) => {
|
2021-10-02 15:47:20 +00:00
|
|
|
let byte = (self.state.d_reg[reg as usize] as u8) as i8;
|
2021-10-01 19:25:23 +00:00
|
|
|
let result = match size {
|
|
|
|
Size::Byte => (byte as u8) as u32,
|
|
|
|
Size::Word => ((byte as i16) as u16) as u32,
|
|
|
|
Size::Long => (byte as i32) as u32,
|
|
|
|
};
|
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], result, size);
|
|
|
|
self.set_logic_flags(result, 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-02 15:47:20 +00:00
|
|
|
self.state.sr |= FLAGS_EXTEND | FLAGS_CARRY;
|
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-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-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) => {
|
|
|
|
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) => {
|
|
|
|
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-02 15:47:20 +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-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-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 {
|
|
|
|
self.state.sr |= FLAGS_CARRY;
|
|
|
|
}
|
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-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) => {
|
|
|
|
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 => {
|
|
|
|
if self.get_flag(FLAGS_OVERFLOW) {
|
2021-10-06 23:14:56 +00:00
|
|
|
self.exception(system, 7)?;
|
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
|
|
|
},
|
|
|
|
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_size) => {
|
2021-10-01 22:38:21 +00:00
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
|
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(reg_offset as u32).wrapping_add(offset as u32) 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
|
|
|
},
|
|
|
|
Target::IndirectPCXRegOffset(rtype, xreg, offset, target_size) => {
|
2021-10-01 22:38:21 +00:00
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
|
2021-10-06 23:14:56 +00:00
|
|
|
get_address_sized(system, (self.decoder.start + 2).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) 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
|
|
|
},
|
|
|
|
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_size) => {
|
2021-10-01 22:38:21 +00:00
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-06 23:14:56 +00:00
|
|
|
set_address_sized(system, (*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32) 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)
|
|
|
|
},
|
|
|
|
Target::IndirectARegXRegOffset(reg, rtype, xreg, offset, target_size) => {
|
2021-10-01 22:38:21 +00:00
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
|
2021-09-30 04:52:38 +00:00
|
|
|
let addr = self.get_a_reg_mut(reg);
|
2021-10-01 22:38:21 +00:00
|
|
|
(*addr).wrapping_add(reg_offset as u32).wrapping_add(offset as u32)
|
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
|
|
|
},
|
|
|
|
Target::IndirectPCXRegOffset(rtype, xreg, offset, target_size) => {
|
2021-10-01 22:38:21 +00:00
|
|
|
let reg_offset = sign_extend_to_long(self.get_x_reg_value(rtype, xreg), target_size);
|
2021-10-02 16:48:21 +00:00
|
|
|
(self.decoder.start + 2).wrapping_add(reg_offset as u32).wrapping_add(offset as u32)
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_x_reg_value(&self, rtype: RegisterType, reg: u8) -> u32 {
|
|
|
|
match rtype {
|
2021-10-02 15:47:20 +00:00
|
|
|
RegisterType::Data => self.state.d_reg[reg as usize],
|
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
|
|
|
RegisterType::Address => 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-02 15:47:20 +00:00
|
|
|
fn is_supervisor(&self) -> bool {
|
|
|
|
self.state.sr & FLAGS_SUPERVISOR != 0
|
|
|
|
}
|
|
|
|
|
2021-09-30 04:52:38 +00:00
|
|
|
fn get_flag(&self, flag: u16) -> bool {
|
2021-10-02 15:47:20 +00:00
|
|
|
if (self.state.sr & flag) == 0 {
|
2021-09-30 04:52:38 +00:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-05 23:22:21 +00:00
|
|
|
fn set_flag(&mut self, flag: u16, value: bool) {
|
|
|
|
self.state.sr = (self.state.sr & !flag) | (if value { flag } else { 0 });
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
flags |= FLAGS_NEGATIVE
|
|
|
|
}
|
|
|
|
if value == 0 {
|
|
|
|
flags |= FLAGS_ZERO
|
|
|
|
}
|
|
|
|
if carry {
|
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
|
|
|
flags |= FLAGS_CARRY;
|
|
|
|
}
|
|
|
|
if overflow {
|
|
|
|
flags |= FLAGS_OVERFLOW;
|
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) {
|
|
|
|
flags |= FLAGS_NEGATIVE;
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
if value == 0 {
|
|
|
|
flags |= FLAGS_ZERO
|
|
|
|
}
|
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());
|
|
|
|
let zeroflag = if (value & mask) == 0 { FLAGS_ZERO } else { 0 };
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.sr = (self.state.sr & !FLAGS_ZERO) | zeroflag;
|
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,
|
|
|
|
Condition::High => !self.get_flag(FLAGS_CARRY) && !self.get_flag(FLAGS_ZERO),
|
|
|
|
Condition::LowOrSame => self.get_flag(FLAGS_CARRY) || self.get_flag(FLAGS_ZERO),
|
|
|
|
Condition::CarryClear => !self.get_flag(FLAGS_CARRY),
|
|
|
|
Condition::CarrySet => self.get_flag(FLAGS_CARRY),
|
|
|
|
Condition::NotEqual => !self.get_flag(FLAGS_ZERO),
|
|
|
|
Condition::Equal => self.get_flag(FLAGS_ZERO),
|
|
|
|
Condition::OverflowClear => !self.get_flag(FLAGS_OVERFLOW),
|
|
|
|
Condition::OverflowSet => self.get_flag(FLAGS_OVERFLOW),
|
|
|
|
Condition::Plus => !self.get_flag(FLAGS_NEGATIVE),
|
|
|
|
Condition::Minus => self.get_flag(FLAGS_NEGATIVE),
|
|
|
|
Condition::GreaterThanOrEqual => (self.get_flag(FLAGS_NEGATIVE) && self.get_flag(FLAGS_OVERFLOW)) || (!self.get_flag(FLAGS_NEGATIVE) && !self.get_flag(FLAGS_OVERFLOW)),
|
|
|
|
Condition::LessThan => (self.get_flag(FLAGS_NEGATIVE) && !self.get_flag(FLAGS_OVERFLOW)) || (!self.get_flag(FLAGS_NEGATIVE) && self.get_flag(FLAGS_OVERFLOW)),
|
|
|
|
Condition::GreaterThan =>
|
|
|
|
(self.get_flag(FLAGS_NEGATIVE) && self.get_flag(FLAGS_OVERFLOW) && !self.get_flag(FLAGS_ZERO))
|
|
|
|
|| (!self.get_flag(FLAGS_NEGATIVE) && !self.get_flag(FLAGS_OVERFLOW) && !self.get_flag(FLAGS_ZERO)),
|
|
|
|
Condition::LessThanOrEqual =>
|
2021-09-30 04:52:38 +00:00
|
|
|
self.get_flag(FLAGS_ZERO)
|
2021-09-30 19:58:11 +00:00
|
|
|
|| (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
|
|
|
|