use crate::core::cpu::{CFLAG_SET, CpuCore};
use crate::core::types::{CpuType, Size};
impl CpuCore {
#[inline]
fn shift_reg_cycles(&self, size: Size, count: u32) -> i32 {
if !matches!(self.cpu_type, CpuType::M68000 | CpuType::M68010) {
return 6;
}
let base = if size == Size::Long { 8 } else { 6 };
base + 2 * count as i32
}
pub fn exec_asl(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let shift = shift & 63;
if shift == 0 {
self.c_flag = 0;
self.set_logic_flags(value, size);
return (value, self.shift_reg_cycles(size, 0));
}
let mask = size.mask();
let msb = size.msb_mask();
let bits = size.bits();
let mut result = value & mask;
let mut last_bit = 0u32;
let mut overflow = false;
for _ in 0..shift.min(bits as u32) {
last_bit = result & msb;
let new_top = (result << 1) & msb;
if new_top != last_bit {
overflow = true;
}
result = (result << 1) & mask;
}
self.c_flag = if shift > bits as u32 {
0
} else if last_bit != 0 {
CFLAG_SET
} else {
0
};
self.x_flag = self.c_flag;
self.v_flag = if overflow { 0x80 } else { 0 };
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, shift))
}
pub fn exec_asr(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let shift = shift & 63;
if shift == 0 {
self.c_flag = 0;
self.set_logic_flags(value, size);
return (value, self.shift_reg_cycles(size, 0));
}
let mask = size.mask();
let msb = size.msb_mask();
let bits = size.bits();
let sign = value & msb;
let value = value & mask;
let result = if shift >= bits as u32 {
if sign != 0 { mask } else { 0 }
} else if sign != 0 {
(value >> shift) | (mask << (bits as u32 - shift))
} else {
value >> shift
} & mask;
let last_bit = if shift >= bits as u32 {
sign
} else {
value & (1u32 << (shift - 1))
};
self.c_flag = if last_bit != 0 { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
self.v_flag = 0; self.set_logic_flags_nv(result, size);
(result & mask, self.shift_reg_cycles(size, shift))
}
pub fn exec_lsl(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let shift = shift & 63;
if shift == 0 {
self.c_flag = 0;
self.set_logic_flags(value, size);
return (value, self.shift_reg_cycles(size, 0));
}
let mask = size.mask();
let bits = size.bits();
let result = if shift >= bits as u32 {
self.c_flag = if shift == bits as u32 && (value & 1) != 0 {
CFLAG_SET
} else {
0
};
0
} else {
let last_out = (value >> (bits as u32 - shift)) & 1;
self.c_flag = if last_out != 0 { CFLAG_SET } else { 0 };
(value << shift) & mask
};
self.x_flag = self.c_flag;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, shift))
}
pub fn exec_lsr(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let shift = shift & 63;
if shift == 0 {
self.c_flag = 0;
self.set_logic_flags(value, size);
return (value, self.shift_reg_cycles(size, 0));
}
let mask = size.mask();
let bits = size.bits();
let value = value & mask;
let result = if shift >= bits as u32 {
self.c_flag = if shift == bits as u32 && (value & size.msb_mask()) != 0 {
CFLAG_SET
} else {
0
};
0
} else {
let last_out = (value >> (shift - 1)) & 1;
self.c_flag = if last_out != 0 { CFLAG_SET } else { 0 };
value >> shift
};
self.x_flag = self.c_flag;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, shift))
}
pub fn exec_rol(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let bits = size.bits() as u32;
let mask = size.mask();
let cnt = shift & 63;
if cnt == 0 {
let result = value & mask;
self.c_flag = 0;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
return (result, self.shift_reg_cycles(size, 0));
}
let mut steps = cnt % bits;
if steps == 0 {
steps = bits;
}
let value = value & mask;
let carry = (value >> (bits - steps)) & 1;
let result = if steps == bits {
value
} else {
((value << steps) | (value >> (bits - steps))) & mask
};
self.c_flag = if carry != 0 { CFLAG_SET } else { 0 };
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, cnt))
}
pub fn exec_ror(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let bits = size.bits() as u32;
let mask = size.mask();
let cnt = shift & 63;
if cnt == 0 {
let result = value & mask;
self.c_flag = 0;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
return (result, self.shift_reg_cycles(size, 0));
}
let mut steps = cnt % bits;
if steps == 0 {
steps = bits;
}
let value = value & mask;
let carry = (value >> (steps - 1)) & 1;
let result = if steps == bits {
value
} else {
((value >> steps) | (value << (bits - steps))) & mask
};
self.c_flag = if carry != 0 { CFLAG_SET } else { 0 };
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, cnt))
}
pub fn exec_roxl(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let bits = size.bits() as u32;
let mask = size.mask();
let count = shift;
let steps = shift % (bits + 1);
if steps == 0 {
let result = value & mask;
self.c_flag = self.x_flag;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
return (result, self.shift_reg_cycles(size, count));
}
let mut result = value & mask;
let mut x = if self.x_flag != 0 { 1u32 } else { 0 };
for _ in 0..steps {
let carry = (result >> (bits - 1)) & 1;
result = ((result << 1) | x) & mask;
x = carry;
}
self.c_flag = if x != 0 { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, count))
}
pub fn exec_roxr(&mut self, size: Size, shift: u32, value: u32) -> (u32, i32) {
let bits = size.bits() as u32;
let mask = size.mask();
let msb = size.msb_mask();
let count = shift;
let steps = shift % (bits + 1);
if steps == 0 {
let result = value & mask;
self.c_flag = self.x_flag;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
return (result, self.shift_reg_cycles(size, count));
}
let mut result = value & mask;
let mut x = if self.x_flag != 0 { 1u32 } else { 0 };
for _ in 0..steps {
let carry = result & 1;
result = (result >> 1) | (if x != 0 { msb } else { 0 });
x = carry;
}
self.c_flag = if x != 0 { CFLAG_SET } else { 0 };
self.x_flag = self.c_flag;
self.v_flag = 0;
self.set_logic_flags_nv(result, size);
(result, self.shift_reg_cycles(size, count))
}
fn set_logic_flags_nv(&mut self, value: u32, size: Size) {
let msb = size.msb_mask();
self.n_flag = if value & msb != 0 { 0x80 } else { 0 };
self.not_z_flag = value & size.mask();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::types::CpuType;
#[test]
fn m68010_long_register_shift_uses_pre_68020_timing() {
let mut cpu = CpuCore::new();
cpu.set_cpu_type(CpuType::M68010);
let (_, cycles) = cpu.exec_lsl(Size::Long, 8, 0x0000_0001);
assert_eq!(cycles, 24);
}
#[test]
fn m68020_register_shift_uses_barrel_shifter_timing() {
let mut cpu = CpuCore::new();
cpu.set_cpu_type(CpuType::M68020);
let (_, cycles) = cpu.exec_lsl(Size::Long, 8, 0x0000_0001);
assert_eq!(cycles, 6);
}
}