Update dynarmic to HEAD

Allows for further work on dynarmic to be done (mainly to get LTO
working) Also allows context register accesses from Rust code.

Change-Id: If385a700daa806bc122eca937ec82b7ee2082a91
This commit is contained in:
abnormalmaps
2025-11-10 12:13:29 -05:00
parent 55a3542449
commit 022acf7b59
5 changed files with 55 additions and 51 deletions

View File

@@ -17,6 +17,7 @@ use crate::mem::{ConstPtr, GuestUSize, Mem, MutPtr, Ptr, SafeRead, SafeWrite};
use touchHLE_dynarmic_wrapper::*;
type VAddr = u32;
pub type CpuContext = touchHLE_DynarmicContext;
fn touchHLE_cpu_read_impl<T: SafeRead + Default>(
mem: *mut touchHLE_Mem,
@@ -104,23 +105,6 @@ impl Drop for Cpu {
}
}
/// Object for storing the state of a CPU (registers etc), useful when switching
/// threads.
pub struct CpuContext {
context: *mut Dynarmic_A32_Context,
}
impl CpuContext {
pub fn new() -> Self {
let context = unsafe { touchHLE_DynarmicWrapper_Context_new() };
CpuContext { context }
}
}
impl Drop for CpuContext {
fn drop(&mut self) {
unsafe { touchHLE_DynarmicWrapper_Context_delete(self.context) }
}
}
/// Why CPU execution ended.
#[derive(Debug)]
pub enum CpuState {
@@ -231,7 +215,7 @@ impl Cpu {
/// Swap the current state of the CPU (registers etc) with the state stored
/// in the context object.
pub fn swap_context(&mut self, context: &mut CpuContext) {
unsafe { touchHLE_DynarmicWrapper_swap_context(self.dynarmic_wrapper, context.context) }
unsafe { touchHLE_DynarmicWrapper_swap_context(self.dynarmic_wrapper, context) }
}
/// Get PC with the Thumb bit appropriately set.

View File

@@ -8,7 +8,6 @@
#include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/config.h"
#include "dynarmic/interface/A32/context.h"
#include "dynarmic/interface/A32/coprocessor.h"
#include "dynarmic/interface/exclusive_monitor.h"
@@ -27,6 +26,12 @@ bool touchHLE_cpu_write_u8(touchHLE_Mem *mem, VAddr addr, std::uint8_t value);
bool touchHLE_cpu_write_u16(touchHLE_Mem *mem, VAddr addr, std::uint16_t value);
bool touchHLE_cpu_write_u32(touchHLE_Mem *mem, VAddr addr, std::uint32_t value);
bool touchHLE_cpu_write_u64(touchHLE_Mem *mem, VAddr addr, std::uint64_t value);
struct touchHLE_DynarmicContext {
std::array<std::uint32_t, 16> regs;
std::array<std::uint32_t, 64> extregs;
std::uint32_t cpsr;
std::uint32_t fpscr;
};
}
const auto HaltReasonSvc = Dynarmic::HaltReason::UserDefined1;
@@ -264,10 +269,14 @@ public:
cpu->InvalidateCacheRange(start, size);
}
void swap_context(void *context) {
Dynarmic::A32::Context tmp = cpu->SaveContext();
cpu->LoadContext(*(Dynarmic::A32::Context *)context);
*(Dynarmic::A32::Context *)context = tmp;
void swap_context(touchHLE_DynarmicContext *context) {
touchHLE_DynarmicContext tmp = {cpu->Regs(), cpu->ExtRegs(), cpu->Cpsr(),
cpu->Fpscr()};
cpu->Regs() = context->regs;
cpu->ExtRegs() = context->extregs;
cpu->SetCpsr(context->cpsr);
cpu->SetFpscr(context->fpscr);
*context = tmp;
}
std::int32_t run_or_step(touchHLE_Mem *mem, std::uint64_t *ticks) {
@@ -327,7 +336,7 @@ void touchHLE_DynarmicWrapper_set_cpsr(DynarmicWrapper *cpu,
}
void touchHLE_DynarmicWrapper_swap_context(DynarmicWrapper *cpu,
void *context) {
touchHLE_DynarmicContext *context) {
cpu->swap_context(context);
}
@@ -342,13 +351,6 @@ std::int32_t touchHLE_DynarmicWrapper_run_or_step(DynarmicWrapper *cpu,
std::uint64_t *ticks) {
return cpu->run_or_step(mem, ticks);
}
void *touchHLE_DynarmicWrapper_Context_new() {
return (void *)new Dynarmic::A32::Context();
}
void touchHLE_DynarmicWrapper_Context_delete(void *context) {
delete (Dynarmic::A32::Context *)context;
}
}
} // namespace touchHLE::cpu

