Merge branch 'soft-tlb'.
This commit is contained in:
commit
4b16cb826e
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -22,6 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
/** @file Handling of low-level PPC exceptions. */
|
||||
|
||||
#include "ppcemu.h"
|
||||
#include "ppcmmu.h"
|
||||
#include <setjmp.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
@ -109,6 +110,8 @@ jmp_buf exc_env; /* Global exception environment. */
|
|||
ppc_next_instruction_address |= 0xFFF00000;
|
||||
}
|
||||
|
||||
mmu_change_mode();
|
||||
|
||||
longjmp(exc_env, 2); /* return to the main execution loop. */
|
||||
}
|
||||
|
||||
|
|
|
@ -309,7 +309,8 @@ void ppc_exec()
|
|||
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
|
||||
#endif
|
||||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
//pc_real = mmu_translate_imem(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
ppc_state.pc = bb_start_la;
|
||||
bb_kind = BB_end_kind::BB_NONE;
|
||||
|
@ -317,7 +318,8 @@ void ppc_exec()
|
|||
}
|
||||
|
||||
/* initial MMU translation for the current code page. */
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
//pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
|
||||
/* set current code page limits */
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
|
@ -335,7 +337,7 @@ again:
|
|||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
} else {
|
||||
pc_real += (int)bb_start_la - (int)ppc_state.pc;
|
||||
ppc_set_cur_instruction(pc_real);
|
||||
|
@ -368,7 +370,8 @@ void ppc_exec_single()
|
|||
return;
|
||||
}
|
||||
|
||||
quickinstruction_translate(ppc_state.pc);
|
||||
//quickinstruction_translate(ppc_state.pc);
|
||||
mmu_translate_imem(ppc_state.pc);
|
||||
ppc_main_opcode();
|
||||
if (bb_kind != BB_end_kind::BB_NONE) {
|
||||
ppc_state.pc = ppc_next_instruction_address;
|
||||
|
@ -403,7 +406,7 @@ void ppc_exec_until(volatile uint32_t goal_addr)
|
|||
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
|
||||
#endif
|
||||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
ppc_state.pc = bb_start_la;
|
||||
bb_kind = BB_end_kind::BB_NONE;
|
||||
|
@ -411,7 +414,8 @@ void ppc_exec_until(volatile uint32_t goal_addr)
|
|||
}
|
||||
|
||||
/* initial MMU translation for the current code page. */
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
//pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
|
||||
/* set current code page limits */
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
|
@ -429,7 +433,7 @@ again:
|
|||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
} else {
|
||||
pc_real += (int)bb_start_la - (int)ppc_state.pc;
|
||||
ppc_set_cur_instruction(pc_real);
|
||||
|
@ -463,7 +467,8 @@ void ppc_exec_dbg(volatile uint32_t start_addr, volatile uint32_t size)
|
|||
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
|
||||
#endif
|
||||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
//pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
ppc_state.pc = bb_start_la;
|
||||
bb_kind = BB_end_kind::BB_NONE;
|
||||
|
@ -472,7 +477,7 @@ void ppc_exec_dbg(volatile uint32_t start_addr, volatile uint32_t size)
|
|||
}
|
||||
|
||||
/* initial MMU translation for the current code page. */
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
|
||||
/* set current code page limits */
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
|
@ -490,7 +495,8 @@ again:
|
|||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
//pc_real = quickinstruction_translate(bb_start_la);
|
||||
pc_real = mmu_translate_imem(bb_start_la);
|
||||
} else {
|
||||
pc_real += (int)bb_start_la - (int)ppc_state.pc;
|
||||
ppc_set_cur_instruction(pc_real);
|
||||
|
|
|
@ -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 {
|
||||
|
@ -776,7 +780,8 @@ void dppc_interpreter::ppc_lfd() {
|
|||
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_qword(ppc_effective_address);
|
||||
//ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
ppc_result64_d = mmu_read_vmem<uint64_t>(ppc_effective_address);
|
||||
ppc_store_dfpresult_int(reg_d);
|
||||
}
|
||||
|
||||
|
@ -785,7 +790,8 @@ void dppc_interpreter::ppc_lfdu() {
|
|||
if (reg_a != 0) {
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += val_reg_a;
|
||||
ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
//ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
ppc_result64_d = mmu_read_vmem<uint64_t>(ppc_effective_address);
|
||||
ppc_store_dfpresult_int(reg_d);
|
||||
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||
} else {
|
||||
|
@ -796,7 +802,8 @@ void dppc_interpreter::ppc_lfdu() {
|
|||
void dppc_interpreter::ppc_lfdx() {
|
||||
ppc_grab_regsfpdiab();
|
||||
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
|
||||
ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
//ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
ppc_result64_d = mmu_read_vmem<uint64_t>(ppc_effective_address);
|
||||
ppc_store_dfpresult_int(reg_d);
|
||||
}
|
||||
|
||||
|
@ -804,7 +811,8 @@ void dppc_interpreter::ppc_lfdux() {
|
|||
ppc_grab_regsfpdiab();
|
||||
if (reg_a) {
|
||||
ppc_effective_address = val_reg_a + val_reg_b;
|
||||
ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
//ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
ppc_result64_d = mmu_read_vmem<uint64_t>(ppc_effective_address);
|
||||
ppc_store_dfpresult_int(reg_d);
|
||||
ppc_state.gpr[reg_a] = ppc_effective_address;
|
||||
} else {
|
||||
|
@ -816,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() {
|
||||
|
@ -824,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);
|
||||
|
@ -834,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);
|
||||
|
@ -852,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() {
|
||||
|
@ -860,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);
|
||||
|
@ -870,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);
|
||||
|
@ -887,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
|
||||
|
|
1725
cpu/ppc/ppcmmu.cpp
1725
cpu/ppc/ppcmmu.cpp
File diff suppressed because it is too large
Load Diff
|
@ -19,14 +19,15 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// The opcodes for the processor - ppcopcodes.cpp
|
||||
/** @file PowerPC Memory Management Unit definitions. */
|
||||
|
||||
#ifndef PPCMEMORY_H
|
||||
#define PPCMEMORY_H
|
||||
#ifndef PPCMMU_H
|
||||
#define PPCMMU_H
|
||||
|
||||
#include <array>
|
||||
#include <cinttypes>
|
||||
#include <vector>
|
||||
#include "devices/memctrlbase.h"
|
||||
|
||||
/* Uncomment this to exhaustive MMU integrity checks. */
|
||||
//#define MMU_INTEGRITY_CHECKS
|
||||
|
@ -40,13 +41,76 @@ typedef struct PPC_BAT_entry {
|
|||
uint32_t bepi; /* copy of Block effective page index */
|
||||
} PPC_BAT_entry;
|
||||
|
||||
/** Block address translation types. */
|
||||
enum BATType : int {
|
||||
IBAT,
|
||||
DBAT
|
||||
};
|
||||
|
||||
/** TLB types. */
|
||||
enum TLBType : int {
|
||||
ITLB,
|
||||
DTLB
|
||||
};
|
||||
|
||||
/** Result of the block address translation. */
|
||||
typedef struct BATResult {
|
||||
bool hit;
|
||||
uint8_t prot;
|
||||
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);
|
||||
|
||||
extern uint8_t* mmu_get_dma_mem(uint32_t addr, uint32_t size);
|
||||
|
||||
extern void mmu_change_mode(void);
|
||||
extern void mmu_pat_ctx_changed();
|
||||
extern void tlb_flush_entry(uint32_t ea);
|
||||
|
||||
extern void ppc_set_cur_instruction(const uint8_t* ptr);
|
||||
extern uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size);
|
||||
uint8_t *mmu_translate_imem(uint32_t vaddr);
|
||||
|
||||
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);
|
||||
|
||||
//====================== Deprecated calls =========================
|
||||
#if 0
|
||||
extern void mem_write_byte(uint32_t addr, uint8_t value);
|
||||
extern void mem_write_word(uint32_t addr, uint16_t value);
|
||||
extern void mem_write_dword(uint32_t addr, uint32_t value);
|
||||
|
@ -55,7 +119,7 @@ extern uint8_t mem_grab_byte(uint32_t addr);
|
|||
extern uint16_t mem_grab_word(uint32_t addr);
|
||||
extern uint32_t mem_grab_dword(uint32_t addr);
|
||||
extern uint64_t mem_grab_qword(uint32_t addr);
|
||||
extern uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size);
|
||||
extern uint8_t* quickinstruction_translate(uint32_t address_grab);
|
||||
#endif
|
||||
|
||||
#endif // PPCMEMORY_H
|
||||
#endif // PPCMMU_H
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -824,6 +843,7 @@ void dppc_interpreter::ppc_mtmsr() {
|
|||
}
|
||||
reg_s = (ppc_cur_instruction >> 21) & 31;
|
||||
ppc_state.msr = ppc_state.gpr[reg_s];
|
||||
mmu_change_mode();
|
||||
}
|
||||
|
||||
void dppc_interpreter::ppc_mfspr() {
|
||||
|
@ -852,6 +872,10 @@ void dppc_interpreter::ppc_mtspr() {
|
|||
ppc_state.spr[ref_spr] = ppc_state.gpr[reg_s];
|
||||
}
|
||||
|
||||
if (ref_spr == SPR::SDR1) {
|
||||
mmu_pat_ctx_changed();
|
||||
}
|
||||
|
||||
switch (ref_spr) {
|
||||
// Mirror the TBRs in the SPR range to the user-mode TBRs.
|
||||
case 284:
|
||||
|
@ -1278,6 +1302,8 @@ void dppc_interpreter::ppc_rfi() {
|
|||
ppc_state.msr = (new_msr_val | new_srr1_val) & 0xFFFBFFFFUL;
|
||||
ppc_next_instruction_address = ppc_state.spr[SPR::SRR0] & 0xFFFFFFFCUL;
|
||||
|
||||
mmu_change_mode();
|
||||
|
||||
grab_return = true;
|
||||
bb_kind = BB_end_kind::BB_RFI;
|
||||
}
|
||||
|
@ -1317,7 +1343,7 @@ void dppc_interpreter::ppc_eieio() {
|
|||
}
|
||||
|
||||
void dppc_interpreter::ppc_isync() {
|
||||
/* placeholder */
|
||||
do_ctx_sync();
|
||||
}
|
||||
|
||||
void dppc_interpreter::ppc_sync() {
|
||||
|
@ -1359,10 +1385,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1375,7 +1401,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() {
|
||||
|
@ -1384,7 +1411,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() {
|
||||
|
@ -1395,7 +1423,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);
|
||||
|
@ -1409,7 +1438,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);
|
||||
|
@ -1423,7 +1453,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() {
|
||||
|
@ -1434,7 +1465,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);
|
||||
|
@ -1448,7 +1480,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);
|
||||
|
@ -1461,7 +1494,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() {
|
||||
|
@ -1471,8 +1505,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++;
|
||||
|
@ -1480,7 +1516,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() {
|
||||
|
@ -1489,7 +1526,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() {
|
||||
|
@ -1503,7 +1541,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 {
|
||||
|
@ -1520,7 +1559,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);
|
||||
|
@ -1534,7 +1574,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);
|
||||
|
@ -1548,7 +1589,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() {
|
||||
|
@ -1565,7 +1607,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;
|
||||
}
|
||||
}
|
||||
|
@ -1577,7 +1620,8 @@ void dppc_interpreter::ppc_lbz() {
|
|||
ppc_grab_regsda();
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
||||
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1589,7 +1633,8 @@ void dppc_interpreter::ppc_lbzu() {
|
|||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
if ((reg_a != reg_d) || reg_a != 0) {
|
||||
ppc_effective_address += ppc_result_a;
|
||||
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_regd();
|
||||
ppc_store_result_rega();
|
||||
|
@ -1604,7 +1649,8 @@ void dppc_interpreter::ppc_lbzx() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1615,7 +1661,8 @@ void dppc_interpreter::ppc_lbzux() {
|
|||
ppc_grab_regsdab();
|
||||
if ((reg_a != reg_d) || reg_a != 0) {
|
||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
||||
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_byte(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_regd();
|
||||
ppc_store_result_rega();
|
||||
|
@ -1632,7 +1679,8 @@ void dppc_interpreter::ppc_lhz() {
|
|||
ppc_grab_regsda();
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += reg_a ? ppc_result_a : 0;
|
||||
ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1644,7 +1692,8 @@ void dppc_interpreter::ppc_lhzu() {
|
|||
if ((reg_a != reg_d) || reg_a != 0) {
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += ppc_result_a;
|
||||
ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_regd();
|
||||
ppc_store_result_rega();
|
||||
|
@ -1659,7 +1708,8 @@ void dppc_interpreter::ppc_lhzx() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1670,8 +1720,9 @@ void dppc_interpreter::ppc_lhzux() {
|
|||
ppc_grab_regsdab();
|
||||
if ((reg_a != reg_d) || reg_a != 0) {
|
||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
||||
ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
//ppc_result_d = mem_grab_word(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_regd();
|
||||
ppc_store_result_rega();
|
||||
} else {
|
||||
|
@ -1686,7 +1737,8 @@ void dppc_interpreter::ppc_lha() {
|
|||
ppc_grab_regsda();
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
||||
uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
//uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
uint16_t val = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
if (val & 0x8000) {
|
||||
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
||||
} else {
|
||||
|
@ -1703,7 +1755,8 @@ void dppc_interpreter::ppc_lhau() {
|
|||
if ((reg_a != reg_d) || reg_a != 0) {
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += ppc_result_a;
|
||||
uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
//uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
uint16_t val = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
if (val & 0x8000) {
|
||||
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
||||
} else {
|
||||
|
@ -1723,7 +1776,8 @@ void dppc_interpreter::ppc_lhaux() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
//uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
uint16_t val = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
if (val & 0x8000) {
|
||||
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
||||
} else {
|
||||
|
@ -1740,7 +1794,8 @@ void dppc_interpreter::ppc_lhax() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
//uint16_t val = mem_grab_word(ppc_effective_address);
|
||||
uint16_t val = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
if (val & 0x8000) {
|
||||
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
||||
} else {
|
||||
|
@ -1755,7 +1810,8 @@ void dppc_interpreter::ppc_lhbrx() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
ppc_result_d = (uint32_t)(BYTESWAP_16(mem_grab_word(ppc_effective_address)));
|
||||
//ppc_result_d = (uint32_t)(BYTESWAP_16(mem_grab_word(ppc_effective_address)));
|
||||
ppc_result_d = (uint32_t)(BYTESWAP_16(mmu_read_vmem<uint16_t>(ppc_effective_address)));
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1766,7 +1822,8 @@ void dppc_interpreter::ppc_lwz() {
|
|||
ppc_grab_regsda();
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
||||
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1776,7 +1833,8 @@ void dppc_interpreter::ppc_lwbrx() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
ppc_result_d = BYTESWAP_32(mem_grab_dword(ppc_effective_address));
|
||||
//ppc_result_d = BYTESWAP_32(mem_grab_dword(ppc_effective_address));
|
||||
ppc_result_d = BYTESWAP_32(mmu_read_vmem<uint32_t>(ppc_effective_address));
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1788,7 +1846,8 @@ void dppc_interpreter::ppc_lwzu() {
|
|||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
if ((reg_a != reg_d) || reg_a != 0) {
|
||||
ppc_effective_address += ppc_result_a;
|
||||
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
|
@ -1803,7 +1862,8 @@ void dppc_interpreter::ppc_lwzx() {
|
|||
#endif
|
||||
ppc_grab_regsdab();
|
||||
ppc_effective_address = reg_a ? (ppc_result_a + ppc_result_b) : ppc_result_b;
|
||||
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1817,7 +1877,8 @@ void dppc_interpreter::ppc_lwzux() {
|
|||
} else {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||
}
|
||||
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_regd();
|
||||
ppc_store_result_rega();
|
||||
|
@ -1831,7 +1892,8 @@ void dppc_interpreter::ppc_lwarx() {
|
|||
ppc_grab_regsdab();
|
||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
||||
ppc_state.reserve = true;
|
||||
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
//ppc_result_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
|
@ -1844,7 +1906,8 @@ void dppc_interpreter::ppc_lmw() {
|
|||
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
||||
// How many words to load in memory - using a do-while for this
|
||||
do {
|
||||
ppc_state.gpr[reg_d] = mem_grab_dword(ppc_effective_address);
|
||||
//ppc_state.gpr[reg_d] = mem_grab_dword(ppc_effective_address);
|
||||
ppc_state.gpr[reg_d] = mmu_read_vmem<uint32_t>(ppc_effective_address);
|
||||
ppc_effective_address += 4;
|
||||
reg_d++;
|
||||
} while (reg_d < 32);
|
||||
|
@ -1863,25 +1926,32 @@ 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;
|
||||
default:
|
||||
ppc_state.gpr[reg_d] = mem_grab_word(ppc_effective_address);
|
||||
//ppc_state.gpr[reg_d] = mem_grab_word(ppc_effective_address);
|
||||
ppc_state.gpr[reg_d] = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
reg_d++;
|
||||
ppc_effective_address += 4;
|
||||
grab_inb -= 4;
|
||||
|
@ -1910,25 +1980,32 @@ 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;
|
||||
default:
|
||||
ppc_state.gpr[reg_d] = mem_grab_word(ppc_effective_address);
|
||||
//ppc_state.gpr[reg_d] = mem_grab_word(ppc_effective_address);
|
||||
ppc_state.gpr[reg_d] = mmu_read_vmem<uint16_t>(ppc_effective_address);
|
||||
reg_d++;
|
||||
ppc_effective_address += 4;
|
||||
grab_inb -= 4;
|
||||
|
@ -1948,22 +2025,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;
|
||||
|
@ -1982,22 +2066,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;
|
||||
|
@ -2011,7 +2102,8 @@ void dppc_interpreter::ppc_tlbie() {
|
|||
#ifdef CPU_PROFILING
|
||||
num_supervisor_instrs++;
|
||||
#endif
|
||||
/* placeholder */
|
||||
|
||||
tlb_flush_entry(ppc_state.gpr[(ppc_cur_instruction >> 11) & 31]);
|
||||
}
|
||||
|
||||
void dppc_interpreter::ppc_tlbia() {
|
||||
|
|
|
@ -151,7 +151,7 @@ void exec_single_68k()
|
|||
|
||||
/* calculate address of the current opcode table entry as follows:
|
||||
get_word(68k_PC) * entry_size + table_base */
|
||||
cur_instr_tab_entry = mem_grab_word(cur_68k_pc) * 8 + emu_table_virt;
|
||||
cur_instr_tab_entry = mmu_read_vmem<uint16_t>(cur_68k_pc) * 8 + emu_table_virt;
|
||||
|
||||
/* grab the PPC PC too */
|
||||
reg = "PC";
|
||||
|
|
31
main.cpp
31
main.cpp
|
@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "utils/profiler.h"
|
||||
#include "ppcemu.h"
|
||||
#include <cinttypes>
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -40,6 +41,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
using namespace std;
|
||||
|
||||
void sigint_handler(int signum) {
|
||||
enter_debugger();
|
||||
|
||||
LOG_F(INFO, "Shutting down...");
|
||||
|
||||
delete gMachineObj.release();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void sigabrt_handler(int signum) {
|
||||
LOG_F(INFO, "Shutting down...");
|
||||
|
||||
delete gMachineObj.release();
|
||||
}
|
||||
|
||||
static string appDescription = string(
|
||||
"\nDingusPPC - Prototype 5bf5 (8/23/2020) "
|
||||
"\nWritten by divingkatae and maximumspatium "
|
||||
|
@ -118,7 +134,7 @@ 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_stderr_verbosity = loguru::Verbosity_INFO;
|
||||
loguru::init(argc, argv);
|
||||
}
|
||||
|
||||
|
@ -161,6 +177,19 @@ int main(int argc, char** argv) {
|
|||
goto bail;
|
||||
}
|
||||
|
||||
// graceful handling of fatal errors
|
||||
loguru::set_fatal_handler([](const loguru::Message& message) {
|
||||
enter_debugger();
|
||||
|
||||
abort();
|
||||
});
|
||||
|
||||
// redirect SIGINT to our own handler
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
// redirect SIGABRT to our own handler
|
||||
signal(SIGABRT, sigabrt_handler);
|
||||
|
||||
#ifdef SDL
|
||||
if (SDL_Init(SDL_INIT_AUDIO)){
|
||||
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
|
||||
|
|
76
memaccess.h
76
memaccess.h
|
@ -1,4 +1,4 @@
|
|||
/** @file Set of macros for accessing host memory units of various sizes
|
||||
/** @file Set of macros for accessing host memory in units of various sizes
|
||||
and endianness.
|
||||
*/
|
||||
|
||||
|
@ -31,25 +31,28 @@
|
|||
#define READ_WORD_BE_U(addr) (((addr)[0] << 8) | (addr)[1])
|
||||
|
||||
/* read an unaligned big-endian DWORD (32bit) */
|
||||
#define READ_DWORD_BE_U(addr) (((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
|
||||
#define READ_DWORD_BE_U(addr) \
|
||||
(((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
|
||||
|
||||
/* read an unaligned big-endian QWORD (32bit) */
|
||||
#define READ_QWORD_BE_U(addr) \
|
||||
(((addr)[0] << 56) | ((addr)[1] << 48) | ((addr)[2] << 40) | ((addr)[3] << 32) | \
|
||||
((addr)[4] << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
|
||||
#define READ_QWORD_BE_U(addr) \
|
||||
((uint64_t((addr)[0]) << 56) | (uint64_t((addr)[1]) << 48) | \
|
||||
(uint64_t((addr)[2]) << 40) | (uint64_t((addr)[3]) << 32) | \
|
||||
((addr)[4] << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
|
||||
|
||||
/* read an unaligned little-endian WORD (16bit) */
|
||||
#define READ_WORD_LE_U(addr) (((addr)[1] << 8) | (addr)[0])
|
||||
|
||||
/* read an unaligned little-endian DWORD (32bit) */
|
||||
#define READ_DWORD_LE_U(addr) (((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||
#define READ_DWORD_LE_U(addr) \
|
||||
(((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||
|
||||
/* read an unaligned little-endian DWORD (32bit) */
|
||||
#define READ_QWORD_LE_U(addr) \
|
||||
(((addr)[7] << 56) | ((addr)[6] << 48) | ((addr)[5] << 40) | ((addr)[4] << 32) | \
|
||||
/* read an unaligned little-endian DWORD (64bit) */
|
||||
#define READ_QWORD_LE_U(addr) \
|
||||
((uint64_t((addr)[7]) << 56) | (uint64_t((addr)[6]) << 48) | \
|
||||
(uint64_t((addr)[5]) << 40) | (uint64_t((addr)[4]) << 32) | \
|
||||
((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||
|
||||
|
||||
/* write an aligned big-endian WORD (16bit) */
|
||||
#define WRITE_WORD_BE_A(addr, val) (*((uint16_t*)((addr))) = BYTESWAP_16(val))
|
||||
|
||||
|
@ -60,19 +63,32 @@
|
|||
#define WRITE_QWORD_BE_A(addr, val) (*((uint64_t*)((addr))) = BYTESWAP_64(val))
|
||||
|
||||
/* write an unaligned big-endian WORD (16bit) */
|
||||
#define WRITE_WORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[1] = (val)&0xFF; \
|
||||
#define WRITE_WORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[1] = (val) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* write an unaligned big-endian DWORD (32bit) */
|
||||
#define WRITE_DWORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 24) & 0xFF; \
|
||||
(addr)[1] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[3] = (val)&0xFF; \
|
||||
#define WRITE_DWORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 24) & 0xFF; \
|
||||
(addr)[1] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[3] = (val) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* write an unaligned big-endian DWORD (64bit) */
|
||||
#define WRITE_QWORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((uint64_t)(val) >> 56) & 0xFF; \
|
||||
(addr)[1] = ((uint64_t)(val) >> 48) & 0xFF; \
|
||||
(addr)[2] = ((uint64_t)(val) >> 40) & 0xFF; \
|
||||
(addr)[3] = ((uint64_t)(val) >> 32) & 0xFF; \
|
||||
(addr)[4] = ((val) >> 24) & 0xFF; \
|
||||
(addr)[5] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[6] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[7] = (val) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* write an aligned little-endian WORD (16bit) */
|
||||
|
@ -85,19 +101,19 @@
|
|||
#define WRITE_QWORD_LE_A(addr, val) (*((uint64_t*)((addr))) = (val))
|
||||
|
||||
/* write an unaligned little-endian WORD (16bit) */
|
||||
#define WRITE_WORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
#define WRITE_WORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* write an unaligned little-endian DWORD (32bit) */
|
||||
#define WRITE_DWORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[3] = ((val) >> 24) & 0xFF; \
|
||||
#define WRITE_DWORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[3] = ((val) >> 24) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* read value of the specified size from memory starting at addr,
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
## Disabling BAT translation
|
||||
|
||||
BAT translation can be disabled by invalidating BAT registers. This is somewhat CPU specific.
|
||||
MPC601 implements its own format for BAT registers that differs from the PowerPC specification.
|
||||
|
||||
MPC601-specific lower BAT registers has the "V" bit. If it's cleared, the corresponding BAT pair
|
||||
is invalid and won't be used for address translation. To invalidate BATs on MPC601, it's enough
|
||||
to write NULL to lower BAT registers. That's exactly what PowerMac 6100 ROM does:
|
||||
```
|
||||
li r0, 0
|
||||
mtspr ibat0l, r0
|
||||
mtspr ibat1l, r0
|
||||
mtspr ibat2l, r0
|
||||
```
|
||||
|
||||
PowerPC CPUs starting with 603 uses the BAT register format described in the PowerPC specification.
|
||||
The upper BAT registers contain two bits: Vs (supervisor state valid bit) and Vp (problem/user state valid bit).
|
||||
PowerPC Architecture First Edition from 1993 gives the following code:
|
||||
|
||||
```BAT_entry_valid = (Vs & ~MSR_PR) | (Vp & MSR_PR)```
|
||||
|
||||
If neither Vs nor Vp is set, the corresponding BAT pair isn't valid and doesn't participate in address translation.
|
||||
To invalidate BATs on non-601, it's sufficient to set the upper BAT register to 0x00000000.
|
|
@ -0,0 +1,107 @@
|
|||
# PowerPC Memory Management Unit Emulation
|
||||
|
||||
Emulation of a [memory management unit](https://en.wikipedia.org/wiki/Memory_management_unit)
|
||||
(MMU) in a full system emulator is considered a hard task. The biggest challenge is to do it fast.
|
||||
|
||||
In this article, I'm going to present a solution for a reasonably fast emulation
|
||||
of the PowerPC MMU.
|
||||
|
||||
This article is based on ideas presented in the paper "Optimizing Memory Emulation
|
||||
in Full System Emulators" by Xin Tong and Motohiro Kawahito (IBM Research Laboratory).
|
||||
|
||||
## PowerPC MMU operation
|
||||
|
||||
The operation of the PowerPC MMU can be described using the following pseudocode:
|
||||
|
||||
```
|
||||
VA is the virtual address of some memory to be accessed
|
||||
PA is the physical address of some memory translated by the MMU
|
||||
AT is access type we want to perform
|
||||
|
||||
if address translation is enabled:
|
||||
PA = block_address_translation(VA)
|
||||
if not PA:
|
||||
PA = page_address_translation(VA)
|
||||
else:
|
||||
PA = VA
|
||||
|
||||
if access_permitted(PA, AT):
|
||||
perfom_phys_access(PA)
|
||||
else:
|
||||
generate_mmu_exception(VA, PA, AT)
|
||||
```
|
||||
|
||||
A HW MMU usually performs several operations in a parallel fashion so the final
|
||||
address translation and memory access only take a few CPU cycles.
|
||||
The slowest part is the page address translation because it requires accessing
|
||||
system memory that is usually an order of magnitudes slower than the CPU.
|
||||
To mitigate this, a PowerPC CPU includes some very fast on-chip memory used for
|
||||
building various [caches](https://en.wikipedia.org/wiki/CPU_cache) like
|
||||
instruction/data cache as well as
|
||||
[translation lookaside buffers (TLB)](https://en.wikipedia.org/wiki/Translation_lookaside_buffer).
|
||||
|
||||
## PowerPC MMU emulation
|
||||
|
||||
### Issues
|
||||
|
||||
An attempt to mimic the HW MMU operation in software will likely have a poor
|
||||
performance. That's because modern hardware can perform several tasks in parallel.
|
||||
However, software has to do almost everything serially. Thus, accessing some memory
|
||||
with address translation enabled can take up to 300 host instructions! Considering
|
||||
the fact that every 10th instruction is a load and every 15th instruction is a store,
|
||||
it will be nearly impossible to achieve a performance comparable to that of the
|
||||
original system.
|
||||
|
||||
Off-loading some operations to the MMU of the host CPU for speeding up emulation
|
||||
isn't feasible because Apple's computers often have hardware being accessed like an
|
||||
usual memory. Thus, an emulator needs to distinguish between accesses to real memory
|
||||
(ROM or RAM) from accesses to memory-mapped peripheral devices. The only way to
|
||||
do that is to maintain special software descriptors for each virtual memory region
|
||||
and consult them on each memory access.
|
||||
|
||||
### Solution
|
||||
|
||||
My solution for a reasonable fast MMU emulation employs a software TLB. It's
|
||||
used for all memory accesses even when address translation is disabled.
|
||||
|
||||
The first stage of the SoftTLB uses a
|
||||
[direct-mapped cache](https://en.wikipedia.org/wiki/Cache_placement_policies#Direct-mapped_cache)
|
||||
called **primary TLB** in my implementation. That's because this kind of cache
|
||||
is the fastest one - one lookup requires up to 15 host instructions. Unfortunately,
|
||||
this cache is not enough to cover all memory accesses due to a high number of
|
||||
collisions, i.e. when several distinct memory pages are mapped to the same cache
|
||||
location.
|
||||
|
||||
That's why, the so-called **secondary TLB** was introduced. Secondary TLB is a
|
||||
4-way fully associative cache. A lookup in this cache is slower than a lookup in the
|
||||
primary TLB. But it's still much faster than performing a full page table walk
|
||||
requiring hundreds of host instructions.
|
||||
|
||||
All translations for memory-mapped I/O go into the secondary TLB because accesses
|
||||
to such devices tend to be slower than real memory accesses in the real HW anyways.
|
||||
Moreover, they usually bypass CPU caches (cache-inhibited accesses). But there
|
||||
are exceptions from this rule, for example, video memory.
|
||||
|
||||
When no translation for a virtual address was found in either cache, a full address
|
||||
translation including the full page table walk is performed. This path is the
|
||||
slowest one. Fortunately, the probabilty that this path will be taken seems to be
|
||||
very low.
|
||||
|
||||
The complete algorithm looks like that:
|
||||
```
|
||||
VA is the virtual address of some memory to be accessed
|
||||
PA is the physical address of some memory translated by the MMU
|
||||
AT is access type we want to perform
|
||||
|
||||
PA = lookup_primary_tlb(VA)
|
||||
if VA in the primary TLB:
|
||||
perform_memory_access(PA, ART)
|
||||
else:
|
||||
PA = lookup_secondary_tlb(VA)
|
||||
if VA not in the secondary TLB:
|
||||
PA = perform_full_address_translation(VA)
|
||||
refill_secondary_tlb(VA, PA)
|
||||
if is_real_memory(PA):
|
||||
refill_primary_tlb(VA, PA)
|
||||
perform_memory_access(PA, ART)
|
||||
```
|
Loading…
Reference in New Issue