Skip to content

Commit 85bbe4f

Browse files
committed
hle interrupt
1 parent 07b84d7 commit 85bbe4f

File tree

6 files changed

+94
-27
lines changed

6 files changed

+94
-27
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,4 @@ opt-level = 3
6767
[profile.release]
6868
panic = "abort"
6969
lto = "fat"
70+
debug = 1

src/core/cpu_regs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl CpuRegs {
114114
}
115115

116116
pub fn set_irf(&mut self, mask: u32, value: u32) {
117-
// debug_println!("{:?} set irf {:?}", self.cpu_type, InterruptFlags(value & mask));
117+
debug_println!("{:?} set irf {:?}", self.cpu_type, InterruptFlags(value & mask));
118118
self.irf &= !(value & mask);
119119
}
120120

src/jit/inst_branch_handler.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ unsafe extern "C" fn flush_cycles<const CPU: CpuType>(asm: &mut JitAsm<CPU>, tot
1919
}
2020

2121
#[inline(always)]
22-
unsafe extern "C" fn call_jit_fun<const CPU: CpuType>(asm: &mut JitAsm<CPU>, target_pc: u32) {
22+
pub unsafe extern "C" fn call_jit_fun<const CPU: CpuType>(asm: &mut JitAsm<CPU>, target_pc: u32, store_host_sp: bool) {
2323
let thumb = target_pc & 1 != 0;
2424
get_regs_mut!(asm.emu, CPU).set_thumb(thumb);
2525
let aligned_pc_mask = !(1 | ((!thumb as u32) << 1));
2626
let aligned_pc = target_pc & aligned_pc_mask;
2727

2828
let jit_entry = get_jit!(asm.emu).get_jit_start_addr::<CPU>(aligned_pc);
2929
let jit_entry: extern "C" fn(bool) = mem::transmute(jit_entry);
30-
jit_entry(false);
30+
jit_entry(store_host_sp);
3131
}
3232

3333
pub unsafe extern "C" fn branch_reg_with_lr_return<const CPU: CpuType>(total_cycles: u16, lr: u32, target_pc: u32, current_pc: u32) {
@@ -45,21 +45,23 @@ pub unsafe extern "C" fn branch_reg_with_lr_return<const CPU: CpuType>(total_cyc
4545
JitAsmCommonFuns::<CPU>::debug_branch_reg(current_pc, target_pc);
4646
}
4747

48-
call_jit_fun(asm, target_pc);
48+
call_jit_fun(asm, target_pc, false);
4949
asm.runtime_data.pre_cycle_count_sum = total_cycles;
5050
}
5151

52-
pub unsafe extern "C" fn branch_lr<const CPU: CpuType>(total_cycles: u16, target_pc: u32, current_pc: u32) {
52+
pub unsafe extern "C" fn branch_lr<const CPU: CpuType, const FLUSH_CYCLES: bool>(total_cycles: u16, target_pc: u32, store_host_sp: bool, current_pc: u32) {
5353
let asm = get_jit_asm_ptr::<CPU>().as_mut_unchecked();
5454

55-
flush_cycles(asm, total_cycles, current_pc);
55+
if FLUSH_CYCLES {
56+
flush_cycles(asm, total_cycles, current_pc);
57+
}
5658

5759
if unlikely(asm.runtime_data.return_stack_ptr == 0) {
5860
if DEBUG_LOG {
5961
JitAsmCommonFuns::<CPU>::debug_return_stack_empty(current_pc, target_pc);
6062
}
6163
asm.runtime_data.pre_cycle_count_sum = 0;
62-
call_jit_fun(asm, target_pc);
64+
call_jit_fun(asm, target_pc, store_host_sp);
6365
unsafe { unreachable_unchecked() };
6466
} else {
6567
asm.runtime_data.return_stack_ptr -= 1;
@@ -75,7 +77,7 @@ pub unsafe extern "C" fn branch_lr<const CPU: CpuType>(total_cycles: u16, target
7577
}
7678
asm.runtime_data.pre_cycle_count_sum = 0;
7779
asm.runtime_data.return_stack_ptr = 0;
78-
call_jit_fun(asm, target_pc);
80+
call_jit_fun(asm, target_pc, store_host_sp);
7981
unsafe { unreachable_unchecked() };
8082
}
8183
}

src/jit/jit_asm.rs

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use crate::core::emu::{get_cpu_regs, get_jit, get_jit_mut, get_regs, get_regs_mut, Emu};
1+
use crate::core::emu::{get_cpu_regs, get_cpu_regs_mut, get_jit, get_jit_mut, get_regs, get_regs_mut, Emu};
22
use crate::core::hle::bios;
33
use crate::core::thread_regs::ThreadRegs;
44
use crate::core::CpuType;
5+
use crate::core::CpuType::ARM9;
56
use crate::jit::assembler::block_asm::{BlockAsm, BLOCK_LOG};
67
use crate::jit::assembler::BlockAsmBuf;
78
use crate::jit::disassembler::lookup_table::lookup_opcode;
89
use crate::jit::disassembler::thumb::lookup_table_thumb::lookup_thumb_opcode;
10+
use crate::jit::inst_branch_handler::{branch_lr, call_jit_fun};
911
use crate::jit::inst_info::InstInfo;
1012
use crate::jit::jit_asm_common_funs::{exit_guest_context, JitAsmCommonFuns};
1113
use crate::jit::op::Op;
@@ -14,6 +16,7 @@ use crate::jit::reg::{reg_reserve, RegReserve};
1416
use crate::logging::debug_println;
1517
use crate::{get_jit_asm_ptr, DEBUG_LOG, IS_DEBUG};
1618
use std::cell::UnsafeCell;
19+
use std::hint::unreachable_unchecked;
1720
use std::intrinsics::unlikely;
1821
use std::{mem, ptr};
1922

@@ -50,7 +53,8 @@ impl JitBuf {
5053

5154
pub const RETURN_STACK_SIZE: usize = 16;
5255

53-
#[repr(C, align(64))]
56+
#[repr(C)]
57+
#[derive(Default)]
5458
pub struct JitRuntimeData {
5559
pub idle_loop: bool,
5660
pub return_stack_ptr: u8,
@@ -59,19 +63,13 @@ pub struct JitRuntimeData {
5963
pub accumulated_cycles: u16,
6064
pub host_sp: usize,
6165
pub branch_out_pc: u32,
66+
guest_irq_table_addr: u32,
67+
guest_irq_handler_thread_switch_addr: u32,
6268
}
6369

6470
impl JitRuntimeData {
6571
fn new() -> Self {
66-
let instance = JitRuntimeData {
67-
branch_out_pc: u32::MAX,
68-
pre_cycle_count_sum: 0,
69-
accumulated_cycles: 0,
70-
idle_loop: false,
71-
host_sp: 0,
72-
return_stack_ptr: 0,
73-
return_stack: [0; RETURN_STACK_SIZE],
74-
};
72+
let instance = JitRuntimeData::default();
7573
assert_eq!(size_of_val(&instance.return_stack), RETURN_STACK_SIZE * 4);
7674
instance
7775
}
@@ -106,7 +104,7 @@ impl JitRuntimeData {
106104
}
107105

108106
pub extern "C" fn hle_bios_uninterrupt<const CPU: CpuType>(store_host_sp: bool) {
109-
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut().unwrap_unchecked() };
107+
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut_unchecked() };
110108
if IS_DEBUG {
111109
asm.runtime_data.branch_out_pc = get_regs!(asm.emu, CPU).pc;
112110
}
@@ -129,8 +127,38 @@ pub extern "C" fn hle_bios_uninterrupt<const CPU: CpuType>(store_host_sp: bool)
129127
}
130128
}
131129

130+
pub extern "C" fn hle_interrupt_handler_arm9(store_host_sp: bool) {
131+
let asm = unsafe { get_jit_asm_ptr::<{ ARM9 }>().as_mut_unchecked() };
132+
133+
let regs = get_regs_mut!(asm.emu, ARM9);
134+
let cpu_regs = get_cpu_regs_mut!(asm.emu, ARM9);
135+
136+
let enabled_interrupts = cpu_regs.ie & cpu_regs.irf;
137+
if cpu_regs.ime == 0 || enabled_interrupts == 0 {
138+
regs.pc = regs.lr;
139+
unsafe { branch_lr::<{ ARM9 }, false>(0, regs.pc, store_host_sp, 0x1ff8000) };
140+
return;
141+
}
142+
143+
regs.sp -= 4;
144+
asm.emu.mem_write::<{ ARM9 }, _>(regs.sp, regs.lr);
145+
146+
let interrupt_number = enabled_interrupts.trailing_zeros();
147+
let ack_interrupt = 1 << interrupt_number;
148+
cpu_regs.set_irf(0xFFFFFFFF, ack_interrupt);
149+
150+
let handler_addr = asm.emu.mem_read::<{ ARM9 }, u32>(asm.runtime_data.guest_irq_table_addr + (interrupt_number << 2));
151+
regs.lr = asm.runtime_data.guest_irq_handler_thread_switch_addr;
152+
regs.pc = handler_addr;
153+
154+
unsafe { call_jit_fun::<{ ARM9 }>(asm, regs.pc, store_host_sp) };
155+
if !store_host_sp {
156+
unsafe { unreachable_unchecked() };
157+
}
158+
}
159+
132160
pub extern "C" fn emit_code_block<const CPU: CpuType>(store_host_sp: bool) {
133-
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut().unwrap_unchecked() };
161+
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut_unchecked() };
134162

135163
let guest_pc = get_regs!(asm.emu, CPU).pc;
136164
let thumb = (guest_pc & 1) == 1;
@@ -141,7 +169,35 @@ pub extern "C" fn emit_code_block<const CPU: CpuType>(store_host_sp: bool) {
141169
}
142170
}
143171

