arm: Implement Arm MSR_FLAGS

Former-commit-id: 64d2cf255304ecca02dadc55266d22bc1f92bb4c
This commit is contained in:
Michel Heily 2019-07-10 22:34:51 +03:00
parent 4c3379615a
commit a9bf2d25e0
3 changed files with 93 additions and 36 deletions

View file

@ -2,7 +2,7 @@ use std::fmt;
use super::{AluOpCode, ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction}; use super::{AluOpCode, ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction};
use crate::arm7tdmi::{ use crate::arm7tdmi::{
reg_string, Addr, BarrelShiftOpCode, BarrelShifterValue, ShiftedRegister, REG_PC, psr::RegPSR, reg_string, Addr, BarrelShiftOpCode, BarrelShifterValue, ShiftedRegister, REG_PC,
}; };
impl fmt::Display for ArmCond { impl fmt::Display for ArmCond {
@ -117,6 +117,26 @@ impl ArmInstruction {
} }
} }
fn fmt_operand2(&self, f: &mut fmt::Formatter) -> Result<Option<u32>, fmt::Error> {
let operand2 = self.operand2().unwrap();
match operand2 {
BarrelShifterValue::RotatedImmediate(_, _) => {
let value = operand2.decode_rotated_immediate().unwrap();
write!(f, "#{}\t; {:#x}", value, value)?;
Ok(Some(value as u32))
}
BarrelShifterValue::ShiftedRegister {
reg,
shift,
added: _,
} => {
write!(f, "{}", self.make_shifted_reg_string(reg, shift))?;
Ok(None)
}
_ => panic!("invalid operand2"),
}
}
fn fmt_data_processing(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_data_processing(&self, f: &mut fmt::Formatter) -> fmt::Result {
use AluOpCode::*; use AluOpCode::*;
@ -149,19 +169,8 @@ impl ArmInstruction {
), ),
}?; }?;
let operand2 = self.operand2().unwrap(); self.fmt_operand2(f).unwrap();
match operand2 { Ok(())
BarrelShifterValue::RotatedImmediate(_, _) => {
let value = operand2.decode_rotated_immediate().unwrap();
write!(f, "#{}\t; {:#x}", value, value)
}
BarrelShifterValue::ShiftedRegister {
reg,
shift,
added: _,
} => write!(f, "{}", self.make_shifted_reg_string(reg, shift)),
_ => write!(f, "RegisterNotImpl"),
}
} }
fn auto_incremenet_mark(&self) -> &str { fn auto_incremenet_mark(&self) -> &str {
@ -284,6 +293,27 @@ impl ArmInstruction {
) )
} }
fn fmt_msr_flags(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"msr{cond}\t{psr}, ",
cond = self.cond,
psr = if self.spsr_flag() { "SPSR_f" } else { "CPSR_f" },
)?;
if let Ok(Some(op)) = self.fmt_operand2(f) {
let psr = RegPSR::new(op & 0xf000_0000);
write!(
f,
"\t; N={} Z={} C={} V={}",
psr.N(),
psr.Z(),
psr.C(),
psr.V()
)?;
}
Ok(())
}
fn fmt_mul_mla(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_mul_mla(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.accumulate_flag() { if self.accumulate_flag() {
write!( write!(
@ -381,6 +411,7 @@ impl fmt::Display for ArmInstruction {
LDM_STM => self.fmt_ldm_stm(f), LDM_STM => self.fmt_ldm_stm(f),
MRS => self.fmt_mrs(f), MRS => self.fmt_mrs(f),
MSR_REG => self.fmt_msr_reg(f), MSR_REG => self.fmt_msr_reg(f),
MSR_FLAGS => self.fmt_msr_flags(f),
MUL_MLA => self.fmt_mul_mla(f), MUL_MLA => self.fmt_mul_mla(f),
MULL_MLAL => self.fmt_mull_mlal(f), MULL_MLAL => self.fmt_mull_mlal(f),
LDR_STR_HS_IMM => self.fmt_ldr_str_hs(f), LDR_STR_HS_IMM => self.fmt_ldr_str_hs(f),

View file

@ -24,6 +24,7 @@ impl Core {
ArmFormat::LDR_STR_HS_REG => self.exec_ldr_str_hs(bus, insn), ArmFormat::LDR_STR_HS_REG => self.exec_ldr_str_hs(bus, insn),
ArmFormat::LDM_STM => self.exec_ldm_stm(bus, insn), ArmFormat::LDM_STM => self.exec_ldm_stm(bus, insn),
ArmFormat::MSR_REG => self.exec_msr_reg(bus, insn), ArmFormat::MSR_REG => self.exec_msr_reg(bus, insn),
ArmFormat::MSR_FLAGS => self.exec_msr_flags(bus, insn),
ArmFormat::MUL_MLA => self.exec_mul_mla(bus, insn), ArmFormat::MUL_MLA => self.exec_mul_mla(bus, insn),
_ => Err(CpuError::UnimplementedCpuInstruction( _ => Err(CpuError::UnimplementedCpuInstruction(
insn.pc, insn.pc,
@ -90,15 +91,49 @@ impl Core {
Ok(CpuPipelineAction::IncPC) Ok(CpuPipelineAction::IncPC)
} }
/// Logical/Arithmetic ALU operations fn exec_msr_flags(
///
/// Cycles: 1S+x+y (from GBATEK)
/// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15.
fn exec_data_processing(
&mut self, &mut self,
_bus: &mut Bus, _bus: &mut Bus,
insn: ArmInstruction, insn: ArmInstruction,
) -> CpuResult<CpuPipelineAction> { ) -> CpuResult<CpuPipelineAction> {
let op = insn.operand2()?;
let op = self.decode_operand2(op)?;
let old_mode = self.cpsr.mode();
if insn.spsr_flag() {
if let Some(index) = old_mode.spsr_index() {
self.spsr[index].set_flag_bits(op);
} else {
panic!("tried to change spsr from invalid mode {}", old_mode)
}
} else {
self.cpsr.set_flag_bits(op);
}
Ok(CpuPipelineAction::IncPC)
}
fn decode_operand2(&mut self, op2: BarrelShifterValue) -> CpuResult<u32> {
match op2 {
BarrelShifterValue::RotatedImmediate(imm, r) => Ok(imm.rotate_right(r)),
BarrelShifterValue::ShiftedRegister {
reg,
shift,
added: _,
} => {
// +1I
self.add_cycle();
let result = self.register_shift(reg, shift)?;
Ok(result as u32)
}
_ => unreachable!(),
}
}
/// Logical/Arithmetic ALU operations
///
/// Cycles: 1S+x+y (from GBATEK)
/// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15.
fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
// TODO handle carry flag // TODO handle carry flag
let mut pipeline_action = CpuPipelineAction::IncPC; let mut pipeline_action = CpuPipelineAction::IncPC;
@ -109,26 +144,10 @@ impl Core {
self.get_reg(insn.rn()) as i32 self.get_reg(insn.rn()) as i32
}; };
let op2 = insn.operand2()?; let op2 = insn.operand2()?;
let op2 = self.decode_operand2(op2)? as i32;
let rd = insn.rd(); let rd = insn.rd();
let op2: i32 = match op2 {
BarrelShifterValue::RotatedImmediate(immediate, rotate) => {
immediate.rotate_right(rotate) as i32
}
BarrelShifterValue::ShiftedRegister {
reg,
shift,
added: _,
} => {
// +1I
self.add_cycle();
let result = self.register_shift(reg, shift)?;
result
}
_ => unreachable!(),
};
let opcode = insn.opcode().unwrap(); let opcode = insn.opcode().unwrap();
let set_flags = opcode.is_setting_flags() || insn.set_cond_flag(); let set_flags = opcode.is_setting_flags() || insn.set_cond_flag();
if let Some(result) = self.alu(opcode, op1, op2, set_flags) { if let Some(result) = self.alu(opcode, op1, op2, set_flags) {

View file

@ -45,6 +45,8 @@ impl Default for RegPSR {
} }
} }
impl RegPSR { impl RegPSR {
pub const FLAG_BITMASK: u32 = 0xf000_0000;
pub fn new(u: u32) -> RegPSR { pub fn new(u: u32) -> RegPSR {
RegPSR { RegPSR {
raw: clear_reserved(u), raw: clear_reserved(u),
@ -59,6 +61,11 @@ impl RegPSR {
self.raw = clear_reserved(psr); self.raw = clear_reserved(psr);
} }
pub fn set_flag_bits(&mut self, value: u32) {
self.raw &= !Self::FLAG_BITMASK;
self.raw |= Self::FLAG_BITMASK & value;
}
pub fn state(&self) -> CpuState { pub fn state(&self) -> CpuState {
self.raw.bit(5).into() self.raw.bit(5).into()
} }