mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-09-29 17:56:59 +00:00
Implement SoftTLB for writes.
This commit is contained in:
parent
4f3dd797be
commit
089645e830
@ -148,22 +148,26 @@ void dppc_interpreter::power_lscbx() {
|
|||||||
if (match_found == false) {
|
if (match_found == false) {
|
||||||
switch (shift_amount) {
|
switch (shift_amount) {
|
||||||
case 0:
|
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_result_d = (ppc_result_d & 0x00FFFFFF) | (return_value << 24);
|
||||||
ppc_store_result_regd();
|
ppc_store_result_regd();
|
||||||
break;
|
break;
|
||||||
case 1:
|
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_result_d = (ppc_result_d & 0xFF00FFFF) | (return_value << 16);
|
||||||
ppc_store_result_regd();
|
ppc_store_result_regd();
|
||||||
break;
|
break;
|
||||||
case 2:
|
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_result_d = (ppc_result_d & 0xFFFF00FF) | (return_value << 8);
|
||||||
ppc_store_result_regd();
|
ppc_store_result_regd();
|
||||||
break;
|
break;
|
||||||
case 3:
|
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_result_d = (ppc_result_d & 0xFFFFFF00) | return_value;
|
||||||
ppc_store_result_regd();
|
ppc_store_result_regd();
|
||||||
break;
|
break;
|
||||||
|
@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include "devices/memctrlbase.h"
|
#include "devices/memctrlbase.h"
|
||||||
#include "endianswap.h"
|
#include "endianswap.h"
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <functional>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -301,6 +302,9 @@ void ppc_fp_changecrf1();
|
|||||||
// MEMORY DECLARATIONS
|
// MEMORY DECLARATIONS
|
||||||
extern MemCtrlBase* mem_ctrl_instance;
|
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
|
// The functions used by the PowerPC processor
|
||||||
namespace dppc_interpreter {
|
namespace dppc_interpreter {
|
||||||
extern void ppc_bcctr();
|
extern void ppc_bcctr();
|
||||||
|
@ -735,7 +735,8 @@ void dppc_interpreter::ppc_lfs() {
|
|||||||
ppc_grab_regsfpdia();
|
ppc_grab_regsfpdia();
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += (reg_a) ? val_reg_a : 0;
|
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_store_sfpresult_int(reg_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,7 +746,8 @@ void dppc_interpreter::ppc_lfsu() {
|
|||||||
if (reg_a) {
|
if (reg_a) {
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += (reg_a) ? val_reg_a : 0;
|
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_store_sfpresult_int(reg_d);
|
||||||
ppc_state.gpr[reg_a] = ppc_effective_address;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
@ -756,7 +758,8 @@ void dppc_interpreter::ppc_lfsu() {
|
|||||||
void dppc_interpreter::ppc_lfsx() {
|
void dppc_interpreter::ppc_lfsx() {
|
||||||
ppc_grab_regsfpdiab();
|
ppc_grab_regsfpdiab();
|
||||||
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
|
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);
|
ppc_store_sfpresult_int(reg_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -764,7 +767,8 @@ void dppc_interpreter::ppc_lfsux() {
|
|||||||
ppc_grab_regsfpdiab();
|
ppc_grab_regsfpdiab();
|
||||||
if (reg_a) {
|
if (reg_a) {
|
||||||
ppc_effective_address = val_reg_a + val_reg_b;
|
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_store_sfpresult_int(reg_d);
|
||||||
ppc_state.gpr[reg_a] = ppc_effective_address;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
@ -820,7 +824,8 @@ void dppc_interpreter::ppc_stfs() {
|
|||||||
ppc_grab_regsfpsia();
|
ppc_grab_regsfpsia();
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += (reg_a) ? val_reg_a : 0;
|
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() {
|
void dppc_interpreter::ppc_stfsu() {
|
||||||
@ -828,7 +833,8 @@ void dppc_interpreter::ppc_stfsu() {
|
|||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += val_reg_a;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
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() {
|
void dppc_interpreter::ppc_stfsx() {
|
||||||
ppc_grab_regsfpsiab();
|
ppc_grab_regsfpsiab();
|
||||||
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
|
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() {
|
void dppc_interpreter::ppc_stfsux() {
|
||||||
ppc_grab_regsfpsiab();
|
ppc_grab_regsfpsiab();
|
||||||
if (reg_a) {
|
if (reg_a) {
|
||||||
ppc_effective_address = val_reg_a + val_reg_b;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -856,7 +864,8 @@ void dppc_interpreter::ppc_stfd() {
|
|||||||
ppc_grab_regsfpsia();
|
ppc_grab_regsfpsia();
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += (reg_a) ? val_reg_a : 0;
|
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() {
|
void dppc_interpreter::ppc_stfdu() {
|
||||||
@ -864,7 +873,8 @@ void dppc_interpreter::ppc_stfdu() {
|
|||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += val_reg_a;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
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() {
|
void dppc_interpreter::ppc_stfdx() {
|
||||||
ppc_grab_regsfpsiab();
|
ppc_grab_regsfpsiab();
|
||||||
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
|
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() {
|
void dppc_interpreter::ppc_stfdux() {
|
||||||
ppc_grab_regsfpsiab();
|
ppc_grab_regsfpsiab();
|
||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = val_reg_a + val_reg_b;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
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() {
|
void dppc_interpreter::ppc_stfiwx() {
|
||||||
ppc_grab_regsfpsiab();
|
ppc_grab_regsfpsiab();
|
||||||
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
|
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
|
// Floating Point Register Transfer
|
||||||
|
@ -137,6 +137,7 @@ public:
|
|||||||
|
|
||||||
/** Temporary TLB test variables. */
|
/** Temporary TLB test variables. */
|
||||||
bool MemAccessType; // true - memory, false - I/O
|
bool MemAccessType; // true - memory, false - I/O
|
||||||
|
bool Unaligned_crosspage = false;
|
||||||
uint64_t MemAddr = 0;
|
uint64_t MemAddr = 0;
|
||||||
MMIODevice *Device = 0;
|
MMIODevice *Device = 0;
|
||||||
uint32_t DevOffset = 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
|
#ifdef MMU_PROFILING
|
||||||
dmem_writes_total++;
|
dmem_writes_total++;
|
||||||
#endif
|
#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)) {
|
switch(sizeof(T)) {
|
||||||
case 1:
|
case 1:
|
||||||
*(mru_rgn->mem_ptr + (addr - mru_rgn->start)) = value;
|
*(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
|
#ifdef MMU_PROFILING
|
||||||
iomem_writes_total++;
|
iomem_writes_total++;
|
||||||
#endif
|
#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,
|
mru_rgn->devobj->write(mru_rgn->start, addr - mru_rgn->start, value,
|
||||||
sizeof(T));
|
sizeof(T));
|
||||||
} else {
|
} else {
|
||||||
@ -298,6 +326,9 @@ void ppc_set_cur_instruction(const uint8_t* ptr) {
|
|||||||
ppc_cur_instruction = READ_DWORD_BE_A(ptr);
|
ppc_cur_instruction = READ_DWORD_BE_A(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool gTLBFlushBatEntries = false;
|
||||||
|
bool gTLBFlushPatEntries = false;
|
||||||
|
|
||||||
void ibat_update(uint32_t bat_reg) {
|
void ibat_update(uint32_t bat_reg) {
|
||||||
int upper_reg_num;
|
int upper_reg_num;
|
||||||
uint32_t bl, hi_mask;
|
uint32_t bl, hi_mask;
|
||||||
@ -335,6 +366,19 @@ void dbat_update(uint32_t bat_reg) {
|
|||||||
bat_entry->hi_mask = hi_mask;
|
bat_entry->hi_mask = hi_mask;
|
||||||
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & 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;
|
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;
|
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;
|
uint32_t sr_val, page_index, pteg_hash1, vsid, pte_word2;
|
||||||
unsigned key, pp;
|
unsigned key, pp;
|
||||||
uint8_t* pte_addr;
|
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;
|
pte_addr[7] |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return physical address */
|
/* return physical address, access protection and C status */
|
||||||
return ((pte_word2 & 0xFFFFF000) | (la & 0x00000FFF));
|
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. */
|
/** PowerPC-style MMU instruction address translation. */
|
||||||
@ -535,7 +585,8 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la) {
|
|||||||
|
|
||||||
/* page address translation */
|
/* page address translation */
|
||||||
if (!bat_hit) {
|
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
|
#ifdef MMU_PROFILING
|
||||||
ptab_transl_total++;
|
ptab_transl_total++;
|
||||||
@ -581,7 +632,8 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) {
|
|||||||
|
|
||||||
/* page address translation */
|
/* page address translation */
|
||||||
if (!bat_hit) {
|
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
|
#ifdef MMU_PROFILING
|
||||||
ptab_transl_total++;
|
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
|
// primary TLB for all MMU modes
|
||||||
static std::array<TLBEntry, TLB_SIZE> mode1_tlb1;
|
static std::array<TLBEntry, TLB_SIZE> mode1_tlb1;
|
||||||
static std::array<TLBEntry, TLB_SIZE> mode2_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;
|
uint64_t UnmappedVal = -1ULL;
|
||||||
TLBEntry UnmappedMem = {TLB_INVALID_TAG, 0, 0, 0};
|
TLBEntry UnmappedMem = {TLB_INVALID_TAG, 0, 0, 0};
|
||||||
|
|
||||||
uint8_t MMUMode = {0xFF};
|
uint8_t CurMMUMode = {0xFF}; // current MMU mode
|
||||||
|
|
||||||
void mmu_change_mode()
|
void mmu_change_mode()
|
||||||
{
|
{
|
||||||
uint8_t mmu_mode = ((ppc_state.msr >> 3) & 0x2) | ((ppc_state.msr >> 14) & 1);
|
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) {
|
switch(mmu_mode) {
|
||||||
case 0: // real address mode
|
case 0: // real address mode
|
||||||
pCurTLB1 = &mode1_tlb1[0];
|
pCurTLB1 = &mode1_tlb1[0];
|
||||||
@ -742,7 +727,7 @@ void mmu_change_mode()
|
|||||||
pCurTLB2 = &mode3_tlb2[0];
|
pCurTLB2 = &mode3_tlb2[0];
|
||||||
break;
|
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)
|
static TLBEntry* tlb2_refill(uint32_t guest_va, int is_write)
|
||||||
{
|
{
|
||||||
uint32_t phys_addr;
|
uint32_t phys_addr;
|
||||||
|
uint16_t flags = 0;
|
||||||
TLBEntry *tlb_entry;
|
TLBEntry *tlb_entry;
|
||||||
|
|
||||||
const uint32_t tag = guest_va & ~0xFFFUL;
|
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) {
|
if (bat_res.hit) {
|
||||||
// check block protection
|
// check block protection
|
||||||
if (!bat_res.prot || ((bat_res.prot & 1) && is_write)) {
|
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::DSISR] = 0x08000000 | (is_write << 25);
|
||||||
ppc_state.spr[SPR::DAR] = guest_va;
|
ppc_state.spr[SPR::DAR] = guest_va;
|
||||||
mmu_exception_handler(Except_Type::EXC_DSI, 0);
|
mmu_exception_handler(Except_Type::EXC_DSI, 0);
|
||||||
}
|
}
|
||||||
phys_addr = bat_res.phys;
|
phys_addr = bat_res.phys;
|
||||||
} else {
|
flags = TLBFlags::PTE_SET_C; // prevent PTE.C updates for BAT
|
||||||
// page address translation
|
flags |= TLBFlags::TLBE_FROM_BAT; // tell the world we come from
|
||||||
phys_addr = page_address_translate(guest_va, false,
|
if (bat_res.prot == 2) {
|
||||||
!!(ppc_state.msr & 0x4000), is_write);
|
flags |= TLBFlags::PAGE_WRITABLE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// page address translation
|
||||||
|
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 { // data translation disabled
|
||||||
phys_addr = guest_va;
|
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
|
// look up host virtual address
|
||||||
@ -848,11 +856,11 @@ static TLBEntry* tlb2_refill(uint32_t guest_va, int is_write)
|
|||||||
// refill the secondary TLB
|
// refill the secondary TLB
|
||||||
tlb_entry = tlb2_target_entry(tag);
|
tlb_entry = tlb2_target_entry(tag);
|
||||||
tlb_entry->tag = tag;
|
tlb_entry->tag = tag;
|
||||||
if (reg_desc->type & RT_MMIO) {
|
if (reg_desc->type & RT_MMIO) { // MMIO region
|
||||||
tlb_entry->flags = 2; // MMIO region
|
tlb_entry->flags = flags | TLBFlags::PAGE_IO;
|
||||||
tlb_entry->reg_desc = reg_desc;
|
tlb_entry->reg_desc = reg_desc;
|
||||||
} else {
|
} else { // memory region backed by host memory
|
||||||
tlb_entry->flags = 1; // 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 +
|
tlb_entry->host_va_offset = (int64_t)reg_desc->mem_ptr - guest_va +
|
||||||
(phys_addr - reg_desc->start);
|
(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;
|
TLBEntry *tlb_entry, *tlb1, *tlb2;
|
||||||
|
|
||||||
@ -878,12 +886,12 @@ void flush_tlb_entry(uint32_t ea)
|
|||||||
tlb2 = &mode1_tlb2[0];
|
tlb2 = &mode1_tlb2[0];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
tlb1 = &mode1_tlb1[0];
|
tlb1 = &mode2_tlb1[0];
|
||||||
tlb2 = &mode1_tlb2[0];
|
tlb2 = &mode2_tlb2[0];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
tlb1 = &mode1_tlb1[0];
|
tlb1 = &mode3_tlb1[0];
|
||||||
tlb2 = &mode1_tlb2[0];
|
tlb2 = &mode3_tlb2[0];
|
||||||
break;
|
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)
|
static inline uint64_t tlb_translate_addr(uint32_t guest_va)
|
||||||
{
|
{
|
||||||
TLBEntry *tlb1_entry, *tlb2_entry;
|
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);
|
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
|
// refill the primary TLB
|
||||||
tlb1_entry->tag = tag;
|
tlb1_entry->tag = tag;
|
||||||
tlb1_entry->flags = 1;
|
tlb1_entry->flags = tlb2_entry->flags;
|
||||||
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
|
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
|
||||||
MemAccessType = true;
|
MemAccessType = true;
|
||||||
MemAddr = tlb1_entry->host_va_offset + guest_va;
|
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;
|
return tlb_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward declarations.
|
||||||
static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t size);
|
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>
|
template <class T>
|
||||||
inline T mmu_read_vmem(uint32_t guest_va) {
|
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);
|
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
|
// refill the primary TLB
|
||||||
tlb1_entry->tag = tag;
|
tlb1_entry->tag = tag;
|
||||||
tlb1_entry->flags = 1;
|
tlb1_entry->flags = tlb2_entry->flags;
|
||||||
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
|
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
|
||||||
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
|
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
|
||||||
} else { // otherwise, it's an access to a memory-mapped device
|
} 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 uint32_t mmu_read_vmem<uint32_t>(uint32_t guest_va);
|
||||||
template uint64_t mmu_read_vmem<uint64_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)
|
static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t result = 0;
|
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;
|
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 */
|
/** Grab a value from memory into a register */
|
||||||
uint8_t mem_grab_byte(uint32_t addr) {
|
uint8_t mem_grab_byte(uint32_t addr) {
|
||||||
tlb_translate_addr(addr);
|
tlb_translate_addr(addr);
|
||||||
|
@ -27,6 +27,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "devices/memctrlbase.h"
|
||||||
|
|
||||||
/* Uncomment this to exhaustive MMU integrity checks. */
|
/* Uncomment this to exhaustive MMU integrity checks. */
|
||||||
//#define MMU_INTEGRITY_CHECKS
|
//#define MMU_INTEGRITY_CHECKS
|
||||||
@ -53,6 +54,36 @@ typedef struct BATResult {
|
|||||||
uint32_t phys;
|
uint32_t phys;
|
||||||
} BATResult;
|
} 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 ibat_update(uint32_t bat_reg);
|
||||||
extern void dbat_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 uint8_t* mmu_get_dma_mem(uint32_t addr, uint32_t size);
|
||||||
|
|
||||||
extern void mmu_change_mode(void);
|
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 ppc_set_cur_instruction(const uint8_t* ptr);
|
||||||
extern void mem_write_byte(uint32_t addr, uint8_t value);
|
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>
|
template <class T>
|
||||||
extern T mmu_read_vmem(uint32_t guest_va);
|
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
|
#endif // PPCMEMORY_H
|
||||||
|
@ -26,12 +26,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <thirdparty/loguru/loguru.hpp>
|
#include <thirdparty/loguru/loguru.hpp>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
uint32_t crf_d;
|
uint32_t crf_d;
|
||||||
uint32_t crf_s;
|
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.
|
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
|
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;
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
||||||
grab_sr = (ppc_cur_instruction >> 16) & 15;
|
grab_sr = (ppc_cur_instruction >> 16) & 15;
|
||||||
ppc_state.sr[grab_sr] = ppc_state.gpr[reg_s];
|
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();
|
ppc_grab_regssb();
|
||||||
grab_sr = ppc_result_b >> 28;
|
grab_sr = ppc_result_b >> 28;
|
||||||
ppc_state.sr[grab_sr] = ppc_result_d;
|
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];
|
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) {
|
switch (ref_spr) {
|
||||||
// Mirror the TBRs in the SPR range to the user-mode TBRs.
|
// Mirror the TBRs in the SPR range to the user-mode TBRs.
|
||||||
case 284:
|
case 284:
|
||||||
@ -1320,7 +1344,7 @@ void dppc_interpreter::ppc_eieio() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dppc_interpreter::ppc_isync() {
|
void dppc_interpreter::ppc_isync() {
|
||||||
/* placeholder */
|
do_ctx_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dppc_interpreter::ppc_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
|
ppc_effective_address &= 0xFFFFFFE0; // align EA on a 32-byte boundary
|
||||||
|
|
||||||
mem_write_qword(ppc_effective_address, 0);
|
//mem_write_qword(ppc_effective_address, 0);
|
||||||
mem_write_qword((ppc_effective_address + 8), 0);
|
//mem_write_qword((ppc_effective_address + 8), 0);
|
||||||
mem_write_qword((ppc_effective_address + 16), 0);
|
//mem_write_qword((ppc_effective_address + 16), 0);
|
||||||
mem_write_qword((ppc_effective_address + 24), 0);
|
//mem_write_qword((ppc_effective_address + 24), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1378,7 +1402,8 @@ void dppc_interpreter::ppc_stb() {
|
|||||||
ppc_grab_regssa();
|
ppc_grab_regssa();
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += reg_a ? ppc_result_a : 0;
|
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() {
|
void dppc_interpreter::ppc_stbx() {
|
||||||
@ -1387,7 +1412,8 @@ void dppc_interpreter::ppc_stbx() {
|
|||||||
#endif
|
#endif
|
||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
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() {
|
void dppc_interpreter::ppc_stbu() {
|
||||||
@ -1398,7 +1424,8 @@ void dppc_interpreter::ppc_stbu() {
|
|||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += ppc_result_a;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1412,7 +1439,8 @@ void dppc_interpreter::ppc_stbux() {
|
|||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1426,7 +1454,8 @@ void dppc_interpreter::ppc_sth() {
|
|||||||
ppc_grab_regssa();
|
ppc_grab_regssa();
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
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() {
|
void dppc_interpreter::ppc_sthu() {
|
||||||
@ -1437,7 +1466,8 @@ void dppc_interpreter::ppc_sthu() {
|
|||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += ppc_result_a;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1451,7 +1481,8 @@ void dppc_interpreter::ppc_sthux() {
|
|||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1464,7 +1495,8 @@ void dppc_interpreter::ppc_sthx() {
|
|||||||
#endif
|
#endif
|
||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
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() {
|
void dppc_interpreter::ppc_sthbrx() {
|
||||||
@ -1474,8 +1506,10 @@ void dppc_interpreter::ppc_sthbrx() {
|
|||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
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));
|
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() {
|
void dppc_interpreter::ppc_stw() {
|
||||||
#ifdef CPU_PROFILING
|
#ifdef CPU_PROFILING
|
||||||
num_int_stores++;
|
num_int_stores++;
|
||||||
@ -1483,7 +1517,8 @@ void dppc_interpreter::ppc_stw() {
|
|||||||
ppc_grab_regssa();
|
ppc_grab_regssa();
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += reg_a ? ppc_result_a : 0;
|
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() {
|
void dppc_interpreter::ppc_stwx() {
|
||||||
@ -1492,7 +1527,8 @@ void dppc_interpreter::ppc_stwx() {
|
|||||||
#endif
|
#endif
|
||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
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() {
|
void dppc_interpreter::ppc_stwcx() {
|
||||||
@ -1506,7 +1542,8 @@ void dppc_interpreter::ppc_stwcx() {
|
|||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
||||||
if (ppc_state.reserve) {
|
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.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000;
|
||||||
ppc_state.reserve = false;
|
ppc_state.reserve = false;
|
||||||
} else {
|
} else {
|
||||||
@ -1523,7 +1560,8 @@ void dppc_interpreter::ppc_stwu() {
|
|||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||||
ppc_effective_address += ppc_result_a;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1537,7 +1575,8 @@ void dppc_interpreter::ppc_stwux() {
|
|||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
if (reg_a != 0) {
|
if (reg_a != 0) {
|
||||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
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;
|
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||||
} else {
|
} else {
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1551,7 +1590,8 @@ void dppc_interpreter::ppc_stwbrx() {
|
|||||||
ppc_grab_regssab();
|
ppc_grab_regssab();
|
||||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||||
ppc_result_d = BYTESWAP_32(ppc_result_d);
|
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() {
|
void dppc_interpreter::ppc_stmw() {
|
||||||
@ -1568,7 +1608,8 @@ void dppc_interpreter::ppc_stmw() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (; reg_s <= 31; reg_s++) {
|
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;
|
ppc_effective_address += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1886,20 +1927,26 @@ void dppc_interpreter::ppc_lswi() {
|
|||||||
while (grab_inb > 0) {
|
while (grab_inb > 0) {
|
||||||
switch (grab_inb) {
|
switch (grab_inb) {
|
||||||
case 1:
|
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;
|
ppc_state.gpr[reg_d] = stringed_word;
|
||||||
grab_inb = 0;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
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 + 1) << 16;
|
//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;
|
ppc_state.gpr[reg_d] = stringed_word;
|
||||||
grab_inb = 0;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
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 + 1) << 16;
|
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
|
||||||
stringed_word += mem_grab_byte(ppc_effective_address + 2) << 8;
|
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;
|
ppc_state.gpr[reg_d] = stringed_word;
|
||||||
grab_inb = 0;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
@ -1934,20 +1981,26 @@ void dppc_interpreter::ppc_lswx() {
|
|||||||
while (grab_inb > 0) {
|
while (grab_inb > 0) {
|
||||||
switch (grab_inb) {
|
switch (grab_inb) {
|
||||||
case 1:
|
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;
|
ppc_state.gpr[reg_d] = stringed_word;
|
||||||
grab_inb = 0;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
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 + 1) << 16;
|
//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;
|
ppc_state.gpr[reg_d] = stringed_word;
|
||||||
grab_inb = 0;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
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 + 1) << 16;
|
//stringed_word = mem_grab_byte(ppc_effective_address) << 24;
|
||||||
stringed_word += mem_grab_byte(ppc_effective_address + 2) << 8;
|
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;
|
ppc_state.gpr[reg_d] = stringed_word;
|
||||||
grab_inb = 0;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
@ -1973,22 +2026,29 @@ void dppc_interpreter::ppc_stswi() {
|
|||||||
while (grab_inb > 0) {
|
while (grab_inb > 0) {
|
||||||
switch (grab_inb) {
|
switch (grab_inb) {
|
||||||
case 1:
|
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;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
|
mmu_write_vmem<uint8_t>(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, ((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;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
|
mmu_write_vmem<uint8_t>(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, ((ppc_result_d >> 24) & 0xFF));
|
||||||
mem_write_byte((ppc_effective_address + 2), ((ppc_result_d >> 8) & 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;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
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++;
|
reg_s++;
|
||||||
ppc_effective_address += 4;
|
ppc_effective_address += 4;
|
||||||
grab_inb -= 4;
|
grab_inb -= 4;
|
||||||
@ -2007,22 +2067,29 @@ void dppc_interpreter::ppc_stswx() {
|
|||||||
while (grab_inb > 0) {
|
while (grab_inb > 0) {
|
||||||
switch (grab_inb) {
|
switch (grab_inb) {
|
||||||
case 1:
|
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;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
|
mmu_write_vmem<uint8_t>(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, ((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;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
mem_write_byte(ppc_effective_address, ((ppc_result_d >> 24) & 0xFF));
|
mmu_write_vmem<uint8_t>(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, ((ppc_result_d >> 24) & 0xFF));
|
||||||
mem_write_byte((ppc_effective_address + 2), ((ppc_result_d >> 8) & 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;
|
grab_inb = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
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++;
|
reg_s++;
|
||||||
ppc_effective_address += 4;
|
ppc_effective_address += 4;
|
||||||
grab_inb -= 4;
|
grab_inb -= 4;
|
||||||
@ -2037,7 +2104,7 @@ void dppc_interpreter::ppc_tlbie() {
|
|||||||
num_supervisor_instrs++;
|
num_supervisor_instrs++;
|
||||||
#endif
|
#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() {
|
void dppc_interpreter::ppc_tlbia() {
|
||||||
|
4
main.cpp
4
main.cpp
@ -118,8 +118,10 @@ int main(int argc, char** argv) {
|
|||||||
loguru::init(argc, argv);
|
loguru::init(argc, argv);
|
||||||
loguru::add_file("dingusppc.log", loguru::Append, 0);
|
loguru::add_file("dingusppc.log", loguru::Append, 0);
|
||||||
} else {
|
} else {
|
||||||
loguru::g_stderr_verbosity = 0;
|
loguru::g_preamble_uptime = false;
|
||||||
|
loguru::g_stderr_verbosity = loguru::Verbosity_INFO;
|
||||||
loguru::init(argc, argv);
|
loguru::init(argc, argv);
|
||||||
|
loguru::add_file("exceptions.log", loguru::Truncate, -7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*machine_opt) {
|
if (*machine_opt) {
|
||||||
|
Loading…
Reference in New Issue
Block a user