View File

@@ -17,10 +17,33 @@ pub type touchHLE_DynarmicWrapper = std::ffi::c_void;
/// `c_void` is used here to avoid depending on it directly)
#[allow(non_camel_case_types)]
pub type touchHLE_Mem = std::ffi::c_void;
/// Opaque C++ type
#[allow(non_camel_case_types)]
pub type Dynarmic_A32_Context = std::ffi::c_void;
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
pub struct touchHLE_DynarmicContext {
pub regs: [u32; 16],
pub extregs: [u32; 64],
pub cpsr: u32,
pub fpscr: u32,
}
impl Default for touchHLE_DynarmicContext {
fn default() -> Self {
Self {
regs: [0; 16],
extregs: [0; 64],
cpsr: 0,
fpscr: 0,
}
}
}
impl touchHLE_DynarmicContext {
pub fn new() -> Self {
Self::default()
}
}
type VAddr = u32;
// Import functions from lib.cpp, see build.rs. Note that lib.cpp depends on
@@ -37,7 +60,7 @@ extern "C" {
pub fn touchHLE_DynarmicWrapper_set_cpsr(cpu: *mut touchHLE_DynarmicWrapper, cpsr: u32);
pub fn touchHLE_DynarmicWrapper_swap_context(
cpu: *mut touchHLE_DynarmicWrapper,
context: *mut Dynarmic_A32_Context,
context: *mut touchHLE_DynarmicContext,
);
pub fn touchHLE_DynarmicWrapper_invalidate_cache_range(
cpu: *mut touchHLE_DynarmicWrapper,
@@ -50,6 +73,4 @@ extern "C" {
ticks: Option<&mut u64>,
) -> i32;
pub fn touchHLE_DynarmicWrapper_Context_new() -> *mut Dynarmic_A32_Context;
pub fn touchHLE_DynarmicWrapper_Context_delete(context: *mut Dynarmic_A32_Context);
}

View File

@@ -62,7 +62,7 @@ pub struct Thread {
/// When a thread is currently executing, its state is stored directly in
/// the CPU, rather than in a context object. In that case, this field is
/// None. See also: [std::mem::take] and [cpu::Cpu::swap_context].
context: Option<cpu::CpuContext>,
context: Option<Box<cpu::CpuContext>>,
/// Address range of this thread's stack, used to check if addresses are in
/// range while producing a stack trace.
stack: Option<std::ops::RangeInclusive<u32>>,
@@ -721,25 +721,22 @@ impl Environment {
return_value: None,
in_start_routine: true,
in_host_function: false,
context: Some(cpu::CpuContext::new()),
context: Some(Box::new(cpu::CpuContext::new())),
stack: Some(stack_alloc.to_bits()..=(stack_high_addr - 1)),
});
let new_thread_id = self.threads.len() - 1;
log_dbg!("Created new thread {} with stack {:#x}{:#x}, will execute function {:?} with data {:?}", new_thread_id, stack_alloc.to_bits(), (stack_high_addr - 1), start_routine, user_data);
let old_thread = self.current_thread;
// Set up the registers for the new thread
let context = self.threads[new_thread_id].context.as_mut().unwrap();
context.regs[cpu::Cpu::SP] = stack_high_addr;
context.regs[0] = user_data.to_bits();
// Switch to the new context (all zeroes) and set up the registers
// (which we can only do by switching). The original thread's state
// should be the same as before.
self.switch_thread(new_thread_id);
self.cpu.set_cpsr(cpu::Cpu::CPSR_USER_MODE);
self.cpu.regs_mut()[cpu::Cpu::SP] = stack_high_addr;
self.cpu.regs_mut()[0] = user_data.to_bits();
self.cpu
.branch_with_link(start_routine, self.dyld.thread_exit_routine());
self.switch_thread(old_thread);
context.cpsr =
cpu::Cpu::CPSR_USER_MODE | ((start_routine.is_thumb() as u32) * cpu::Cpu::CPSR_THUMB);
context.regs[cpu::Cpu::PC] = start_routine.addr_without_thumb_bit();
context.regs[cpu::Cpu::LR] = self.dyld.thread_exit_routine().addr_with_thumb_bit();
new_thread_id
}