Implement SoftTLB for writes.

This commit is contained in:
Maxim Poliakovski 2021-08-03 16:01:32 +02:00
parent 4f3dd797be
commit 089645e830
7 changed files with 546 additions and 165 deletions

View File

@ -148,22 +148,26 @@ void dppc_interpreter::power_lscbx() {
if (match_found == false) {
switch (shift_amount) {
case 0:
return_value = mem_grab_byte(ppc_effective_address);
return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
//return_value = mem_grab_byte(ppc_effective_address);
ppc_result_d = (ppc_result_d & 0x00FFFFFF) | (return_value << 24);
ppc_store_result_regd();
break;
case 1:
return_value = mem_grab_byte(ppc_effective_address);
return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
//return_value = mem_grab_byte(ppc_effective_address);
ppc_result_d = (ppc_result_d & 0xFF00FFFF) | (return_value << 16);
ppc_store_result_regd();
break;
case 2:
return_value = mem_grab_byte(ppc_effective_address);
return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
//return_value = mem_grab_byte(ppc_effective_address);
ppc_result_d = (ppc_result_d & 0xFFFF00FF) | (return_value << 8);
ppc_store_result_regd();
break;
case 3:
return_value = mem_grab_byte(ppc_effective_address);
return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
//return_value = mem_grab_byte(ppc_effective_address);
ppc_result_d = (ppc_result_d & 0xFFFFFF00) | return_value;
ppc_store_result_regd();
break;
@ -494,4 +498,4 @@ void dppc_interpreter::power_srlq() {
void dppc_interpreter::power_srq() {
LOG_F(WARNING, "OOPS! Placeholder for srq!!! \n");
}
}

View File

@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "devices/memctrlbase.h"
#include "endianswap.h"
#include <cinttypes>
#include <functional>
#include <setjmp.h>
#include <string>
@ -301,6 +302,9 @@ void ppc_fp_changecrf1();
// MEMORY DECLARATIONS
extern MemCtrlBase* mem_ctrl_instance;
//typedef std::function<void()> CtxSyncCallback;
extern void add_ctx_sync_action(const std::function<void()> &);
// The functions used by the PowerPC processor
namespace dppc_interpreter {
extern void ppc_bcctr();

View File

@ -674,11 +674,11 @@ void dppc_interpreter::ppc_fctiw() {
if (std::isnan(val_reg_b)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x1000100;
}
}
else if (val_reg_b > static_cast<double>(0x7fffffff)) {
ppc_state.fpr[reg_d].int64_r = 0x7fffffff;
ppc_state.fpscr |= 0x100;
}
}
else if (val_reg_b < -static_cast<double>(0x80000000)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x100;
@ -696,7 +696,7 @@ void dppc_interpreter::ppc_fctiw() {
}
ppc_store_dfpresult_int(reg_d);
}
if (rc_flag)
@ -710,15 +710,15 @@ void dppc_interpreter::ppc_fctiwz() {
if (std::isnan(val_reg_b)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x1000100;
}
}
else if (val_reg_b > static_cast<double>(0x7fffffff)) {
ppc_state.fpr[reg_d].int64_r = 0x7fffffff;
ppc_state.fpscr |= 0x100;
}
}
else if (val_reg_b < -static_cast<double>(0x80000000)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x100;
}
}
else {
ppc_result64_d = round_to_zero(val_reg_b);
@ -735,7 +735,8 @@ void dppc_interpreter::ppc_lfs() {
ppc_grab_regsfpdia();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a) ? val_reg_a : 0;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
}
@ -745,7 +746,8 @@ void dppc_interpreter::ppc_lfsu() {
if (reg_a) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a) ? val_reg_a : 0;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
@ -756,7 +758,8 @@ void dppc_interpreter::ppc_lfsu() {
void dppc_interpreter::ppc_lfsx() {
ppc_grab_regsfpdiab();
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
}
@ -764,7 +767,8 @@ void dppc_interpreter::ppc_lfsux() {
ppc_grab_regsfpdiab();
if (reg_a) {
ppc_effective_address = val_reg_a + val_reg_b;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
@ -820,7 +824,8 @@ void dppc_interpreter::ppc_stfs() {
ppc_grab_regsfpsia();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a) ? val_reg_a : 0;
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
mmu_write_vmem<uint32_t>(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
//mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
}
void dppc_interpreter::ppc_stfsu() {
@ -828,7 +833,8 @@ void dppc_interpreter::ppc_stfsu() {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += val_reg_a;
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
mmu_write_vmem<uint32_t>(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
//mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -838,14 +844,16 @@ void dppc_interpreter::ppc_stfsu() {
void dppc_interpreter::ppc_stfsx() {
ppc_grab_regsfpsiab();
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
mmu_write_vmem<uint32_t>(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
//mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
}
void dppc_interpreter::ppc_stfsux() {
ppc_grab_regsfpsiab();
if (reg_a) {
ppc_effective_address = val_reg_a + val_reg_b;
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
mmu_write_vmem<uint32_t>(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
//mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -856,7 +864,8 @@ void dppc_interpreter::ppc_stfd() {
ppc_grab_regsfpsia();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a) ? val_reg_a : 0;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
mmu_write_vmem<uint64_t>(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
//mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
}
void dppc_interpreter::ppc_stfdu() {
@ -864,7 +873,8 @@ void dppc_interpreter::ppc_stfdu() {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += val_reg_a;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
mmu_write_vmem<uint64_t>(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
//mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -874,14 +884,16 @@ void dppc_interpreter::ppc_stfdu() {
void dppc_interpreter::ppc_stfdx() {
ppc_grab_regsfpsiab();
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
mmu_write_vmem<uint64_t>(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
//mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
}
void dppc_interpreter::ppc_stfdux() {
ppc_grab_regsfpsiab();
if (reg_a != 0) {
ppc_effective_address = val_reg_a + val_reg_b;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
mmu_write_vmem<uint64_t>(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
//mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -891,7 +903,8 @@ void dppc_interpreter::ppc_stfdux() {
void dppc_interpreter::ppc_stfiwx() {
ppc_grab_regsfpsiab();
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
mem_write_dword(ppc_effective_address, (uint32_t)(ppc_state.fpr[reg_s].int64_r));
mmu_write_vmem<uint32_t>(ppc_effective_address, (uint32_t)(ppc_state.fpr[reg_s].int64_r));
//mem_write_dword(ppc_effective_address, (uint32_t)(ppc_state.fpr[reg_s].int64_r));
}
// Floating Point Register Transfer

View File

@ -137,6 +137,7 @@ public:
/** Temporary TLB test variables. */
bool MemAccessType; // true - memory, false - I/O
bool Unaligned_crosspage = false;
uint64_t MemAddr = 0;
MMIODevice *Device = 0;
uint32_t DevOffset = 0;
@ -239,6 +240,21 @@ static inline void write_phys_mem(AddressMapEntry *mru_rgn, uint32_t addr, T val
#ifdef MMU_PROFILING
dmem_writes_total++;
#endif
#if 1
if (!MemAccessType) {
LOG_F(ERROR, "TLB real memory access expected!");
}
if (!is_aligned && Unaligned_crosspage) {
LOG_F(WARNING, "Unaligned cross-page access ignored!");
} else if ((mru_rgn->mem_ptr + (addr - mru_rgn->start)) != (uint8_t *)MemAddr) {
LOG_F(ERROR, "TLB address mismatch! Expected: 0x%llx, got: 0x%llx",
(uint64_t)(mru_rgn->mem_ptr + (addr - mru_rgn->start)),
(uint64_t)MemAddr);
}
#endif
switch(sizeof(T)) {
case 1:
*(mru_rgn->mem_ptr + (addr - mru_rgn->start)) = value;
@ -270,6 +286,18 @@ static inline void write_phys_mem(AddressMapEntry *mru_rgn, uint32_t addr, T val
#ifdef MMU_PROFILING
iomem_writes_total++;
#endif
#if 1
if (MemAccessType) {
LOG_F(ERROR, "TLB I/O memory access expected!");
}
if (mru_rgn->devobj != Device || (addr - mru_rgn->start) != DevOffset) {
LOG_F(ERROR, "TLB MMIO access mismatch! Expected: 0x%X, got: 0x%X",
addr - mru_rgn->start, DevOffset);
}
#endif
mru_rgn->devobj->write(mru_rgn->start, addr - mru_rgn->start, value,
sizeof(T));
} else {
@ -298,6 +326,9 @@ void ppc_set_cur_instruction(const uint8_t* ptr) {
ppc_cur_instruction = READ_DWORD_BE_A(ptr);
}
bool gTLBFlushBatEntries = false;
bool gTLBFlushPatEntries = false;
void ibat_update(uint32_t bat_reg) {
int upper_reg_num;
uint32_t bl, hi_mask;
@ -335,6 +366,19 @@ void dbat_update(uint32_t bat_reg) {
bat_entry->hi_mask = hi_mask;
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & hi_mask;
bat_entry->bepi = ppc_state.spr[upper_reg_num] & hi_mask;
if (!gTLBFlushBatEntries) {
gTLBFlushBatEntries = true;
add_ctx_sync_action(&tlb_flush_bat_entries);
}
}
}
void mmu_pat_ctx_changed()
{
if (!gTLBFlushPatEntries) {
gTLBFlushPatEntries = true;
add_ctx_sync_action(&tlb_flush_pat_entries);
}
}
@ -437,7 +481,9 @@ static bool search_pteg(
return false;
}
static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, unsigned msr_pr, int is_write) {
static PATResult page_address_translate(uint32_t la, bool is_instr_fetch,
unsigned msr_pr, int is_write)
{
uint32_t sr_val, page_index, pteg_hash1, vsid, pte_word2;
unsigned key, pp;
uint8_t* pte_addr;
@ -497,8 +543,12 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, unsigne
pte_addr[7] |= 0x80;
}
/* return physical address */
return ((pte_word2 & 0xFFFFF000) | (la & 0x00000FFF));
/* return physical address, access protection and C status */
return PATResult{
((pte_word2 & 0xFFFFF000) | (la & 0x00000FFF)),
static_cast<uint8_t>((key << 2) | pp),
static_cast<uint8_t>(pte_word2 & 0x80)
};
}
/** PowerPC-style MMU instruction address translation. */
@ -535,7 +585,8 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la) {
/* page address translation */
if (!bat_hit) {
pa = page_address_translate(la, true, msr_pr, 0);
PATResult pat_res = page_address_translate(la, true, msr_pr, 0);
pa = pat_res.phys;
#ifdef MMU_PROFILING
ptab_transl_total++;
@ -581,7 +632,8 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) {
/* page address translation */
if (!bat_hit) {
pa = page_address_translate(la, false, msr_pr, is_write);
PATResult pat_res = page_address_translate(la, false, msr_pr, is_write);
pa = pat_res.phys;
#ifdef MMU_PROFILING
ptab_transl_total++;
@ -635,73 +687,6 @@ static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size) {
}
}
void mem_write_byte(uint32_t addr, uint8_t value) {
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint8_t, true>(&last_write_area, addr, value);
}
void mem_write_word(uint32_t addr, uint16_t value) {
if (addr & 1) {
mem_write_unaligned(addr, value, 2);
return;
}
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint16_t, true>(&last_write_area, addr, value);
}
void mem_write_dword(uint32_t addr, uint32_t value) {
if (addr & 3) {
mem_write_unaligned(addr, value, 4);
return;
}
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint32_t, true>(&last_write_area, addr, value);
}
void mem_write_qword(uint32_t addr, uint64_t value) {
if (addr & 7) {
LOG_F(ERROR, "SOS! Attempt to write unaligned QWORD to 0x%08X\n", addr);
exit(-1); // FIXME!
}
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint64_t, true>(&last_write_area, addr, value);
}
#define PAGE_SIZE_BITS 12
#define TLB_SIZE 4096
#define TLB2_WAYS 4
#define TLB_INVALID_TAG 0xFFFFFFFF
typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
int64_t host_va_offset;
AddressMapEntry* reg_desc;
};
} TLBEntry;
// primary TLB for all MMU modes
static std::array<TLBEntry, TLB_SIZE> mode1_tlb1;
static std::array<TLBEntry, TLB_SIZE> mode2_tlb1;
@ -721,13 +706,13 @@ uint32_t tlb_size_mask = TLB_SIZE - 1;
uint64_t UnmappedVal = -1ULL;
TLBEntry UnmappedMem = {TLB_INVALID_TAG, 0, 0, 0};
uint8_t MMUMode = {0xFF};
uint8_t CurMMUMode = {0xFF}; // current MMU mode
void mmu_change_mode()
{
uint8_t mmu_mode = ((ppc_state.msr >> 3) & 0x2) | ((ppc_state.msr >> 14) & 1);
if (MMUMode != mmu_mode) {
if (CurMMUMode != mmu_mode) {
switch(mmu_mode) {
case 0: // real address mode
pCurTLB1 = &mode1_tlb1[0];
@ -742,7 +727,7 @@ void mmu_change_mode()
pCurTLB2 = &mode3_tlb2[0];
break;
}
MMUMode = mmu_mode;
CurMMUMode = mmu_mode;
}
}
@ -817,6 +802,7 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
static TLBEntry* tlb2_refill(uint32_t guest_va, int is_write)
{
uint32_t phys_addr;
uint16_t flags = 0;
TLBEntry *tlb_entry;
const uint32_t tag = guest_va & ~0xFFFUL;
@ -828,18 +814,40 @@ static TLBEntry* tlb2_refill(uint32_t guest_va, int is_write)
if (bat_res.hit) {
// check block protection
if (!bat_res.prot || ((bat_res.prot & 1) && is_write)) {
LOG_F(WARNING, "BAT DSI exception in TLB2 refill!");
LOG_F(WARNING, "Attempt to write to read-only region, LA=0x%08X, PC=0x%08X!", guest_va, ppc_state.pc);
//UnmappedMem.tag = tag;
//UnmappedMem.host_va_offset = (int64_t)(&UnmappedVal) - guest_va;
//return &UnmappedMem;
ppc_state.spr[SPR::DSISR] = 0x08000000 | (is_write << 25);
ppc_state.spr[SPR::DAR] = guest_va;
mmu_exception_handler(Except_Type::EXC_DSI, 0);
}
phys_addr = bat_res.phys;
flags = TLBFlags::PTE_SET_C; // prevent PTE.C updates for BAT
flags |= TLBFlags::TLBE_FROM_BAT; // tell the world we come from
if (bat_res.prot == 2) {
flags |= TLBFlags::PAGE_WRITABLE;
}
} else {
// page address translation
phys_addr = page_address_translate(guest_va, false,
!!(ppc_state.msr & 0x4000), is_write);
PATResult pat_res = page_address_translate(guest_va, false,
!!(ppc_state.msr & 0x4000), is_write);
phys_addr = pat_res.phys;
flags = TLBFlags::TLBE_FROM_PAT; // tell the world we come from
if (pat_res.prot <= 2 || pat_res.prot == 6) {
flags |= TLBFlags::PAGE_WRITABLE;
}
if (is_write || pat_res.pte_c_status) {
// C-bit of the PTE is already set so the TLB logic
// doesn't need to update it anymore
flags |= TLBFlags::PTE_SET_C;
}
}
} else {
} else { // data translation disabled
phys_addr = guest_va;
flags = TLBFlags::PTE_SET_C; // no PTE.C updates in real addressing mode
flags |= TLBFlags::PAGE_WRITABLE; // assume physical pages are writable
}
// look up host virtual address
@ -848,11 +856,11 @@ static TLBEntry* tlb2_refill(uint32_t guest_va, int is_write)
// refill the secondary TLB
tlb_entry = tlb2_target_entry(tag);
tlb_entry->tag = tag;
if (reg_desc->type & RT_MMIO) {
tlb_entry->flags = 2; // MMIO region
if (reg_desc->type & RT_MMIO) { // MMIO region
tlb_entry->flags = flags | TLBFlags::PAGE_IO;
tlb_entry->reg_desc = reg_desc;
} else {
tlb_entry->flags = 1; // memory region backed by host memory
} else { // memory region backed by host memory
tlb_entry->flags = flags | TLBFlags::PAGE_MEM;
tlb_entry->host_va_offset = (int64_t)reg_desc->mem_ptr - guest_va +
(phys_addr - reg_desc->start);
}
@ -865,7 +873,7 @@ static TLBEntry* tlb2_refill(uint32_t guest_va, int is_write)
}
}
void flush_tlb_entry(uint32_t ea)
void tlb_flush_entry(uint32_t ea)
{
TLBEntry *tlb_entry, *tlb1, *tlb2;
@ -878,12 +886,12 @@ void flush_tlb_entry(uint32_t ea)
tlb2 = &mode1_tlb2[0];
break;
case 1:
tlb1 = &mode1_tlb1[0];
tlb2 = &mode1_tlb2[0];
tlb1 = &mode2_tlb1[0];
tlb2 = &mode2_tlb2[0];
break;
case 2:
tlb1 = &mode1_tlb1[0];
tlb2 = &mode1_tlb2[0];
tlb1 = &mode3_tlb1[0];
tlb2 = &mode3_tlb2[0];
break;
}
@ -905,6 +913,53 @@ void flush_tlb_entry(uint32_t ea)
}
}
void tlb_flush_entries(TLBFlags type)
{
int i;
// Flush BAT entries from the primary TLBs
for (i = 0; i < TLB_SIZE; i++) {
if (mode2_tlb1[i].flags & type) {
mode2_tlb1[i].tag = TLB_INVALID_TAG;
}
if (mode3_tlb1[i].flags & type) {
mode3_tlb1[i].tag = TLB_INVALID_TAG;
}
}
// Flush BAT entries from the secondary TLBs
for (i = 0; i < TLB_SIZE * TLB2_WAYS; i++) {
if (mode2_tlb2[i].flags & type) {
mode2_tlb2[i].tag = TLB_INVALID_TAG;
}
if (mode3_tlb2[i].flags & type) {
mode3_tlb2[i].tag = TLB_INVALID_TAG;
}
}
}
void tlb_flush_bat_entries()
{
if (!gTLBFlushBatEntries)
return;
tlb_flush_entries(TLBE_FROM_BAT);
gTLBFlushBatEntries = false;
}
void tlb_flush_pat_entries()
{
if (!gTLBFlushPatEntries)
return;
tlb_flush_entries(TLBE_FROM_PAT);
gTLBFlushPatEntries = false;
}
static inline uint64_t tlb_translate_addr(uint32_t guest_va)
{
TLBEntry *tlb1_entry, *tlb2_entry;
@ -951,10 +1006,10 @@ static inline uint64_t tlb_translate_addr(uint32_t guest_va)
tlb2_entry = tlb2_refill(guest_va, 0);
}
if (tlb2_entry->flags & 1) { // is it a real memory region?
if (tlb2_entry->flags & TLBFlags::PAGE_MEM) { // is it a real memory region?
// refill the primary TLB
tlb1_entry->tag = tag;
tlb1_entry->flags = 1;
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
MemAccessType = true;
MemAddr = tlb1_entry->host_va_offset + guest_va;
@ -1056,7 +1111,10 @@ static inline TLBEntry * lookup_secondary_tlb(uint32_t guest_va, uint32_t tag) {
return tlb_entry;
}
// Forward declarations.
static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t size);
static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value,
uint32_t size);
template <class T>
inline T mmu_read_vmem(uint32_t guest_va) {
@ -1078,10 +1136,10 @@ inline T mmu_read_vmem(uint32_t guest_va) {
tlb2_entry = tlb2_refill(guest_va, 0);
}
if (tlb2_entry->flags & 1) { // is it a real memory region?
if (tlb2_entry->flags & TLBFlags::PAGE_MEM) { // is it a real memory region?
// refill the primary TLB
tlb1_entry->tag = tag;
tlb1_entry->flags = 1;
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
} else { // otherwise, it's an access to a memory-mapped device
@ -1117,6 +1175,110 @@ template uint16_t mmu_read_vmem<uint16_t>(uint32_t guest_va);
template uint32_t mmu_read_vmem<uint32_t>(uint32_t guest_va);
template uint64_t mmu_read_vmem<uint64_t>(uint32_t guest_va);
template <class T>
inline void mmu_write_vmem(uint32_t guest_va, T value) {
TLBEntry *tlb1_entry, *tlb2_entry;
uint8_t *host_va;
const uint32_t tag = guest_va & ~0xFFFUL;
// look up guest virtual address in the primary TLB
tlb1_entry = &pCurTLB1[(guest_va >> PAGE_SIZE_BITS) & tlb_size_mask];
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
if (!(tlb1_entry->flags & TLBFlags::PAGE_WRITABLE)) {
ppc_state.spr[SPR::DSISR] = 0x08000000 | (1 << 25);
ppc_state.spr[SPR::DAR] = guest_va;
mmu_exception_handler(Except_Type::EXC_DSI, 0);
}
if (!(tlb1_entry->flags & TLBFlags::PTE_SET_C)) {
// perform full page address translation to update PTE.C bit
PATResult pat_res = page_address_translate(guest_va, false,
!!(ppc_state.msr & 0x4000), true);
tlb1_entry->flags |= TLBFlags::PTE_SET_C;
// don't forget to update the secondary TLB as well
tlb2_entry = lookup_secondary_tlb(guest_va, tag);
if (tlb2_entry != nullptr) {
tlb2_entry->flags |= TLBFlags::PTE_SET_C;
}
}
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
MemAccessType = true;
MemAddr = (uint64_t)host_va;
} else {
// primary TLB miss -> look up address in the secondary TLB
tlb2_entry = lookup_secondary_tlb(guest_va, tag);
if (tlb2_entry == nullptr) {
// secondary TLB miss ->
// perform full address translation and refill the secondary TLB
tlb2_entry = tlb2_refill(guest_va, 1);
}
if (!(tlb2_entry->flags & TLBFlags::PAGE_WRITABLE)) {
LOG_F(WARNING, "DSI Exception in mmu_write_vmem! PC=0x%08X", ppc_state.pc);
//return;
ppc_state.spr[SPR::DSISR] = 0x08000000 | (1 << 25);
ppc_state.spr[SPR::DAR] = guest_va;
mmu_exception_handler(Except_Type::EXC_DSI, 0);
}
if (!(tlb2_entry->flags & TLBFlags::PTE_SET_C)) {
// perform full page address translation to update PTE.C bit
PATResult pat_res = page_address_translate(guest_va, false,
!!(ppc_state.msr & 0x4000), true);
tlb2_entry->flags |= TLBFlags::PTE_SET_C;
}
if (tlb2_entry->flags & TLBFlags::PAGE_MEM) { // is it a real memory region?
// refill the primary TLB
tlb1_entry->tag = tag;
tlb1_entry->flags = tlb2_entry->flags;
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
//MemAccessType = true;
//MemAddr = (uint64_t)host_va;
} else { // otherwise, it's an access to a memory-mapped device
tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start,
guest_va - tlb2_entry->reg_desc->start, value, sizeof(T));
//MemAccessType = false;
//Device = tlb2_entry->reg_desc->devobj;
//DevOffset = guest_va - tlb2_entry->reg_desc->start;
return;
}
}
// handle unaligned memory accesses
if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) {
write_unaligned(guest_va, host_va, value, sizeof(T));
return;
}
#if 1
// handle aligned memory accesses
switch(sizeof(T)) {
case 1:
*host_va = value;
break;
case 2:
WRITE_WORD_BE_A(host_va, value);
break;
case 4:
WRITE_DWORD_BE_A(host_va, value);
break;
case 8:
WRITE_QWORD_BE_A(host_va, value);
break;
}
#endif
}
// explicitely instantiate all required mmu_write_vmem variants
// to avoid linking errors
template void mmu_write_vmem<uint8_t>(uint32_t guest_va, uint8_t value);
template void mmu_write_vmem<uint16_t>(uint32_t guest_va, uint16_t value);
template void mmu_write_vmem<uint32_t>(uint32_t guest_va, uint32_t value);
template void mmu_write_vmem<uint64_t>(uint32_t guest_va, uint64_t value);
static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t size)
{
uint32_t result = 0;
@ -1142,6 +1304,99 @@ static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t siz
return result;
}
static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value,
uint32_t size)
{
// is it a misaligned cross-page write?
if (((guest_va & 0xFFF) + size) > 0x1000) {
Unaligned_crosspage = true;
// Break such a memory access into multiple, bytewise accesses.
// Because such accesses suffer a performance penalty, they will be
// presumably very rare so don't waste time optimizing the code below.
uint32_t shift = (size - 1) * 8;
for (int i = 0; i < size; shift -= 8, guest_va++, i++) {
mmu_write_vmem<uint8_t>(guest_va, (value >> shift) & 0xFF);
}
} else {
Unaligned_crosspage = false;
#if 1
switch(size) {
case 2:
WRITE_WORD_BE_U(host_va, value);
break;
case 4:
WRITE_DWORD_BE_U(host_va, value);
break;
case 8: // FIXME: should we raise alignment exception here?
WRITE_QWORD_BE_U(host_va, value);
break;
}
#endif
}
}
void mem_write_byte(uint32_t addr, uint8_t value) {
mmu_write_vmem<uint8_t>(addr, value);
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint8_t, true>(&last_write_area, addr, value);
}
void mem_write_word(uint32_t addr, uint16_t value) {
mmu_write_vmem<uint16_t>(addr, value);
if (addr & 1) {
mem_write_unaligned(addr, value, 2);
return;
}
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint16_t, true>(&last_write_area, addr, value);
}
void mem_write_dword(uint32_t addr, uint32_t value) {
mmu_write_vmem<uint32_t>(addr, value);
if (addr & 3) {
mem_write_unaligned(addr, value, 4);
return;
}
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint32_t, true>(&last_write_area, addr, value);
}
void mem_write_qword(uint32_t addr, uint64_t value) {
mmu_write_vmem<uint64_t>(addr, value);
if (addr & 7) {
LOG_F(ERROR, "SOS! Attempt to write unaligned QWORD to 0x%08X\n", addr);
exit(-1); // FIXME!
}
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1);
}
write_phys_mem<uint64_t, true>(&last_write_area, addr, value);
}
/** Grab a value from memory into a register */
uint8_t mem_grab_byte(uint32_t addr) {
tlb_translate_addr(addr);

View File

@ -27,6 +27,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <array>
#include <cinttypes>
#include <vector>
#include "devices/memctrlbase.h"
/* Uncomment this to exhaustive MMU integrity checks. */
//#define MMU_INTEGRITY_CHECKS
@ -53,6 +54,36 @@ typedef struct BATResult {
uint32_t phys;
} BATResult;
/** Result of the page address translation. */
typedef struct PATResult {
uint32_t phys;
uint8_t prot;
uint8_t pte_c_status; // status of the C bit of the PTE
} PATResult;
#define PAGE_SIZE_BITS 12
#define TLB_SIZE 4096
#define TLB2_WAYS 4
#define TLB_INVALID_TAG 0xFFFFFFFF
typedef struct TLBEntry {
uint32_t tag;
uint16_t flags;
uint16_t lru_bits;
union {
int64_t host_va_offset;
AddressMapEntry* reg_desc;
};
} TLBEntry;
enum TLBFlags : uint16_t {
PAGE_MEM = 1 << 0, // memory page backed by host memory
PAGE_IO = 1 << 1, // memory mapped I/O page
TLBE_FROM_BAT = 1 << 2, // TLB entry has been translated with BAT
TLBE_FROM_PAT = 1 << 3, // TLB entry has been translated with PAT
PAGE_WRITABLE = 1 << 4, // page is writable
PTE_SET_C = 1 << 5, // tells if C bit of the PTE needs to be updated
};
extern void ibat_update(uint32_t bat_reg);
extern void dbat_update(uint32_t bat_reg);
@ -60,7 +91,10 @@ extern void dbat_update(uint32_t bat_reg);
extern uint8_t* mmu_get_dma_mem(uint32_t addr, uint32_t size);
extern void mmu_change_mode(void);
extern void flush_tlb_entry(uint32_t ea);
extern void mmu_pat_ctx_changed();
extern void tlb_flush_entry(uint32_t ea);
extern void tlb_flush_bat_entries();
extern void tlb_flush_pat_entries();
extern void ppc_set_cur_instruction(const uint8_t* ptr);
extern void mem_write_byte(uint32_t addr, uint8_t value);
@ -76,5 +110,7 @@ extern uint8_t* quickinstruction_translate(uint32_t address_grab);
template <class T>
extern T mmu_read_vmem(uint32_t guest_va);
template <class T>
extern void mmu_write_vmem(uint32_t guest_va, T value);
#endif // PPCMEMORY_H

View File

@ -26,12 +26,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <array>
#include <cinttypes>
#include <cstring>
#include <functional>
#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <thirdparty/loguru/loguru.hpp>
#include <thread>
#include <vector>
uint32_t crf_d;
uint32_t crf_s;
@ -188,6 +190,21 @@ inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) {
}
}
typedef std::function<void()> CtxSyncCallback;
std::vector<CtxSyncCallback> gCtxSyncCallbacks;
// perform context synchronization by executing registered actions if any
void do_ctx_sync() {
while (!gCtxSyncCallbacks.empty()) {
gCtxSyncCallbacks.back()();
gCtxSyncCallbacks.pop_back();
}
}
void add_ctx_sync_action(const CtxSyncCallback &cb) {
gCtxSyncCallbacks.push_back(cb);
}
/**
The core functionality of this PPC emulation is within all of these void functions.
This is where the opcode tables in the ppcemumain.h come into play - reducing the number of
@ -768,6 +785,7 @@ void dppc_interpreter::ppc_mtsr() {
reg_s = (ppc_cur_instruction >> 21) & 31;
grab_sr = (ppc_cur_instruction >> 16) & 15;
ppc_state.sr[grab_sr] = ppc_state.gpr[reg_s];
mmu_pat_ctx_changed();
}
}
@ -779,6 +797,7 @@ void dppc_interpreter::ppc_mtsrin() {
ppc_grab_regssb();
grab_sr = ppc_result_b >> 28;
ppc_state.sr[grab_sr] = ppc_result_d;
mmu_pat_ctx_changed();
}
}
@ -853,6 +872,11 @@ void dppc_interpreter::ppc_mtspr() {
ppc_state.spr[ref_spr] = ppc_state.gpr[reg_s];
}
if (ref_spr == SPR::SDR1) {
LOG_F(INFO, "SDR1 changed to 0x%08X", ppc_state.spr[SPR::SDR1]);
mmu_pat_ctx_changed();
}
switch (ref_spr) {
// Mirror the TBRs in the SPR range to the user-mode TBRs.
case 284:
@ -1320,7 +1344,7 @@ void dppc_interpreter::ppc_eieio() {
}
void dppc_interpreter::ppc_isync() {
/* placeholder */
do_ctx_sync();
}
void dppc_interpreter::ppc_sync() {
@ -1362,10 +1386,10 @@ void dppc_interpreter::ppc_dcbz() {
ppc_effective_address &= 0xFFFFFFE0; // align EA on a 32-byte boundary
mem_write_qword(ppc_effective_address, 0);
mem_write_qword((ppc_effective_address + 8), 0);
mem_write_qword((ppc_effective_address + 16), 0);
mem_write_qword((ppc_effective_address + 24), 0);
//mem_write_qword(ppc_effective_address, 0);
//mem_write_qword((ppc_effective_address + 8), 0);
//mem_write_qword((ppc_effective_address + 16), 0);
//mem_write_qword((ppc_effective_address + 24), 0);
}
@ -1378,7 +1402,8 @@ void dppc_interpreter::ppc_stb() {
ppc_grab_regssa();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += reg_a ? ppc_result_a : 0;
mem_write_byte(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint8_t>(ppc_effective_address, ppc_result_d);
//mem_write_byte(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_stbx() {
@ -1387,7 +1412,8 @@ void dppc_interpreter::ppc_stbx() {
#endif
ppc_grab_regssab();
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
mem_write_byte(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint8_t>(ppc_effective_address, ppc_result_d);
//mem_write_byte(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_stbu() {
@ -1398,7 +1424,8 @@ void dppc_interpreter::ppc_stbu() {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += ppc_result_a;
mem_write_byte(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint8_t>(ppc_effective_address, ppc_result_d);
//mem_write_byte(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1412,7 +1439,8 @@ void dppc_interpreter::ppc_stbux() {
ppc_grab_regssab();
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_byte(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint8_t>(ppc_effective_address, ppc_result_d);
//mem_write_byte(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1426,7 +1454,8 @@ void dppc_interpreter::ppc_sth() {
ppc_grab_regssa();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
mem_write_word(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint16_t>(ppc_effective_address, ppc_result_d);
//mem_write_word(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_sthu() {
@ -1437,7 +1466,8 @@ void dppc_interpreter::ppc_sthu() {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += ppc_result_a;
mem_write_word(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint16_t>(ppc_effective_address, ppc_result_d);
//mem_write_word(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1451,7 +1481,8 @@ void dppc_interpreter::ppc_sthux() {
ppc_grab_regssab();
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_word(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint16_t>(ppc_effective_address, ppc_result_d);
//mem_write_word(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1464,7 +1495,8 @@ void dppc_interpreter::ppc_sthx() {
#endif
ppc_grab_regssab();
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
mem_write_word(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint16_t>(ppc_effective_address, ppc_result_d);
//mem_write_word(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_sthbrx() {
@ -1474,8 +1506,10 @@ void dppc_interpreter::ppc_sthbrx() {
ppc_grab_regssab();
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
ppc_result_d = (uint32_t)(BYTESWAP_16((uint16_t)ppc_result_d));
mem_write_word(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint16_t>(ppc_effective_address, ppc_result_d);
//mem_write_word(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_stw() {
#ifdef CPU_PROFILING
num_int_stores++;
@ -1483,7 +1517,8 @@ void dppc_interpreter::ppc_stw() {
ppc_grab_regssa();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += reg_a ? ppc_result_a : 0;
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_stwx() {
@ -1492,7 +1527,8 @@ void dppc_interpreter::ppc_stwx() {
#endif
ppc_grab_regssab();
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_stwcx() {
@ -1506,7 +1542,8 @@ void dppc_interpreter::ppc_stwcx() {
ppc_grab_regssab();
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
if (ppc_state.reserve) {
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000;
ppc_state.reserve = false;
} else {
@ -1523,7 +1560,8 @@ void dppc_interpreter::ppc_stwu() {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += ppc_result_a;
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1537,7 +1575,8 @@ void dppc_interpreter::ppc_stwux() {
ppc_grab_regssab();
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1551,7 +1590,8 @@ void dppc_interpreter::ppc_stwbrx() {
ppc_grab_regssab();
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
ppc_result_d = BYTESWAP_32(ppc_result_d);
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
}
void dppc_interpreter::ppc_stmw() {
@ -1568,7 +1608,8 @@ void dppc_interpreter::ppc_stmw() {
}
for (; reg_s <= 31; reg_s++) {
mem_write_dword(ppc_effective_address, ppc_state.gpr[reg_s]);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_state.gpr[reg_s]);
//mem_write_dword(ppc_effective_address, ppc_state.gpr[reg_s]);
ppc_effective_address += 4;
}
}
@ -1886,20 +1927,26 @@ void dppc_interpreter::ppc_lswi() {
while (grab_inb > 0) {
switch (grab_inb) {
case 1:
stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word = mmu_read_vmem<uint8_t>(ppc_effective_address) << 24;
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
ppc_state.gpr[reg_d] = stringed_word;
grab_inb = 0;
break;
case 2:
stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
stringed_word = mmu_read_vmem<uint8_t>(ppc_effective_address) << 24;
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mmu_read_vmem<uint8_t>(ppc_effective_address + 1) << 16;
//stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
ppc_state.gpr[reg_d] = stringed_word;
grab_inb = 0;
break;
case 3:
stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
stringed_word += mem_grab_byte(ppc_effective_address + 2) << 8;
stringed_word = mmu_read_vmem<uint8_t>(ppc_effective_address) << 24;
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mmu_read_vmem<uint8_t>(ppc_effective_address + 1) << 16;
//stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
stringed_word += mmu_read_vmem<uint8_t>(ppc_effective_address + 2) << 8;
//stringed_word += mem_grab_byte(ppc_effective_address + 2) << 8;
ppc_state.gpr[reg_d] = stringed_word;
grab_inb = 0;
break;
@ -1934,20 +1981,26 @@ void dppc_interpreter::ppc_lswx() {
while (grab_inb > 0) {
switch (grab_inb) {
case 1:
stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word = mmu_read_vmem<uint8_t>(ppc_effective_address) << 24;
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
ppc_state.gpr[reg_d] = stringed_word;
grab_inb = 0;
break;
case 2:
stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
stringed_word = mmu_read_vmem<uint8_t>(ppc_effective_address) << 24;
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mmu_read_vmem<uint8_t>(ppc_effective_address + 1) << 16;
//stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
ppc_state.gpr[reg_d] = stringed_word;
grab_inb = 0;
break;
case 3:
stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
stringed_word += mem_grab_byte(ppc_effective_address + 2) << 8;
stringed_word = mmu_read_vmem<uint8_t>(ppc_effective_address) << 24;
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
stringed_word += mmu_read_vmem<uint8_t>(ppc_effective_address + 1) << 16;
//stringed_word += mem_grab_byte(ppc_effective_address + 1) << 16;
stringed_word += mmu_read_vmem<uint8_t>(ppc_effective_address + 2) << 8;
//stringed_word += mem_grab_byte(ppc_effective_address + 2) << 8;
ppc_state.gpr[reg_d] = stringed_word;
grab_inb = 0;
break;
@ -1973,22 +2026,29 @@ void dppc_interpreter::ppc_stswi() {
while (grab_inb > 0) {
switch (grab_inb) {
case 1:
mem_write_byte(ppc_effective_address, (ppc_result_d >> 24));
mmu_write_vmem<uint8_t>(ppc_effective_address, (ppc_result_d >> 24));
//mem_write_byte(ppc_effective_address, (ppc_result_d >> 24));
grab_inb = 0;
break;
case 2:
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
mmu_write_vmem<uint8_t>(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
//mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mmu_write_vmem<uint8_t>((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
//mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
grab_inb = 0;
break;
case 3:
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
mem_write_byte((ppc_effective_address + 2), ((ppc_result_d >> 8) & 0xFF));
mmu_write_vmem<uint8_t>(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
//mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mmu_write_vmem<uint8_t>((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
//mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
mmu_write_vmem<uint8_t>((ppc_effective_address + 2), ((ppc_result_d >> 8) & 0xFF));
//mem_write_byte((ppc_effective_address + 2), ((ppc_result_d >> 8) & 0xFF));
grab_inb = 0;
break;
default:
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
reg_s++;
ppc_effective_address += 4;
grab_inb -= 4;
@ -2007,22 +2067,29 @@ void dppc_interpreter::ppc_stswx() {
while (grab_inb > 0) {
switch (grab_inb) {
case 1:
mem_write_byte(ppc_effective_address, (ppc_result_d >> 24));
mmu_write_vmem<uint8_t>(ppc_effective_address, (ppc_result_d >> 24));
//mem_write_byte(ppc_effective_address, (ppc_result_d >> 24));
grab_inb = 0;
break;
case 2:
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
mmu_write_vmem<uint8_t>(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
//mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mmu_write_vmem<uint8_t>((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
//mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
grab_inb = 0;
break;
case 3:
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
mem_write_byte((ppc_effective_address + 2), ((ppc_result_d >> 8) & 0xFF));
mmu_write_vmem<uint8_t>(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
//mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
mmu_write_vmem<uint8_t>((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
//mem_write_byte((ppc_effective_address + 1), ((ppc_result_d >> 16) & 0xFF));
mmu_write_vmem<uint8_t>((ppc_effective_address + 2), ((ppc_result_d >> 8) & 0xFF));
//mem_write_byte((ppc_effective_address + 2), ((ppc_result_d >> 8) & 0xFF));
grab_inb = 0;
break;
default:
mem_write_dword(ppc_effective_address, ppc_result_d);
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
//mem_write_dword(ppc_effective_address, ppc_result_d);
reg_s++;
ppc_effective_address += 4;
grab_inb -= 4;
@ -2037,7 +2104,7 @@ void dppc_interpreter::ppc_tlbie() {
num_supervisor_instrs++;
#endif
flush_tlb_entry(ppc_state.gpr[(ppc_cur_instruction >> 11) & 31]);
tlb_flush_entry(ppc_state.gpr[(ppc_cur_instruction >> 11) & 31]);
}
void dppc_interpreter::ppc_tlbia() {

View File

@ -118,8 +118,10 @@ int main(int argc, char** argv) {
loguru::init(argc, argv);
loguru::add_file("dingusppc.log", loguru::Append, 0);
} else {
loguru::g_stderr_verbosity = 0;
loguru::g_preamble_uptime = false;
loguru::g_stderr_verbosity = loguru::Verbosity_INFO;
loguru::init(argc, argv);
loguru::add_file("exceptions.log", loguru::Truncate, -7);
}
if (*machine_opt) {