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