Skip to content

Commit f9017fa

Browse files
committed
Set thumb bit in cpsr when block linking
1 parent 8b15572 commit f9017fa

File tree

10 files changed

+80
-30
lines changed

10 files changed

+80
-30
lines changed

src/core/graphics/gpu_renderer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl GpuRenderer {
150150
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
151151
gl::Viewport(0, 0, PRESENTER_SCREEN_WIDTH as _, PRESENTER_SCREEN_HEIGHT as _);
152152

153-
let fps = fps.load(Ordering::Relaxed);
153+
let fps = fps.load(Ordering::Relaxed) as u32;
154154
let per = fps * 100 / 60;
155155

156156
let last_time_saved = *last_save_time.lock().unwrap();

src/core/thread_regs.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,8 @@ impl ThreadRegs {
365365
self.cpu.check_for_interrupt(cycle_manager);
366366
}
367367

368-
pub fn set_thumb(&mut self, enable: bool) {
369-
let mut cpsr = Cpsr::from(self.cpsr);
370-
cpsr.set_thumb(enable);
371-
self.cpsr = u32::from(cpsr);
368+
pub fn set_thumb(&mut self, thumb: bool) {
369+
self.cpsr = (self.cpsr & !(1 << 5)) | ((thumb as u32) << 5);
372370
}
373371

374372
pub fn is_thumb(&self) -> bool {

src/jit/assembler/arm/alu_assembler.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,33 @@ impl Bfc {
563563
}
564564
}
565565

566+
#[bitsize(32)]
567+
#[derive(FromBits)]
568+
pub struct Bfi {
569+
rn: u4,
570+
id: u3,
571+
lsb: u5,
572+
rd: u4,
573+
msb: u5,
574+
id2: u7,
575+
cond: u4,
576+
}
577+
578+
impl Bfi {
579+
#[inline]
580+
pub fn create(rd: Reg, rn: Reg, lsb: u8, width: u8, cond: Cond) -> u32 {
581+
u32::from(Bfi::new(
582+
u4::new(rn as u8),
583+
u3::new(0b001),
584+
u5::new(lsb),
585+
u4::new(rd as u8),
586+
u5::new(lsb + width - 1),
587+
u7::new(0b0111110),
588+
u4::new(cond as u8),
589+
))
590+
}
591+
}
592+
566593
// TODO Add const asserts once const features has been added back to rust
567594
// https://github.com/rust-lang/rust/issues/110395
568595
//const_assert_eq!(lookup_opcode(Self::add(0, 0, 0, 0)).0 as u8, And as u8);

src/jit/assembler/block_asm.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,14 @@ impl<'a> BlockAsm<'a> {
318318
self.insert_inst(BlockInst::Bfc { operand: operand.into(), lsb, width })
319319
}
320320

321+
pub fn bfi(&mut self, op0: impl Into<BlockReg>, op1: impl Into<BlockReg>, lsb: u8, width: u8) {
322+
self.insert_inst(BlockInst::Bfi {
323+
operands: [op0.into(), op1.into()],
324+
lsb,
325+
width,
326+
})
327+
}
328+
321329
pub fn muls_guest_thumb_pc_aligned(&mut self, op0: impl Into<BlockReg>, op1: impl Into<BlockReg>, op2: impl Into<BlockOperandShift>) {
322330
self.insert_inst(BlockInst::Mul {
323331
operands: [op0.into().into(), op1.into().into(), op2.into()],

src/jit/assembler/block_inst.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::jit::assembler::arm::alu_assembler::{AluImm, AluReg, AluShiftImm, Bfc, MulReg};
1+
use crate::jit::assembler::arm::alu_assembler::{AluImm, AluReg, AluShiftImm, Bfc, Bfi, MulReg};
22
use crate::jit::assembler::arm::branch_assembler::Bx;
33
use crate::jit::assembler::arm::transfer_assembler::{LdmStm, LdrStrImm, LdrStrImmSBHD, LdrStrReg, LdrStrRegSBHD, Mrs, Msr};
44
use crate::jit::assembler::arm::Bkpt;
@@ -124,6 +124,7 @@ impl BlockInst {
124124
BlockSystemRegOp::Msr => (block_reg_set!(operand.try_as_reg()), block_reg_set!()),
125125
},
126126
BlockInst::Bfc { operand, .. } => (block_reg_set!(Some(*operand)), block_reg_set!(Some(*operand))),
127+
BlockInst::Bfi { operands, .. } => (block_reg_set!(Some(operands[0]), Some(operands[1])), block_reg_set!(Some(operands[0]))),
127128

128129
BlockInst::SaveContext { .. } => (block_reg_set!(), block_reg_set!()),
129130
BlockInst::SaveReg {
@@ -250,6 +251,10 @@ impl BlockInst {
250251
}
251252
}
252253
BlockInst::Bfc { operand, .. } => Self::replace_reg(operand, old, new),
254+
BlockInst::Bfi { operands, .. } => {
255+
Self::replace_reg(&mut operands[0], old, new);
256+
Self::replace_reg(&mut operands[1], old, new);
257+
}
253258
BlockInst::SaveContext { .. } => {
254259
unreachable!()
255260
}
@@ -296,6 +301,7 @@ impl BlockInst {
296301
}
297302
}
298303
BlockInst::Bfc { operand, .. } => Self::replace_reg(operand, old, new),
304+
BlockInst::Bfi { operands, .. } => Self::replace_reg(&mut operands[0], old, new),
299305
BlockInst::SaveContext { tmp_guest_cpsr_reg, .. } => Self::replace_reg(tmp_guest_cpsr_reg, old, new),
300306
BlockInst::SaveReg {
301307
guest_reg,
@@ -338,6 +344,10 @@ impl BlockInst {
338344
BlockInst::TransferMultiple { operand, .. } => Self::replace_reg(operand, old, new),
339345
BlockInst::SystemReg { operand, .. } => Self::replace_operand(operand, old, new),
340346
BlockInst::Bfc { operand, .. } => Self::replace_reg(operand, old, new),
347+
BlockInst::Bfi { operands, .. } => {
348+
Self::replace_reg(&mut operands[0], old, new);
349+
Self::replace_reg(&mut operands[1], old, new);
350+
}
341351

342352
BlockInst::SaveContext { .. } => {
343353
unreachable!()
@@ -518,6 +528,7 @@ impl BlockInst {
518528
BlockSystemRegOp::Msr => opcodes.push(Msr::cpsr_flags(operand.as_reg().as_fixed(), Cond::AL)),
519529
},
520530
BlockInst::Bfc { operand, lsb, width } => opcodes.push(Bfc::create(operand.as_fixed(), *lsb, *width, Cond::AL)),
531+
BlockInst::Bfi { operands, lsb, width } => opcodes.push(Bfi::create(operands[0].as_fixed(), operands[1].as_fixed(), *lsb, *width, Cond::AL)),
521532
BlockInst::Mul { operands, set_cond, .. } => match operands[2].operand {
522533
BlockOperand::Reg(reg) => opcodes.push(MulReg::mul(
523534
operands[0].as_reg().as_fixed(),
@@ -686,6 +697,11 @@ pub enum BlockInst {
686697
lsb: u8,
687698
width: u8,
688699
},
700+
Bfi {
701+
operands: [BlockReg; 2],
702+
lsb: u8,
703+
width: u8,
704+
},
689705
Mul {
690706
operands: [BlockOperandShift; 3],
691707
set_cond: BlockAluSetCond,
@@ -789,6 +805,7 @@ impl Debug for BlockInst {
789805
}
790806
BlockInst::SystemReg { op, operand } => write!(f, "{op:?} {operand:?}"),
791807
BlockInst::Bfc { operand, lsb, width } => write!(f, "Bfc {operand:?}, {lsb}, {width}"),
808+
BlockInst::Bfi { operands, lsb, width } => write!(f, "Bfi {:?}, {:?}, {lsb}, {width}", operands[0], operands[1]),
792809
BlockInst::Mul { operands, set_cond, thumb_pc_aligned } => write!(f, "Mul{set_cond:?} {operands:?}, align pc: {thumb_pc_aligned}"),
793810
BlockInst::Label { label, guest_pc } => {
794811
let guest_pc = match guest_pc {

src/jit/emitter/emit_branch.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,27 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
184184
asm.emit_return_stack_write(block_asm, runtime_data_addr_reg);
185185
}
186186

187+
let cpsr_reg = block_asm.new_reg();
188+
let addr_mask_reg = block_asm.new_reg();
189+
190+
// Set thumb bit
191+
block_asm.transfer_read(cpsr_reg, block_asm.thread_regs_addr_reg, Reg::CPSR as u32 * 4, false, MemoryAmount::Word);
192+
block_asm.bfi(cpsr_reg, target_pc_reg, 5, 1);
193+
block_asm.transfer_write(cpsr_reg, block_asm.thread_regs_addr_reg, Reg::CPSR as u32 * 4, false, MemoryAmount::Word);
194+
195+
block_asm.free_reg(cpsr_reg);
196+
187197
let target_addr_reg = block_asm.new_reg();
188-
let pc_mask_reg = block_asm.new_reg();
189198

190199
// Align pc to !1 or !3
191-
block_asm.mvn(pc_mask_reg, 1);
192-
block_asm.tst(target_pc_reg, 1);
193-
block_asm.start_cond_block(Cond::EQ);
194-
block_asm.mvn(pc_mask_reg, 3);
195-
block_asm.end_cond_block();
200+
// let thumb = (target_pc & 1) == 1;
201+
// let addr_mask = !(1 | ((!thumb as u32) << 1));
202+
// let target_addr = target_pc & addr_mask;
203+
block_asm.mvn(addr_mask_reg, 3);
204+
block_asm.orr(addr_mask_reg, addr_mask_reg, (target_pc_reg.into(), ShiftType::Lsl, BlockOperand::from(1)));
205+
block_asm.and(target_addr_reg, target_pc_reg, addr_mask_reg);
196206

197-
block_asm.and(target_addr_reg, target_pc_reg, pc_mask_reg);
207+
block_asm.free_reg(addr_mask_reg);
198208

199209
let map_ptr = get_jit!(asm.emu).jit_memory_map.get_map_ptr::<CPU>();
200210

@@ -228,7 +238,6 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
228238
block_asm.free_reg(map_entry_base_ptr_reg);
229239
block_asm.free_reg(map_index_reg);
230240
block_asm.free_reg(map_ptr_reg);
231-
block_asm.free_reg(pc_mask_reg);
232241
block_asm.free_reg(target_addr_reg);
233242
},
234243
|asm, block_asm| {

src/jit/emitter/thumb/emit_branch_thumb.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,11 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
3636
block_asm.end_cond_block();
3737
}
3838

39-
pub fn emit_bl_setup_thumb(&mut self) {
40-
let next_inst_info = &self.jit_buf.insts[self.jit_buf.current_index + 1];
41-
assert!(next_inst_info.op == Op::BlOffT || next_inst_info.op == Op::BlxOffT)
42-
}
43-
4439
pub fn emit_bl_thumb(&mut self, block_asm: &mut BlockAsm) {
4540
let previous_inst_info = &self.jit_buf.insts[self.jit_buf.current_index - 1];
46-
assert_eq!(previous_inst_info.op, Op::BlSetupT);
41+
if previous_inst_info.op != Op::BlSetupT {
42+
return;
43+
}
4744

4845
let relative_pc = *previous_inst_info.operands()[0].as_imm().unwrap() as i32 + 4;
4946
let mut target_pc = (self.jit_buf.current_pc as i32 - 2 + relative_pc) as u32;

src/jit/emitter/thumb/emit_thumb.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
4949
Op::BT | Op::BeqT | Op::BneT | Op::BcsT | Op::BccT | Op::BmiT | Op::BplT | Op::BvsT | Op::BvcT | Op::BhiT | Op::BlsT | Op::BgeT | Op::BltT | Op::BgtT | Op::BleT => {
5050
self.emit_b_thumb(block_asm)
5151
}
52-
Op::BlSetupT => self.emit_bl_setup_thumb(),
52+
Op::BlSetupT => {}
5353
Op::BlOffT | Op::BlxOffT => self.emit_bl_thumb(block_asm),
5454
Op::BxRegT => self.emit_bx_thumb(block_asm),
5555
Op::BlxRegT => self.emit_blx_thumb(block_asm),

src/jit/jit_asm.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@ fn emit_code_block_internal<const CPU: CpuType, const THUMB: bool>(store_host_sp
238238
jit_entry(store_host_sp);
239239
}
240240

241-
#[inline]
242241
fn execute_internal<const CPU: CpuType>(guest_pc: u32) -> u16 {
243242
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut().unwrap_unchecked() };
244243

@@ -248,7 +247,8 @@ fn execute_internal<const CPU: CpuType>(guest_pc: u32) -> u16 {
248247
let jit_entry = {
249248
get_regs_mut!(asm.emu, CPU).set_thumb(thumb);
250249

251-
let guest_pc = if thumb { guest_pc & !1 } else { guest_pc & !3 };
250+
let guest_pc_mask = !(1 | ((!thumb as u32) << 1));
251+
let guest_pc = guest_pc & guest_pc_mask;
252252
let jit_entry = get_jit!(asm.emu).get_jit_start_addr::<CPU>(guest_pc);
253253
let jit_entry: extern "C" fn(bool) = unsafe { mem::transmute(jit_entry) };
254254

@@ -313,7 +313,6 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
313313
}
314314
}
315315

316-
#[inline(always)]
317316
pub fn execute(&mut self) -> u16 {
318317
let entry = get_regs!(self.emu, CPU).pc;
319318
execute_internal::<CPU>(entry)

src/jit/jit_memory.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::utils::{HeapMem, HeapMemU32};
88
use crate::{utils, DEBUG_LOG};
99
use lazy_static::lazy_static;
1010
use paste::paste;
11-
use std::hint::assert_unchecked;
1211
use std::intrinsics::unlikely;
1312
use std::marker::ConstParamTy;
1413
use std::{ptr, slice};
@@ -225,11 +224,7 @@ impl JitMemory {
225224
}
226225

227226
pub fn get_jit_start_addr<const CPU: CpuType>(&self, guest_pc: u32) -> *const extern "C" fn(bool) {
228-
let ptr = self.jit_memory_map.get_jit_entry::<CPU>(guest_pc);
229-
unsafe {
230-
assert_unchecked(!ptr.is_null());
231-
(*ptr).0
232-
}
227+
unsafe { (*self.jit_memory_map.get_jit_entry::<CPU>(guest_pc)).0 }
233228
}
234229

235230
pub fn invalidate_block<const REGION: JitRegion>(&mut self, guest_addr: u32, size: usize) {

0 commit comments

Comments
 (0)