Thumb 4 - Take care of "neg" case.
I overlooked it :/ Former-commit-id: 360eb755bcf343cddd98807e9faeff007c94cf64
This commit is contained in:
parent
34233fa654
commit
65de0c4e9d
|
@ -3,7 +3,7 @@ use num::FromPrimitive;
|
||||||
|
|
||||||
use super::{Core, CpuError, CpuResult, REG_PC};
|
use super::{Core, CpuError, CpuResult, REG_PC};
|
||||||
|
|
||||||
#[derive(Debug, Primitive)]
|
#[derive(Debug, Primitive, PartialEq)]
|
||||||
pub enum AluOpCode {
|
pub enum AluOpCode {
|
||||||
AND = 0b0000,
|
AND = 0b0000,
|
||||||
EOR = 0b0001,
|
EOR = 0b0001,
|
||||||
|
@ -229,6 +229,26 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_barrel_shifted_value(&mut self, sval: BarrelShifterValue) -> i32 {
|
||||||
|
// TODO decide if error handling or panic here
|
||||||
|
match sval {
|
||||||
|
BarrelShifterValue::ImmediateValue(offset) => offset,
|
||||||
|
BarrelShifterValue::ShiftedRegister {
|
||||||
|
reg,
|
||||||
|
shift,
|
||||||
|
added: Some(added),
|
||||||
|
} => {
|
||||||
|
let abs = self.register_shift(reg, shift).unwrap();
|
||||||
|
if added {
|
||||||
|
abs
|
||||||
|
} else {
|
||||||
|
-abs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("bad barrel shift"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn alu_sub_flags(a: i32, b: i32, carry: &mut bool, overflow: &mut bool) -> i32 {
|
fn alu_sub_flags(a: i32, b: i32, carry: &mut bool, overflow: &mut bool) -> i32 {
|
||||||
let res = a.wrapping_sub(b);
|
let res = a.wrapping_sub(b);
|
||||||
*carry = b <= a;
|
*carry = b <= a;
|
||||||
|
|
|
@ -135,26 +135,6 @@ impl Core {
|
||||||
Ok(pipeline_action)
|
Ok(pipeline_action)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rn_offset(&mut self, sval: BarrelShifterValue) -> i32 {
|
|
||||||
// TODO decide if error handling or panic here
|
|
||||||
match sval {
|
|
||||||
BarrelShifterValue::ImmediateValue(offset) => offset,
|
|
||||||
BarrelShifterValue::ShiftedRegister {
|
|
||||||
reg,
|
|
||||||
shift,
|
|
||||||
added: Some(added),
|
|
||||||
} => {
|
|
||||||
let abs = self.register_shift(reg, shift).unwrap();
|
|
||||||
if added {
|
|
||||||
abs
|
|
||||||
} else {
|
|
||||||
-abs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("bad barrel shift"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Memory Load/Store
|
/// Memory Load/Store
|
||||||
/// Instruction | Cycles | Flags | Expl.
|
/// Instruction | Cycles | Flags | Expl.
|
||||||
/// ------------------------------------------------------------------------------
|
/// ------------------------------------------------------------------------------
|
||||||
|
@ -178,7 +158,7 @@ impl Core {
|
||||||
addr = insn.pc + 8; // prefetching
|
addr = insn.pc + 8; // prefetching
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = self.get_rn_offset(insn.ldr_str_offset());
|
let offset = self.get_barrel_shifted_value(insn.ldr_str_offset());
|
||||||
|
|
||||||
let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
|
let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
|
||||||
addr = if insn.pre_index_flag() {
|
addr = if insn.pre_index_flag() {
|
||||||
|
@ -238,7 +218,7 @@ impl Core {
|
||||||
addr = insn.pc + 8; // prefetching
|
addr = insn.pc + 8; // prefetching
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = self.get_rn_offset(insn.ldr_str_hs_offset().unwrap());
|
let offset = self.get_barrel_shifted_value(insn.ldr_str_hs_offset().unwrap());
|
||||||
|
|
||||||
let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
|
let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
|
||||||
addr = if insn.pre_index_flag() {
|
addr = if insn.pre_index_flag() {
|
||||||
|
|
|
@ -37,9 +37,16 @@ impl ThumbInstruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_thumb_alu_ops(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_thumb_alu_ops(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use ShiftedRegister::ByRegister;
|
||||||
let (op, shft) = self.alu_opcode();
|
let (op, shft) = self.alu_opcode();
|
||||||
if let Some(ShiftedRegister::ByRegister(_, op)) = shft {
|
if let Some(BarrelShifterValue::ShiftedRegister {
|
||||||
|
shift: ByRegister(_, op),
|
||||||
|
..
|
||||||
|
}) = shft
|
||||||
|
{
|
||||||
write!(f, "{}", op)?;
|
write!(f, "{}", op)?;
|
||||||
|
} else if op == AluOpCode::RSB {
|
||||||
|
write!(f, "neg")?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", op)?;
|
write!(f, "{}", op)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,8 +92,7 @@ impl Core {
|
||||||
let (arm_alu_op, shft) = insn.alu_opcode();
|
let (arm_alu_op, shft) = insn.alu_opcode();
|
||||||
let op1 = self.get_reg(rd) as i32;
|
let op1 = self.get_reg(rd) as i32;
|
||||||
let op2 = if let Some(shft) = shft {
|
let op2 = if let Some(shft) = shft {
|
||||||
let bs_result = self.register_shift(rd, shft)?;
|
self.get_barrel_shifted_value(shft)
|
||||||
bs_result
|
|
||||||
} else {
|
} else {
|
||||||
self.get_reg(insn.rs()) as i32
|
self.get_reg(insn.rs()) as i32
|
||||||
};
|
};
|
||||||
|
|
|
@ -242,36 +242,42 @@ impl ThumbInstruction {
|
||||||
OpFormat5::from_u8(self.raw.bit_range(8..10) as u8).unwrap()
|
OpFormat5::from_u8(self.raw.bit_range(8..10) as u8).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alu_opcode(&self) -> (AluOpCode, Option<ShiftedRegister>) {
|
pub fn alu_opcode(&self) -> (AluOpCode, Option<BarrelShifterValue>) {
|
||||||
|
use ShiftedRegister::*;
|
||||||
match self.raw.bit_range(6..10) {
|
match self.raw.bit_range(6..10) {
|
||||||
0b0010 => (
|
0b0010 => (
|
||||||
AluOpCode::MOV,
|
AluOpCode::MOV,
|
||||||
Some(ShiftedRegister::ByRegister(
|
Some(BarrelShifterValue::ShiftedRegister {
|
||||||
self.rs(),
|
reg: self.rd(),
|
||||||
BarrelShiftOpCode::LSL,
|
shift: ByRegister(self.rs(), BarrelShiftOpCode::LSL),
|
||||||
)),
|
added: Some(true),
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
0b0011 => (
|
0b0011 => (
|
||||||
AluOpCode::MOV,
|
AluOpCode::MOV,
|
||||||
Some(ShiftedRegister::ByRegister(
|
Some(BarrelShifterValue::ShiftedRegister {
|
||||||
self.rs(),
|
reg: self.rd(),
|
||||||
BarrelShiftOpCode::LSR,
|
shift: ByRegister(self.rs(), BarrelShiftOpCode::LSR),
|
||||||
)),
|
added: Some(true),
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
0b0100 => (
|
0b0100 => (
|
||||||
AluOpCode::MOV,
|
AluOpCode::MOV,
|
||||||
Some(ShiftedRegister::ByRegister(
|
Some(BarrelShifterValue::ShiftedRegister {
|
||||||
self.rs(),
|
reg: self.rd(),
|
||||||
BarrelShiftOpCode::ASR,
|
shift: ByRegister(self.rs(), BarrelShiftOpCode::ASR),
|
||||||
)),
|
added: Some(true),
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
0b0111 => (
|
0b0111 => (
|
||||||
AluOpCode::MOV,
|
AluOpCode::MOV,
|
||||||
Some(ShiftedRegister::ByRegister(
|
Some(BarrelShifterValue::ShiftedRegister {
|
||||||
self.rs(),
|
reg: self.rd(),
|
||||||
BarrelShiftOpCode::ROR,
|
shift: ByRegister(self.rs(), BarrelShiftOpCode::ROR),
|
||||||
)),
|
added: Some(true),
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
|
0b1001 => (AluOpCode::RSB, Some(BarrelShifterValue::ImmediateValue(0))),
|
||||||
0b1101 => panic!("tried to decode MUL"),
|
0b1101 => panic!("tried to decode MUL"),
|
||||||
op => (AluOpCode::from_u16(op).unwrap(), None),
|
op => (AluOpCode::from_u16(op).unwrap(), None),
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue