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:
parent
2817db4e1c
commit
6c0df33597
|
@ -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)
|
||||
}
|
||||
|
|
Reference in a new issue