172+
fn emit_hle_interrupt_handler_arm9(asm: &mut JitAsm<{ ARM9 }>, store_host_sp: bool) {
173+
{
174+
let ldr_irq_table_op = asm.emu.mem_read::<{ ARM9 }, u32>(0x1ff8040);
175+
let (op, func) = lookup_opcode(ldr_irq_table_op);
176+
let inst_info = func(ldr_irq_table_op, *op);
177+
assert!(*op == Op::LdrOfip && *inst_info.operands()[1].as_reg_no_shift().unwrap() == Reg::PC && *inst_info.operands()[2].as_imm().unwrap() == 8);
178+
}
179+
180+
{
181+
let ldr_irq_handler_thread_switch_op = asm.emu.mem_read::<{ ARM9 }, u32>(0x1ff8048);
182+
let (op, func) = lookup_opcode(ldr_irq_handler_thread_switch_op);
183+
let inst_info = func(ldr_irq_handler_thread_switch_op, *op);
184+
assert!(*op == Op::LdrOfip && *inst_info.operands()[1].as_reg_no_shift().unwrap() == Reg::PC && *inst_info.operands()[2].as_imm().unwrap() == 4);
185+
}
186+
187+
asm.runtime_data.guest_irq_table_addr = asm.emu.mem_read::<{ ARM9 }, _>(0x1ff8040 + 16);
188+
asm.runtime_data.guest_irq_handler_thread_switch_addr = asm.emu.mem_read::<{ ARM9 }, _>(0x1ff8048 + 12);
189+
190+
get_jit_mut!(asm.emu).insert_function::<{ ARM9 }>(0x1ff8000, hle_interrupt_handler_arm9 as _);
191+
192+
hle_interrupt_handler_arm9(store_host_sp);
193+
}
194+
144195
fn emit_code_block_internal<const CPU: CpuType, const THUMB: bool>(asm: &mut JitAsm<CPU>, store_host_sp: bool, guest_pc: u32) {
196+
if CPU == ARM9 && unlikely(guest_pc == 0x1ff8000) {
197+
unsafe { emit_hle_interrupt_handler_arm9(mem::transmute(asm), store_host_sp) };
198+
return;
199+
}
200+
145201
let mut uncond_branch_count = 0;
146202
let mut pc_offset = 0;
147203
loop {
@@ -227,9 +283,7 @@ fn emit_code_block_internal<const CPU: CpuType, const THUMB: bool>(asm: &mut Jit
227283
}
228284
let jit_entry: extern "C" fn(bool) = unsafe { mem::transmute(insert_entry) };
229285

230-
if DEBUG_LOG {
231-
// println!("{CPU:?} Mapping {guest_pc:#010x} to {:#010x}", jit_entry as *const fn() as usize);
232-
}
286+
debug_println!("{CPU:?} Mapping {guest_pc:#010x} to {:#010x}", jit_entry as *const fn() as usize);
233287
asm.jit_buf.clear_all();
234288
jit_entry
235289
};
@@ -238,7 +292,7 @@ fn emit_code_block_internal<const CPU: CpuType, const THUMB: bool>(asm: &mut Jit
238292
}
239293

240294
fn execute_internal<const CPU: CpuType>(guest_pc: u32) -> u16 {
241-
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut().unwrap_unchecked() };
295+
let asm = unsafe { get_jit_asm_ptr::<CPU>().as_mut_unchecked() };
242296

243297
let thumb = (guest_pc & 1) == 1;
244298
debug_println!("{:?} Execute {:x} thumb {}", CPU, guest_pc, thumb);

src/jit/jit_asm_common_funs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ impl<const CPU: CpuType> JitAsmCommonFuns<CPU> {
170170

171171
pub fn emit_call_branch_return_stack(&self, block_asm: &mut BlockAsm, total_cycles: u16, target_pc_reg: BlockReg, current_pc: u32) {
172172
if IS_DEBUG {
173-
block_asm.call3(branch_lr::<CPU> as *const (), total_cycles as u32, target_pc_reg, current_pc);
173+
block_asm.call4(branch_lr::<CPU, true> as *const (), total_cycles as u32, target_pc_reg, 0, current_pc);
174174
} else {
175-
block_asm.call2(branch_lr::<CPU> as *const (), total_cycles as u32, target_pc_reg);
175+
block_asm.call3(branch_lr::<CPU, true> as *const (), total_cycles as u32, target_pc_reg, 0);
176176
}
177177
}
178178

src/jit/jit_memory.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ impl JitMemory {
305305
}
306306
}
307307

308+
pub fn insert_function<const CPU: CpuType>(&mut self, guest_pc: u32, func: *const extern "C" fn(bool)) {
309+
unsafe {
310+
let entry = self.jit_memory_map.get_jit_entry::<CPU>(guest_pc).as_mut_unchecked();
311+
entry.0 = func;
312+
let live_range = self.jit_memory_map.get_live_range::<CPU>(guest_pc);
313+
let live_ranges_bit = (guest_pc >> JIT_LIVE_RANGE_PAGE_SIZE_SHIFT) & 0x7;
314+
*live_range |= 1 << live_ranges_bit;
315+
}
316+
}
317+
308318
pub fn get_jit_start_addr<const CPU: CpuType>(&self, guest_pc: u32) -> *const extern "C" fn(bool) {
309319
unsafe { (*self.jit_memory_map.get_jit_entry::<CPU>(guest_pc)).0 }
310320
}

0 commit comments

Comments
 (0)