Merge branch 'soft-tlb'.

This commit is contained in:
Maxim Poliakovski 2021-09-25 19:58:09 +02:00
commit 4b16cb826e
13 changed files with 1889 additions and 493 deletions

View File

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

View File

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

View File

@ -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. */
}

View File

@ -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);

View File

@ -674,11 +674,11 @@ void dppc_interpreter::ppc_fctiw() {
if (std::isnan(val_reg_b)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x1000100;
}
}
else if (val_reg_b > static_cast<double>(0x7fffffff)) {
ppc_state.fpr[reg_d].int64_r = 0x7fffffff;
ppc_state.fpscr |= 0x100;
}
}
else if (val_reg_b < -static_cast<double>(0x80000000)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x100;
@ -696,7 +696,7 @@ void dppc_interpreter::ppc_fctiw() {
}
ppc_store_dfpresult_int(reg_d);
}
if (rc_flag)
@ -710,15 +710,15 @@ void dppc_interpreter::ppc_fctiwz() {
if (std::isnan(val_reg_b)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x1000100;
}
}
else if (val_reg_b > static_cast<double>(0x7fffffff)) {
ppc_state.fpr[reg_d].int64_r = 0x7fffffff;
ppc_state.fpscr |= 0x100;
}
}
else if (val_reg_b < -static_cast<double>(0x80000000)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x100;
}
}
else {
ppc_result64_d = round_to_zero(val_reg_b);
@ -735,7 +735,8 @@ void dppc_interpreter::ppc_lfs() {
ppc_grab_regsfpdia();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a) ? val_reg_a : 0;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
}
@ -745,7 +746,8 @@ void dppc_interpreter::ppc_lfsu() {
if (reg_a) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a) ? val_reg_a : 0;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
@ -756,7 +758,8 @@ void dppc_interpreter::ppc_lfsu() {
void dppc_interpreter::ppc_lfsx() {
ppc_grab_regsfpdiab();
ppc_effective_address = (reg_a) ? val_reg_a + val_reg_b : val_reg_b;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
}
@ -764,7 +767,8 @@ void dppc_interpreter::ppc_lfsux() {
ppc_grab_regsfpdiab();
if (reg_a) {
ppc_effective_address = val_reg_a + val_reg_b;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result64_d = mmu_read_vmem<uint32_t>(ppc_effective_address);
//ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_sfpresult_int(reg_d);
ppc_state.gpr[reg_a] = ppc_effective_address;
} else {
@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -26,12 +26,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <array>
#include <cinttypes>
#include <cstring>
#include <functional>
#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <thirdparty/loguru/loguru.hpp>
#include <thread>
#include <vector>
uint32_t crf_d;
uint32_t crf_s;
@ -188,6 +190,21 @@ inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) {
}
}
typedef std::function<void()> CtxSyncCallback;
std::vector<CtxSyncCallback> gCtxSyncCallbacks;
// perform context synchronization by executing registered actions if any
void do_ctx_sync() {
while (!gCtxSyncCallbacks.empty()) {
gCtxSyncCallbacks.back()();
gCtxSyncCallbacks.pop_back();
}
}
void add_ctx_sync_action(const CtxSyncCallback &cb) {
gCtxSyncCallbacks.push_back(cb);
}
/**
The core functionality of this PPC emulation is within all of these void functions.
This is where the opcode tables in the ppcemumain.h come into play - reducing the number of
@ -768,6 +785,7 @@ void dppc_interpreter::ppc_mtsr() {
reg_s = (ppc_cur_instruction >> 21) & 31;
grab_sr = (ppc_cur_instruction >> 16) & 15;
ppc_state.sr[grab_sr] = ppc_state.gpr[reg_s];
mmu_pat_ctx_changed();
}
}
@ -779,6 +797,7 @@ void dppc_interpreter::ppc_mtsrin() {
ppc_grab_regssb();
grab_sr = ppc_result_b >> 28;
ppc_state.sr[grab_sr] = ppc_result_d;
mmu_pat_ctx_changed();
}
}
@ -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() {

View File

@ -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";

View File

@ -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());

View File

@ -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,

23
zdocs/cpu/powerpc/mmu.md Normal file
View File

@ -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.

107
zdocs/cpu/powerpc/mmuemu.md Normal file
View File

@ -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)
```