Finally got the barrel shifter right?

The barrel shifter sure has lots of edge cases, need to implement tests ASAP


Former-commit-id: 989fc4477f610603154404d0ed4335619ebd6345
This commit is contained in:
Michel Heily 2019-07-08 21:58:30 +03:00
parent 2817db4e1c
commit 6c0df33597

View file

@ -98,7 +98,13 @@ impl BarrelShifterValue {
impl Core {
/// Performs a generic barrel shifter operation
fn barrel_shift(&mut self, val: i32, amount: u32, shift: BarrelShiftOpCode) -> i32 {
fn barrel_shift(
&mut self,
val: i32,
amount: u32,
shift: BarrelShiftOpCode,
immediate: bool,
) -> i32 {
//
// From GBATEK:
// Zero Shift Amount (Shift Register by Immediate, with Immediate=0)
@ -135,24 +141,42 @@ impl Core {
}
},
BarrelShiftOpCode::LSR => match amount {
x if x > 0 && x < 32 => {
0 | 32 => {
if immediate {
self.cpsr.set_C((val as u32).bit(31));
0
} else {
val
}
}
x if x < 32 => {
self.cpsr.set_C(val >> (amount - 1) & 1 == 1);
((val as u32) >> amount) as i32
}
0 | 32 => {
self.cpsr.set_C((val as u32).bit(31));
0
}
_ => {
self.cpsr.set_C(false);
0
}
},
BarrelShiftOpCode::ASR => {
if 0 < amount && amount < 32 {
BarrelShiftOpCode::ASR => match amount {
0 => {
if immediate {
let bit31 = (val as u32).bit(31);
self.cpsr.set_C(bit31);
if bit31 {
-1
} else {
0
}
} else {
val
}
}
x if x < 32 => {
self.cpsr.set_C(val.wrapping_shr(amount - 1) & 1 == 1);
val.wrapping_shr(amount)
} else {
}
_ => {
let bit31 = (val as u32).bit(31);
self.cpsr.set_C(bit31);
if bit31 {
@ -161,24 +185,28 @@ impl Core {
0
}
}
}
},
BarrelShiftOpCode::ROR => {
match amount {
0 =>
/* RRX */
{
let val = val as u32;
let old_c = self.cpsr.C() as u32;
(val.rotate_right(1) | (old_c << 31)) as i32
}
32 => {
self.cpsr.set_C((val as u32).bit(31));
val
0 => {
if immediate {
/* RRX */
self.cpsr.set_C(val & 0b1 != 0);
let old_c = self.cpsr.C() as i32;
((val as u32) >> 1) as i32 | (old_c << 31)
} else {
val
}
}
_ => {
let amount = amount % 32;
self.cpsr.set_C(((val as u32) >> (amount - 1)) & 1 == 1);
val.rotate_right(amount)
let val = if amount != 0 {
val.rotate_right(amount)
} else {
val
};
self.cpsr.set_C((val as u32).bit(31));
val
}
}
}
@ -188,10 +216,12 @@ impl Core {
pub fn register_shift(&mut self, reg: usize, shift: ShiftedRegister) -> CpuResult<i32> {
let val = self.get_reg(reg) as i32;
match shift {
ShiftedRegister::ByAmount(amount, shift) => Ok(self.barrel_shift(val, amount, shift)),
ShiftedRegister::ByAmount(amount, shift) => {
Ok(self.barrel_shift(val, amount, shift, true))
}
ShiftedRegister::ByRegister(reg, shift) => {
if reg != REG_PC {
Ok(self.barrel_shift(val, self.get_reg(reg) & 0xff, shift))
Ok(self.barrel_shift(val, self.get_reg(reg) & 0xff, shift, false))
} else {
Err(CpuError::IllegalInstruction)
}