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-09-30 00:11:48 +00:00
|
|
|
use crate::memory::{Address, AddressSpace};
|
|
|
|
|
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
|
|
|
/*
|
2021-09-30 00:11:48 +00:00
|
|
|
pub trait Processor {
|
|
|
|
fn reset();
|
|
|
|
fn step();
|
|
|
|
}
|
2021-10-01 03:27:01 +00:00
|
|
|
*/
|
2021-09-30 00:11:48 +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;
|
|
|
|
|
|
|
|
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-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(),
|
|
|
|
decoder: M68kDecoder::new(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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset(&mut self) {
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state = MC68010State::new();
|
|
|
|
self.decoder = M68kDecoder::new(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
|
|
|
}
|
|
|
|
|
|
|
|
pub fn init(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
|
|
|
println!("Initializing CPU");
|
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.msp = space.read_beu32(0)?;
|
|
|
|
self.state.pc = space.read_beu32(4)?;
|
|
|
|
self.state.status = Status::Running;
|
2021-09-30 00:11:48 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-01 19:25:23 +00:00
|
|
|
pub fn dump_state(&self, space: &mut AddressSpace) {
|
2021-10-02 15:47:20 +00:00
|
|
|
println!("Status: {:?}", self.state.status);
|
|
|
|
println!("PC: {:#010x}", self.state.pc);
|
|
|
|
println!("SR: {:#06x}", self.state.sr);
|
2021-09-30 04:52:38 +00:00
|
|
|
for i in 0..7 {
|
2021-10-02 15:47:20 +00:00
|
|
|
println!("D{}: {:#010x} A{}: {:#010x}", i, self.state.d_reg[i as usize], i, self.state.a_reg[i as usize]);
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
2021-10-02 15:47:20 +00:00
|
|
|
println!("D7: {:#010x}", self.state.d_reg[7]);
|
|
|
|
println!("MSP: {:#010x}", self.state.msp);
|
|
|
|
println!("USP: {:#010x}", self.state.usp);
|
2021-09-30 19:58:11 +00:00
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
|
2021-09-30 19:58:11 +00:00
|
|
|
println!("");
|
2021-10-02 15:47:20 +00:00
|
|
|
space.dump_memory(self.state.msp as Address, 0x40);
|
2021-09-30 19:58:11 +00:00
|
|
|
println!("");
|
2021-09-30 04:52:38 +00:00
|
|
|
}
|
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
pub fn step(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
|
|
|
match self.state.status {
|
|
|
|
Status::Init => self.init(space),
|
|
|
|
Status::Stopped => Err(Error::new("CPU stopped")),
|
|
|
|
Status::Running => {
|
2021-10-04 03:45:50 +00:00
|
|
|
let timer = self.timer.cycle.start();
|
2021-10-02 15:47:20 +00:00
|
|
|
self.decode_next(space)?;
|
|
|
|
self.execute_current(space)?;
|
2021-10-04 03:45:50 +00:00
|
|
|
self.timer.cycle.end(timer);
|
|
|
|
|
|
|
|
if (self.timer.cycle.events % 500) == 0 {
|
|
|
|
println!("{}", self.timer);
|
|
|
|
}
|
|
|
|
|
2021-10-02 15:47:20 +00:00
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
}
|
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
|
|
|
pub fn decode_next(&mut self, space: &mut AddressSpace) -> 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-02 22:35:08 +00:00
|
|
|
self.decoder = M68kDecoder::decode_at(space, 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-02 15:47:20 +00:00
|
|
|
Ok(format!("{:04x} ", space.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-02 00:53:55 +00:00
|
|
|
self.run_debugger(space);
|
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
|
|
|
|
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
|
|
|
pub fn execute_current(&mut self, space: &mut AddressSpace) -> 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) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, 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-09-30 04:52:38 +00:00
|
|
|
self.set_target_value(space, dest, result, size)?;
|
|
|
|
},
|
|
|
|
Instruction::AND(src, dest, size) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, dest, size)?;
|
|
|
|
self.set_target_value(space, dest, existing & value, size)?;
|
|
|
|
self.set_logic_flags(value, size);
|
|
|
|
},
|
|
|
|
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) => {
|
|
|
|
let count = self.get_target_value(space, count, size)? % 64;
|
|
|
|
let mut pair = (self.get_target_value(space, target, size)?, false);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
self.set_target_value(space, target, pair.0, size)?;
|
|
|
|
},
|
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-02 15:47:20 +00:00
|
|
|
self.push_long(space, self.state.pc)?;
|
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) => {
|
|
|
|
let bitnum = self.get_target_value(space, bitnum, Size::Byte)?;
|
|
|
|
let value = self.get_target_value(space, target, size)?;
|
|
|
|
self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
},
|
|
|
|
Instruction::BCHG(bitnum, target, size) => {
|
|
|
|
let bitnum = self.get_target_value(space, bitnum, Size::Byte)?;
|
|
|
|
let mut value = self.get_target_value(space, target, size)?;
|
|
|
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
value = (value & !mask) | (!(value & mask) & mask);
|
|
|
|
self.set_target_value(space, target, value, size)?;
|
|
|
|
},
|
|
|
|
Instruction::BCLR(bitnum, target, size) => {
|
|
|
|
let bitnum = self.get_target_value(space, bitnum, Size::Byte)?;
|
|
|
|
let mut value = self.get_target_value(space, target, size)?;
|
|
|
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
value = value & !mask;
|
|
|
|
self.set_target_value(space, target, value, size)?;
|
|
|
|
},
|
|
|
|
Instruction::BSET(bitnum, target, size) => {
|
|
|
|
let bitnum = self.get_target_value(space, bitnum, Size::Byte)?;
|
|
|
|
let mut value = self.get_target_value(space, target, size)?;
|
|
|
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
|
|
|
value = value | mask;
|
|
|
|
self.set_target_value(space, target, value, size)?;
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::CLR(target, size) => {
|
|
|
|
self.set_target_value(space, 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) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, 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) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = sign_extend_to_long(*self.get_a_reg_mut(reg), size) 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
|
|
|
let (result, carry) = overflowing_sub_sized(existing, value, Size::Long);
|
|
|
|
self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, Size::Long));
|
|
|
|
},
|
|
|
|
Instruction::DBcc(cond, reg, offset) => {
|
|
|
|
let condition_true = self.get_current_condition(cond);
|
|
|
|
if !condition_true {
|
|
|
|
let next = (get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16 - 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"));
|
|
|
|
}
|
|
|
|
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, dest, Size::Long)?;
|
|
|
|
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),
|
|
|
|
};
|
|
|
|
self.set_target_value(space, 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) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, dest, size)?;
|
|
|
|
self.set_target_value(space, dest, existing ^ value, size)?;
|
|
|
|
self.set_logic_flags(value, size);
|
|
|
|
},
|
|
|
|
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-02 15:47:20 +00:00
|
|
|
self.push_long(space, self.state.pc)?;
|
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);
|
|
|
|
self.push_long(space, value)?;
|
|
|
|
let sp = *self.get_stack_pointer_mut();
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
*addr = sp;
|
|
|
|
*self.get_stack_pointer_mut() = sp + (offset as i32) as u32;
|
|
|
|
},
|
2021-10-01 22:38:21 +00:00
|
|
|
Instruction::LSd(count, target, size, shift_dir) => {
|
|
|
|
let count = self.get_target_value(space, count, size)? % 64;
|
|
|
|
let mut pair = (self.get_target_value(space, target, size)?, false);
|
|
|
|
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
|
|
|
}
|
|
|
|
self.set_target_value(space, target, pair.0, size)?;
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
Instruction::MOVE(src, dest, size) => {
|
|
|
|
let value = self.get_target_value(space, 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-09-30 00:11:48 +00:00
|
|
|
self.set_target_value(space, dest, value, size)?;
|
|
|
|
},
|
2021-10-01 19:25:23 +00:00
|
|
|
Instruction::MOVEA(src, reg, size) => {
|
|
|
|
let value = self.get_target_value(space, 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-02 15:47:20 +00:00
|
|
|
self.set_target_value(space, target, self.state.sr as u32, Size::Word)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
Instruction::MOVEtoSR(target) => {
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.sr = self.get_target_value(space, target, Size::Word)? as u16;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
2021-09-30 22:15:23 +00:00
|
|
|
Instruction::MOVEtoCCR(target) => {
|
|
|
|
let value = self.get_target_value(space, 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 => {
|
|
|
|
let value = self.get_target_value(space, target, Size::Long)?;
|
|
|
|
let addr = self.get_control_reg_mut(control_reg);
|
|
|
|
*addr = value;
|
|
|
|
},
|
|
|
|
Direction::ToTarget => {
|
|
|
|
let addr = self.get_control_reg_mut(control_reg);
|
|
|
|
let value = *addr;
|
|
|
|
self.set_target_value(space, target, value, Size::Long)?;
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
2021-10-02 22:35:08 +00:00
|
|
|
Instruction::MOVEUSP(target, dir) => {
|
|
|
|
match dir {
|
|
|
|
Direction::ToTarget => self.set_target_value(space, target, self.state.usp, Size::Long)?,
|
|
|
|
Direction::FromTarget => { self.state.usp = self.get_target_value(space, target, Size::Long)?; },
|
|
|
|
}
|
|
|
|
},
|
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
|
|
|
|
|
|
|
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);
|
|
|
|
self.set_target_value(space, target, 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-02 15:47:20 +00:00
|
|
|
self.set_target_value(space, target, 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-02 15:47:20 +00:00
|
|
|
self.state.d_reg[i] = self.get_target_value(space, target, size)?;
|
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-02 05:06:53 +00:00
|
|
|
let value = self.get_target_value(space, target, size)?;
|
|
|
|
let addr = self.get_a_reg_mut(i);
|
|
|
|
*addr = value;
|
2021-09-30 19:58:11 +00:00
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
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"));
|
|
|
|
}
|
|
|
|
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, dest, size)?;
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
self.set_target_value(space, 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) => {
|
|
|
|
let original = self.get_target_value(space, target, size)?;
|
|
|
|
let (value, _) = (0 as u32).overflowing_sub(original);
|
|
|
|
self.set_target_value(space, target, value, size);
|
|
|
|
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) => {
|
|
|
|
let mut value = self.get_target_value(space, target, size)?;
|
|
|
|
value = get_value_sized(!value, size);
|
|
|
|
self.set_target_value(space, target, value, size)?;
|
|
|
|
self.set_logic_flags(value, size);
|
|
|
|
},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::OR(src, dest, size) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, dest, size)?;
|
|
|
|
self.set_target_value(space, dest, existing | value, size)?;
|
|
|
|
self.set_logic_flags(value, size);
|
|
|
|
},
|
|
|
|
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)?;
|
|
|
|
self.push_long(space, value)?;
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::RESET => {
|
|
|
|
//},
|
|
|
|
//Instruction::ROd(Target, Target, Size, ShiftDirection) => {
|
|
|
|
//},
|
|
|
|
//Instruction::ROXd(Target, Target, Size, ShiftDirection) => {
|
|
|
|
//},
|
|
|
|
//Instruction::RTE => {
|
|
|
|
//},
|
|
|
|
//Instruction::RTR => {
|
|
|
|
//},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::RTS => {
|
2021-10-02 15:47:20 +00:00
|
|
|
self.state.pc = self.pop_long(space)?;
|
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 {
|
|
|
|
self.set_target_value(space, target, 0xFF, Size::Byte);
|
|
|
|
} else {
|
|
|
|
self.set_target_value(space, target, 0x00, Size::Byte);
|
|
|
|
}
|
|
|
|
},
|
2021-09-30 00:11:48 +00:00
|
|
|
//Instruction::STOP(u16) => {
|
|
|
|
//},
|
2021-09-30 04:52:38 +00:00
|
|
|
Instruction::SUB(src, dest, size) => {
|
|
|
|
let value = self.get_target_value(space, src, size)?;
|
|
|
|
let existing = self.get_target_value(space, 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-09-30 04:52:38 +00:00
|
|
|
self.set_target_value(space, dest, result, size)?;
|
|
|
|
},
|
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) => {
|
|
|
|
let value = self.get_target_value(space, 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-09-30 00:11:48 +00:00
|
|
|
//Instruction::TRAP(u8) => {
|
|
|
|
//},
|
|
|
|
//Instruction::TRAPV => {
|
|
|
|
//},
|
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;
|
|
|
|
let new_value = self.pop_long(space)?;
|
|
|
|
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-02 15:47:20 +00:00
|
|
|
fn push_long(&mut self, space: &mut AddressSpace, value: u32) -> Result<(), Error> {
|
|
|
|
let reg = self.get_stack_pointer_mut();
|
|
|
|
*reg -= 4;
|
|
|
|
//println!("PUSHING {:08x} at {:08x}", value, *reg);
|
|
|
|
space.write_beu32(*reg as Address, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_long(&mut self, space: &mut AddressSpace) -> Result<u32, Error> {
|
|
|
|
let reg = self.get_stack_pointer_mut();
|
|
|
|
let value = space.read_beu32(*reg as Address)?;
|
|
|
|
//println!("POPPING {:08x} at {:08x}", value, *reg);
|
|
|
|
*reg += 4;
|
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
2021-09-30 00:11:48 +00:00
|
|
|
fn get_target_value(&mut self, space: &mut AddressSpace, target: Target, size: Size) -> Result<u32, Error> {
|
|
|
|
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)),
|
|
|
|
Target::IndirectAReg(reg) => get_address_sized(space, *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);
|
|
|
|
let result = get_address_sized(space, *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();
|
|
|
|
get_address_sized(space, *addr as Address, size)
|
|
|
|
},
|
|
|
|
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
|
|
|
get_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, size)
|
|
|
|
},
|
|
|
|
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);
|
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
|
|
|
get_address_sized(space, (*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) => {
|
|
|
|
get_address_sized(space, addr as Address, size)
|
|
|
|
},
|
|
|
|
Target::IndirectPCOffset(offset) => {
|
2021-10-02 16:48:21 +00:00
|
|
|
get_address_sized(space, (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-02 16:48:21 +00:00
|
|
|
get_address_sized(space, (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
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_target_value(&mut self, space: &mut AddressSpace, target: Target, value: u32, size: Size) -> Result<(), Error> {
|
|
|
|
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-09-30 04:52:38 +00:00
|
|
|
set_address_sized(space, *self.get_a_reg_mut(reg) as Address, value, size)?;
|
|
|
|
},
|
|
|
|
Target::IndirectARegInc(reg) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
set_address_sized(space, *addr as Address, value, size)?;
|
|
|
|
*addr += size.in_bytes();
|
|
|
|
},
|
|
|
|
Target::IndirectARegDec(reg) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
*addr -= size.in_bytes();
|
|
|
|
set_address_sized(space, *addr as Address, value, size)?;
|
|
|
|
},
|
|
|
|
Target::IndirectARegOffset(reg, offset) => {
|
|
|
|
let addr = self.get_a_reg_mut(reg);
|
|
|
|
set_address_sized(space, (*addr).wrapping_add(offset as u32) as Address, value, size)?;
|
|
|
|
},
|
|
|
|
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
|
|
|
set_address_sized(space, (*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) => {
|
|
|
|
set_address_sized(space, addr as Address, value, size)?;
|
2021-09-30 00:11:48 +00:00
|
|
|
},
|
|
|
|
_ => return Err(Error::new(&format!("Unimplemented addressing target: {:?}", target))),
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_target_address(&mut self, target: Target) -> Result<u32, Error> {
|
|
|
|
let addr = match target {
|
2021-09-30 04:52:38 +00:00
|
|
|
Target::IndirectAReg(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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 => {
|
|
|
|
match size {
|
|
|
|
Size::Byte => (((value as u8) << 1) as u32, get_msb(value, size)),
|
|
|
|
Size::Word => (((value as u16) << 1) as u32, get_msb(value, size)),
|
|
|
|
Size::Long => ((value << 1) as u32, get_msb(value, size)),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ShiftDirection::Right => {
|
|
|
|
let mask = if arithmetic { get_msb_mask(value, size) } else { 0 };
|
|
|
|
((value >> 1) | mask, (value & 0x1) != 0)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-09-30 00:11:48 +00:00
|
|
|
fn get_value_sized(value: u32, size: Size) -> u32 {
|
|
|
|
match size {
|
|
|
|
Size::Byte => { 0x000000FF & value },
|
|
|
|
Size::Word => { 0x0000FFFF & value },
|
|
|
|
Size::Long => { value },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_address_sized(space: &mut AddressSpace, addr: Address, size: Size) -> Result<u32, Error> {
|
|
|
|
match size {
|
|
|
|
Size::Byte => space.read_u8(addr).map(|value| value as u32),
|
|
|
|
Size::Word => space.read_beu16(addr).map(|value| value as u32),
|
|
|
|
Size::Long => space.read_beu32(addr),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_value_sized(addr: &mut u32, value: u32, size: Size) {
|
|
|
|
match size {
|
|
|
|
Size::Byte => { *addr = (*addr & 0xFFFFFF00) | (0x000000FF & value); }
|
|
|
|
Size::Word => { *addr = (*addr & 0xFFFF0000) | (0x0000FFFF & value); }
|
|
|
|
Size::Long => { *addr = value; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_address_sized(space: &mut AddressSpace, addr: Address, value: u32, size: Size) -> Result<(), Error> {
|
|
|
|
match size {
|
|
|
|
Size::Byte => space.write_u8(addr, value as u8),
|
|
|
|
Size::Word => space.write_beu16(addr, value as u16),
|
|
|
|
Size::Long => space.write_beu32(addr, value),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
fn get_overflow(operand1: u32, operand2: u32, result: u32, size: Size) -> bool {
|
|
|
|
let msb1 = get_msb(operand1, size);
|
|
|
|
let msb2 = get_msb(operand2, size);
|
|
|
|
let msb_res = get_msb(result, size);
|
|
|
|
|
|
|
|
msb1 && msb2 && !msb_res
|
2021-09-30 22:15:23 +00:00
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-01 22:38:21 +00:00
|
|
|
fn get_msb(value: u32, size: Size) -> bool {
|
|
|
|
match size {
|
|
|
|
Size::Byte => (value & 0x00000080) != 0,
|
|
|
|
Size::Word => (value & 0x00008000) != 0,
|
|
|
|
Size::Long => (value & 0x80000000) != 0,
|
|
|
|
}
|
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
|
2021-10-01 22:38:21 +00:00
|
|
|
fn get_msb_mask(value: u32, size: Size) -> u32 {
|
|
|
|
match size {
|
|
|
|
Size::Byte => value & 0x00000080,
|
|
|
|
Size::Word => value & 0x00008000,
|
|
|
|
Size::Long => value & 0x80000000,
|
|
|
|
}
|
2021-09-30 00:11:48 +00:00
|
|
|
}
|
2021-10-01 22:38:21 +00:00
|
|
|
|