use crate::core::cpu::{CFLAG_SET, CpuCore, VFLAG_SET};
use crate::core::ea::AddressingMode;
use crate::core::execute::RUN_MODE_BERR_AERR_RESET;
use crate::core::memory::AddressBus;
use crate::core::types::Size;
impl CpuCore {
pub fn exec_add<B: AddressBus>(
&mut self,
_bus: &mut B,
size: Size,
src: u32,
dst: u32,
) -> (u32, i32) {
let result = src.wrapping_add(dst);
self.set_add_flags(src, dst, result, size);
(result & size.mask(), 4)
}
pub fn exec_adda<B: AddressBus>(
&mut self,
_bus: &mut B,
size: Size,
src: u32,
dst_reg: usize,
) -> i32 {
let src = if size == Size::Word {
src as i16 as i32 as u32
} else {
src
};
let dst = self.a(dst_reg);
self.set_a(dst_reg, dst.wrapping_add(src));
8
}
pub fn exec_addq<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
data: u32,
mode: AddressingMode,
) -> i32 {
if let AddressingMode::AddressDirect(reg) = mode {
let reg = reg as usize;
self.set_a(reg, self.a(reg).wrapping_add(data));
return 4;
}
let ea = self.resolve_ea(bus, mode, size);
let dst = self.read_resolved_ea(bus, ea, size);
let (result, _) = self.exec_add::<B>(bus, size, data, dst);
self.write_resolved_ea(bus, ea, size, result);
4
}
pub fn exec_addx(&mut self, size: Size, src: u32, dst: u32) -> u32 {
let mask = size.mask();
let msb = size.msb_mask();
let extend = if self.x_flag != 0 { 1u64 } else { 0u64 };
let d = (dst & mask) as u64;
let s = (src & mask) as u64;
let sum = d + s + extend;
let r = (sum as u32) & mask;
self.n_flag = if (r & msb) != 0 { 0x80 } else { 0 };
if r != 0 {
self.not_z_flag = r;
}
let v = (src ^ r) & (dst ^ r) & msb;
self.v_flag = if v != 0 { VFLAG_SET } else { 0 };
let carry = sum > (mask as u64);
self.c_flag = if carry { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
r
}
pub fn exec_sub<B: AddressBus>(
&mut self,
_bus: &mut B,
size: Size,
src: u32,
dst: u32,
) -> (u32, i32) {
let result = dst.wrapping_sub(src);
self.set_sub_flags(src, dst, result, size);
(result & size.mask(), 4)
}
pub fn exec_suba<B: AddressBus>(
&mut self,
_bus: &mut B,
size: Size,
src: u32,
dst_reg: usize,
) -> i32 {
let src = if size == Size::Word {
src as i16 as i32 as u32
} else {
src
};
let dst = self.a(dst_reg);
self.set_a(dst_reg, dst.wrapping_sub(src));
8
}
pub fn exec_subq<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
data: u32,
mode: AddressingMode,
) -> i32 {
if let AddressingMode::AddressDirect(reg) = mode {
let reg = reg as usize;
self.set_a(reg, self.a(reg).wrapping_sub(data));
return 4;
}
let ea = self.resolve_ea(bus, mode, size);
let dst = self.read_resolved_ea(bus, ea, size);
let (result, _) = self.exec_sub::<B>(bus, size, data, dst);
self.write_resolved_ea(bus, ea, size, result);
4
}
pub fn exec_subx(&mut self, size: Size, src: u32, dst: u32) -> u32 {
let mask = size.mask();
let msb = size.msb_mask();
let extend = if self.x_flag != 0 { 1u64 } else { 0u64 };
let d = (dst & mask) as u64;
let s = (src & mask) as u64;
let sub = s + extend; let r = ((d.wrapping_sub(sub)) as u32) & mask;
self.n_flag = if (r & msb) != 0 { 0x80 } else { 0 };
if r != 0 {
self.not_z_flag = r;
}
let src_masked = src & mask;
let dst_masked = dst & mask;
self.v_flag = if ((src_masked ^ dst_masked) & (r ^ dst_masked) & msb) != 0 {
VFLAG_SET
} else {
0
};
let borrow = sub > d;
self.c_flag = if borrow { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
r
}
pub fn exec_cmp(&mut self, size: Size, src: u32, dst: u32) -> i32 {
let result = dst.wrapping_sub(src);
self.set_cmp_flags(src, dst, result, size);
4
}
pub fn exec_cmpa(&mut self, size: Size, src: u32, dst_reg: usize) -> i32 {
let src = if size == Size::Word {
src as i16 as i32 as u32
} else {
src
};
let dst = self.a(dst_reg);
let result = dst.wrapping_sub(src);
self.set_cmp_flags(src, dst, result, Size::Long);
6
}
pub fn exec_clr<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
mode: AddressingMode,
) -> i32 {
let ea = self.resolve_ea(bus, mode, size);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
self.write_resolved_ea(bus, ea, size, 0);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
self.n_flag = 0;
self.not_z_flag = 0;
self.v_flag = 0;
self.c_flag = 0;
4
}
pub fn exec_neg<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
mode: AddressingMode,
) -> i32 {
let ea = self.resolve_ea(bus, mode, size);
let src = self.read_resolved_ea(bus, ea, size);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
let result = 0u32.wrapping_sub(src);
self.write_resolved_ea(bus, ea, size, result & size.mask());
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
self.set_sub_flags(src, 0, result, size);
4
}
pub fn exec_negx<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
mode: AddressingMode,
) -> i32 {
let ea = self.resolve_ea(bus, mode, size);
let src = self.read_resolved_ea(bus, ea, size);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
let result = self.exec_subx(size, src, 0);
self.write_resolved_ea(bus, ea, size, result);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
4
}
pub fn exec_not<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
mode: AddressingMode,
) -> i32 {
let ea = self.resolve_ea(bus, mode, size);
let src = self.read_resolved_ea(bus, ea, size);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
let result = !src & size.mask();
self.write_resolved_ea(bus, ea, size, result);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
self.set_logic_flags(result, size);
4
}
pub fn exec_ext(&mut self, size: Size, reg: usize) -> i32 {
let value = self.d(reg);
let result = match size {
Size::Word => (value as i8 as i16 as u16) as u32 | (value & 0xFFFF0000),
Size::Long => value as i16 as i32 as u32,
Size::Byte => value, };
self.set_d(reg, result);
self.set_logic_flags(result, size);
4
}
pub fn exec_extb(&mut self, reg: usize) -> i32 {
let value = self.d(reg);
let result = value as i8 as i32 as u32;
self.set_d(reg, result);
self.set_logic_flags(result, Size::Long);
4
}
pub fn exec_tst<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
mode: AddressingMode,
) -> i32 {
let ea = self.resolve_ea(bus, mode, size);
let value = self.read_resolved_ea(bus, ea, size);
if self.run_mode == RUN_MODE_BERR_AERR_RESET {
return 50;
}
self.set_logic_flags(value, size);
4
}
pub fn set_add_flags(&mut self, src: u32, dst: u32, result: u32, size: Size) {
let msb = size.msb_mask();
let mask = size.mask();
self.n_flag = if result & msb != 0 { 0x80 } else { 0 };
self.not_z_flag = result & mask;
let v = (src ^ result) & (dst ^ result) & msb;
self.v_flag = if v != 0 { 0x80 } else { 0 };
let carry = match size {
Size::Byte => result & 0x100 != 0,
Size::Word => result & 0x10000 != 0,
Size::Long => {
let s = src;
let d = dst;
let r = result;
((s & d) | (!r & (s | d))) & 0x80000000 != 0
}
};
self.c_flag = if carry { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
}
#[allow(dead_code)]
fn set_addx_flags(&mut self, src: u32, dst: u32, result: u32, size: Size) {
let msb = size.msb_mask();
let mask = size.mask();
let r = result & mask;
let s = src & mask;
let d = dst & mask;
self.n_flag = if r & msb != 0 { 0x80 } else { 0 };
if r != 0 {
self.not_z_flag = r;
}
let overflow = ((s ^ r) & (d ^ r) & msb) != 0;
self.v_flag = if overflow { VFLAG_SET } else { 0 };
let carry = match size {
Size::Byte => result & 0x100 != 0,
Size::Word => result & 0x10000 != 0,
Size::Long => {
((s & d) | (!r & (s | d))) & 0x80000000 != 0
}
};
self.c_flag = if carry { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
}
pub fn set_sub_flags(&mut self, src: u32, dst: u32, result: u32, size: Size) {
let msb = size.msb_mask();
let mask = size.mask();
let r = result & mask;
let s = src & mask;
let d = dst & mask;
self.n_flag = if r & msb != 0 { 0x80 } else { 0 };
self.not_z_flag = r;
let v = (s ^ d) & (r ^ d) & msb;
self.v_flag = if v != 0 { 0x80 } else { 0 };
let carry = match size {
Size::Byte => s > d,
Size::Word => s > d,
Size::Long => {
((s & r) | (!d & (s | r))) & 0x80000000 != 0
}
};
self.c_flag = if carry { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
}
fn set_cmp_flags(&mut self, src: u32, dst: u32, result: u32, size: Size) {
let msb = size.msb_mask();
let mask = size.mask();
let r = result & mask;
let s = src & mask;
let d = dst & mask;
self.n_flag = if r & msb != 0 { 0x80 } else { 0 };
self.not_z_flag = r;
let overflow = ((s ^ d) & (r ^ d) & msb) != 0;
self.v_flag = if overflow { VFLAG_SET } else { 0 };
let carry = s > d;
self.c_flag = if carry { CFLAG_SET } else { 0 };
}
#[allow(dead_code)]
fn set_subx_flags(&mut self, src: u32, dst: u32, result: u32, size: Size) {
let msb = size.msb_mask();
let mask = size.mask();
let r = result & mask;
let s = src & mask;
let d = dst & mask;
self.n_flag = if r & msb != 0 { 0x80 } else { 0 };
if r != 0 {
self.not_z_flag = r;
}
let overflow = ((s ^ d) & (r ^ d) & msb) != 0;
self.v_flag = if overflow { VFLAG_SET } else { 0 };
let carry = match size {
Size::Byte => s > d,
Size::Word => s > d,
Size::Long => {
((s & r) | (!d & (s | r))) & 0x80000000 != 0
}
};
self.c_flag = if carry { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
}
pub fn exec_chk<B: AddressBus>(
&mut self,
bus: &mut B,
size: Size,
bound: u32,
reg: usize,
) -> i32 {
let (val, limit) = match size {
Size::Word => (self.d(reg) as i16 as i32, bound as i16 as i32),
Size::Long => (self.d(reg) as i32, bound as i32),
Size::Byte => (self.d(reg) as i8 as i32, bound as i8 as i32),
};
self.n_flag = if val < 0 { 0x80 } else { 0 };
self.not_z_flag = 1; self.v_flag = 0;
self.c_flag = 0;
if val < 0 || val > limit {
return self.exception_chk(bus);
}
10
}
}