ppcemu: refactor page address translation.

The refactored code is UNTESTED. Moreover,
no TLB is currently implemeneted.
This commit is contained in:
Maxim Poliakovski 2020-01-03 16:17:45 +01:00
parent 241031dfe7
commit 4b843157d9
3 changed files with 109 additions and 292 deletions

View File

@ -60,12 +60,6 @@ std::atomic<bool> hash_found (false);
PPC_BAT_entry ibat_array[4] = {{0}}; PPC_BAT_entry ibat_array[4] = {{0}};
PPC_BAT_entry dbat_array[4] = {{0}}; PPC_BAT_entry dbat_array[4] = {{0}};
void msr_status_update(){
msr_ip_test = (ppc_state.ppc_msr >> 6) & 1;
msr_ir_test = (ppc_state.ppc_msr >> 5) & 1;
msr_dr_test = (ppc_state.ppc_msr >> 4) & 1;
}
static inline void ppc_set_cur_instruction(const uint8_t *ptr) static inline void ppc_set_cur_instruction(const uint8_t *ptr)
{ {
ppc_cur_instruction = READ_DWORD_BE(ptr); ppc_cur_instruction = READ_DWORD_BE(ptr);
@ -175,278 +169,115 @@ void dbat_update(uint32_t bat_reg)
} }
} }
void get_pointer_pteg1(uint32_t address_grab){ /* remember page table memory region for quicker translation. */
//Grab the array pointer for the PTEG uint32_t page_table_pa_start = 0;
if (address_grab < 0x80000000){ uint32_t page_table_pa_end = 0;
pte_word1 = address_grab % ram_size_set; unsigned char *page_table_ptr = 0;
if (address_grab < 0x040000000){ //for debug purposes
grab_pteg1_ptr = machine_sysram_mem;
}
else if ((address_grab >= 0x5fffe000) && (address_grab <= 0x5fffffff)){
pte_word1 = address_grab % 0x2000;
grab_pteg1_ptr = machine_sysconfig_mem;
}
else{
printf("Uncharted territory: %x \n", address_grab);
}
}
else if (address_grab < 0x80800000){
pte_word1 = address_grab % 0x800000;
grab_pteg1_ptr = machine_upperiocontrol_mem;
} static inline uint8_t *calc_pteg_addr(uint32_t hash)
else if (address_grab < 0x81000000){ {
pte_word1 = address_grab % 0x800000; uint32_t sdr1_val, pteg_addr;
grab_pteg1_ptr = machine_iocontrolcdma_mem;
} sdr1_val = ppc_state.ppc_spr[25];
else if (address_grab < 0xBF80000){
pte_word1 = address_grab % 33554432;
grab_pteg1_ptr = machine_loweriocontrol_mem;
} pteg_addr = sdr1_val & 0xFE000000;
else if (address_grab < 0xC0000000){ pteg_addr |= (sdr1_val & 0x01FF0000) |
pte_word1 = address_grab % 16; (((sdr1_val & 0x1FF) << 16) & ((hash & 0x7FC00) << 6));
grab_pteg1_ptr = machine_interruptack_mem; pteg_addr |= (hash & 0x3FF) << 6;
} if (pteg_addr >= page_table_pa_start && pteg_addr <= page_table_pa_end) {
else if (address_grab < 0xF0000000){ return page_table_ptr + (pteg_addr - page_table_pa_start);
printf("Invalid Memory Attempt: %x \n", address_grab); } else {
return; AddressMapEntry *entry = mem_ctrl_instance->find_range(pteg_addr);
} if (entry && entry->type & (RT_ROM | RT_RAM)) {
else if (address_grab < 0xF8000000){ page_table_pa_start = entry->start;
pte_word1 = address_grab % 67108864; page_table_pa_end = entry->end;
grab_pteg1_ptr = machine_iocontrolmem_mem; page_table_ptr = entry->mem_ptr;
return page_table_ptr + (pteg_addr - page_table_pa_start);
} } else {
else if (address_grab < rom_file_begin){ printf("SOS: no page table region was found at %08X!\n", pteg_addr);
//Get back to this! (weeny1) exit(-1); // FIXME: ugly error handling, must be the proper exception!
if (address_grab < 0xFE000000){
pte_word1 = address_grab % 4096;
grab_pteg1_ptr = machine_f8xxxx_mem;
} }
else if (address_grab < 0xFEC00000){
pte_word1 = address_grab % 65536;
grab_pteg1_ptr = machine_fexxxx_mem;
}
else if (address_grab < 0xFEE00000){
pte_word1 = 0x0CF8; //CONFIG_ADDR
grab_pteg1_ptr = machine_fecxxx_mem;
}
else if (address_grab < 0xFF000000){
pte_word1 = 0x0CFC; //CONFIG_DATA
grab_pteg1_ptr = machine_feexxx_mem;
}
else if (address_grab < 0xFF800000){
pte_word1 = address_grab % 4096;
grab_pteg1_ptr = machine_ff00xx_mem;
}
else{
pte_word1 = (address_grab % 1048576) + 0x400000;
grab_pteg1_ptr = machine_sysram_mem;
}
}
else{
pte_word1 = address_grab % rom_filesize;
grab_pteg1_ptr = machine_sysrom_mem;
} }
} }
void get_pointer_pteg2(uint32_t address_grab){ static bool search_pteg(uint8_t *pteg_addr, uint8_t **ret_pte_addr,
//Grab the array pointer for the PTEG uint32_t vsid, uint16_t page_index, uint8_t pteg_num)
if (address_grab < 0x80000000){ {
pte_word2 = address_grab % ram_size_set; /* construct PTE matching word */
if (address_grab < 0x040000000){ //for debug purposes uint32_t pte_check = 0x80000000 | (vsid << 7) | (pteg_num << 6) |
grab_pteg2_ptr = machine_sysram_mem; (page_index >> 10);
}
else if ((address_grab >= 0x5fffe000) && (address_grab <= 0x5fffffff)){
pte_word2 = address_grab % 0x2000;
grab_pteg2_ptr = machine_sysconfig_mem;
}
else{
printf("Uncharted territory: %x \n", address_grab);
}
}
else if (address_grab < 0x80800000){
pte_word2 = address_grab % 0x800000;
grab_pteg2_ptr = machine_upperiocontrol_mem;
for (int i = 0; i < 8; i++, pteg_addr += 8) {
if (pte_check == READ_DWORD_BE(pteg_addr)) {
*ret_pte_addr = pteg_addr;
return true;
}
} }
else if (address_grab < 0x81000000){
pte_word2 = address_grab % 0x800000;
grab_pteg2_ptr = machine_iocontrolcdma_mem;
} return false;
else if (address_grab < 0xBF80000){
pte_word2 = address_grab % 33554432;
grab_pteg2_ptr = machine_loweriocontrol_mem;
}
else if (address_grab < 0xC0000000){
pte_word2 = address_grab % 16;
grab_pteg2_ptr = machine_interruptack_mem;
}
else if (address_grab < 0xF0000000){
printf("Invalid Memory Attempt: %x \n", address_grab);
return;
}
else if (address_grab < 0xF8000000){
pte_word2 = address_grab % 67108864;
grab_pteg2_ptr = machine_iocontrolmem_mem;
}
else if (address_grab < rom_file_begin){
//Get back to this! (weeny1)
if (address_grab < 0xFE000000){
pte_word2 = address_grab % 4096;
grab_pteg2_ptr = machine_f8xxxx_mem;
}
else if (address_grab < 0xFEC00000){
pte_word2 = address_grab % 65536;
grab_pteg2_ptr = machine_fexxxx_mem;
}
else if (address_grab < 0xFEE00000){
pte_word2 = 0x0CF8; //CONFIG_ADDR
grab_pteg2_ptr = machine_fecxxx_mem;
}
else if (address_grab < 0xFF000000){
pte_word2 = 0x0CFC; //CONFIG_DATA
grab_pteg2_ptr = machine_feexxx_mem;
}
else if (address_grab < 0xFF800000){
pte_word2 = address_grab % 4096;
grab_pteg2_ptr = machine_ff00xx_mem;
}
else{
pte_word2 = (address_grab % 1048576) + 0x400000;
grab_pteg2_ptr = machine_sysram_mem;
}
}
else{
pte_word2 = address_grab % rom_filesize;
grab_pteg2_ptr = machine_sysrom_mem;
}
} }
void primary_generate_pa(){ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
pteg_address1 |= ppc_state.ppc_spr[25] & 0xFE000000; unsigned msr_pr, bool is_write)
pteg_temp1 = (((ppc_state.ppc_spr[25] & 0x1FF) << 10) & (pteg_hash1 & 0x7FC00)); {
pteg_address1 |= ((ppc_state.ppc_spr[25] & 0x1FF0000) | pteg_temp1); uint32_t sr_val, page_index, vsid, pte_word2;
pteg_address1 |= (pteg_hash1 & 0x3FF) << 6; unsigned key, pp;
} uint8_t *pte_addr;
void secondary_generate_pa(){ sr_val = ppc_state.ppc_sr[(la >> 28) & 0x0F];
pteg_address2 |= ppc_state.ppc_spr[25] & 0xFE000000; if (sr_val & 0x80000000) {
pteg_temp2 = (((ppc_state.ppc_spr[25] & 0x1FF) << 10) & (pteg_hash2 & 0x7FC00)); printf("Direct-store segments not supported, LA=%0xX\n", la);
pteg_address2 |= ((ppc_state.ppc_spr[25] & 0x1FF0000) | pteg_temp2); exit(-1); // FIXME: ugly error handling, must be the proper exception!
pteg_address2 |= (pteg_hash2 & 0x3FF) << 6; }
}
void primary_hash_check(uint32_t vpid_known){ /* instruction fetch from a no-execute segment will cause ISI exception */
if ((sr_val & 0x10000000) && is_instr_fetch) {
ppc_exception_handler(0x400, 0); // FIXME: proper exception handling!
}
uint32_t entries_size = ((ppc_state.ppc_spr[25] & 0x1FF) > 0)? ((ppc_state.ppc_spr[25] & 0x1FF) << 9): 65536; page_index = (la >> 12) & 0xFFFF;
uint32_t entries_area = pte_word1 + entries_size; pteg_hash1 = (sr_val & 0x7FFFF) ^ page_index;
vsid = sr_val & 0x0FFFFFF;
uint32_t check_vpid = 0; if (!search_pteg(calc_pteg_addr(pteg_hash1), &pte_addr, vsid, page_index, 0)) {
if (!search_pteg(calc_pteg_addr(~pteg_hash1), &pte_addr, vsid, page_index, 1)) {
do{ if (is_instr_fetch) {
if (!hash_found){ ppc_exception_handler(0x400, 0);
check_vpid |= grab_pteg1_ptr[pte_word1++] << 24; } else {
check_vpid |= grab_pteg1_ptr[pte_word1++] << 16; ppc_exception_handler(0x300, 0);
check_vpid |= grab_pteg1_ptr[pte_word1++] << 8;
check_vpid |= grab_pteg1_ptr[pte_word1++];
check_vpid = (check_vpid >> 7) & 0xFFFFFF;
if ((check_vpid >> 31) & 0x01){
if (vpid_known == check_vpid){
hash_found = true;
pteg_answer |= grab_pteg1_ptr[pte_word1++] << 24;
pteg_answer |= grab_pteg1_ptr[pte_word1++] << 16;
pteg_answer |= grab_pteg1_ptr[pte_word1++] << 8;
pteg_answer |= grab_pteg1_ptr[pte_word1++];
break;
}
else{
pte_word1 += 4;
check_vpid = 0;
} }
} }
else{ }
pte_word1 += 4;
check_vpid = 0; pte_word2 = READ_DWORD_BE(pte_addr + 4);
}
} key = (((sr_val >> 29) & 1) & msr_pr) | (((sr_val >> 30) & 1) & (msr_pr ^ 1));
else{
pte_word1 = entries_area; /* check page access */
pp = pte_word2 & 3;
// the following scenarios cause DSI/ISI exception:
// any access with key = 1 and PP = %00
// write access with key = 1 and PP = %01
// write access with PP = %11
if ((key && (!pp || (pp == 1 && is_write))) || (pp == 3 && is_write)) {
if (is_instr_fetch) {
ppc_exception_handler(0x400, 0);
} else {
ppc_exception_handler(0x300, 0);
} }
}
}while (pte_word1 < entries_area); /* update R and C bits */
} /* For simplicity, R is set on each access, C is set only for writes */
pte_addr[6] |= 0x01;
if (is_write) {
pte_addr[7] |= 0x80;
}
void secondary_hash_check(uint32_t vpid_known){ /* return physical address */
return ((pte_word2 & 0xFFFFF000) | (la & 0x00000FFF));
uint32_t entries_size = ((ppc_state.ppc_spr[25] & 0x1FF) > 0)? ((ppc_state.ppc_spr[25] & 0x1FF) << 9): 65536;
uint32_t entries_area = pte_word1 + entries_size;
uint32_t check_vpid = 0;
do{
if (!hash_found){
check_vpid |= grab_pteg2_ptr[pte_word2++] << 24;
check_vpid |= grab_pteg2_ptr[pte_word2++] << 16;
check_vpid |= grab_pteg2_ptr[pte_word2++] << 8;
check_vpid |= grab_pteg2_ptr[pte_word2++];
check_vpid = (check_vpid >> 7) & 0xFFFFFF;
if ((check_vpid >> 31) & 0x01){
if (vpid_known == check_vpid){
hash_found = true;
pteg_answer |= grab_pteg2_ptr[pte_word2++] << 24;
pteg_answer |= grab_pteg2_ptr[pte_word2++] << 16;
pteg_answer |= grab_pteg2_ptr[pte_word2++] << 8;
pteg_answer |= grab_pteg2_ptr[pte_word2++];
break;
}
else{
pte_word2 += 4;
check_vpid = 0;
}
}
else{
pte_word2 += 4;
check_vpid = 0;
}
}
else{
pte_word2 = entries_area;
}
}while (pte_word2 < entries_area);
}
void pteg_translate(uint32_t address_grab){
uint32_t choose_sr = (ppc_effective_address >> 28) & 0x0F;
pteg_hash1 = ppc_state.ppc_sr[choose_sr] & 0x7FFFF;
uint32_t page_index = (ppc_effective_address & 0xFFFF000) >> 12;
pteg_hash1 = (pteg_hash1 ^ page_index);
pteg_hash2 = ~pteg_hash1;
std::thread primary_pa_check(&primary_generate_pa);
std::thread secondary_pa_check(&secondary_generate_pa);
primary_pa_check.join();
secondary_pa_check.join();
uint32_t grab_val = ppc_state.ppc_sr[choose_sr] & 0xFFFFFF;
std::thread primary_pteg_check(&primary_hash_check, std::ref(grab_val));
std::thread secondary_pteg_check(&secondary_hash_check, std::ref(grab_val));
primary_pteg_check.join();
secondary_pteg_check.join();
} }
/** PowerPC-style MMU instruction address translation. */ /** PowerPC-style MMU instruction address translation. */
@ -476,19 +307,16 @@ uint32_t ppc_mmu_instr_translate(uint32_t la)
} }
} }
// Segment registers & page table translation /* page address translation */
if (!bat_hit){ if (!bat_hit) {
pteg_translate(la); pa = page_address_translate(la, true, msr_pr, false);
if (hash_found == true){
pa = (la & 0xFFF) | (pteg_answer & 0xFFFFF000);
}
} }
return pa; return pa;
} }
/** PowerPC-style MMU data address translation. */ /** PowerPC-style MMU data address translation. */
uint32_t ppc_mmu_addr_translate(uint32_t la, uint32_t access_type) uint32_t ppc_mmu_addr_translate(uint32_t la, bool is_write)
{ {
uint32_t pa; /* translated physical address */ uint32_t pa; /* translated physical address */
@ -514,12 +342,9 @@ uint32_t ppc_mmu_addr_translate(uint32_t la, uint32_t access_type)
} }
} }
// Segment registers & page table translation /* page address translation */
if (!bat_hit){ if (!bat_hit) {
pteg_translate(la); pa = page_address_translate(la, false, msr_pr, is_write);
if (hash_found == true){
pa = (la & 0xFFF) | (pteg_answer & 0xFFFFF000);
}
} }
return pa; return pa;
@ -534,7 +359,7 @@ void address_quickinsert_translate(uint32_t value, uint32_t addr, uint8_t num_by
{ {
/* data address translation if enabled */ /* data address translation if enabled */
if (ppc_state.ppc_msr & 0x10) { if (ppc_state.ppc_msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 0); addr = ppc_mmu_addr_translate(addr, true);
} }
if (addr >= write_last_pa_start && addr <= write_last_pa_end) { if (addr >= write_last_pa_start && addr <= write_last_pa_end) {
@ -568,7 +393,7 @@ void address_quickgrab_translate(uint32_t addr, uint8_t num_bytes)
{ {
/* data address translation if enabled */ /* data address translation if enabled */
if (ppc_state.ppc_msr & 0x10) { if (ppc_state.ppc_msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 0); addr = ppc_mmu_addr_translate(addr, false);
} }
if (addr >= read_last_pa_start && addr <= read_last_pa_end) { if (addr >= read_last_pa_start && addr <= read_last_pa_end) {
@ -596,29 +421,36 @@ void address_quickgrab_translate(uint32_t addr, uint8_t num_bytes)
} }
} }
/* remember recently used memory region for quicker translation. */
uint32_t exec_last_pa_start = 0; uint32_t exec_last_pa_start = 0;
uint32_t exec_last_pa_end = 0; uint32_t exec_last_pa_end = 0;
unsigned char *exec_last_ptr = 0; unsigned char *exec_last_ptr = 0;
void quickinstruction_translate(uint32_t addr) uint8_t *quickinstruction_translate(uint32_t addr)
{ {
/* instruction address translation if enabled */ uint8_t *real_addr;
/* perform instruction address translation if enabled */
if (ppc_state.ppc_msr & 0x20) { if (ppc_state.ppc_msr & 0x20) {
addr = ppc_mmu_instr_translate(addr); addr = ppc_mmu_instr_translate(addr);
} }
if (addr >= exec_last_pa_start && addr <= exec_last_pa_end) { if (addr >= exec_last_pa_start && addr <= exec_last_pa_end) {
ppc_set_cur_instruction(exec_last_ptr, addr - exec_last_pa_start); real_addr = exec_last_ptr + (addr - exec_last_pa_start);
ppc_set_cur_instruction(real_addr);
} else { } else {
AddressMapEntry *entry = mem_ctrl_instance->find_range(addr); AddressMapEntry *entry = mem_ctrl_instance->find_range(addr);
if (entry && entry->type & (RT_ROM | RT_RAM)) { if (entry && entry->type & (RT_ROM | RT_RAM)) {
exec_last_pa_start = entry->start; exec_last_pa_start = entry->start;
exec_last_pa_end = entry->end; exec_last_pa_end = entry->end;
exec_last_ptr = entry->mem_ptr; exec_last_ptr = entry->mem_ptr;
ppc_set_cur_instruction(exec_last_ptr, addr - exec_last_pa_start); real_addr = exec_last_ptr + (addr - exec_last_pa_start);
ppc_set_cur_instruction(real_addr);
} else { } else {
printf("WARNING: attempt to execute code at %08X!\n", addr); printf("WARNING: attempt to execute code at %08X!\n", addr);
exit(-1); // FIXME: ugly error handling, must be the proper exception!
} }
} }
return real_addr;
} }

View File

@ -25,27 +25,13 @@ typedef struct PPC_BAT_entry {
extern uint32_t bat_srch; extern uint32_t bat_srch;
extern uint32_t bepi_chk; extern uint32_t bepi_chk;
extern uint32_t msr_ir_test;
extern uint32_t msr_dr_test;
extern uint32_t msr_ip_test;
extern unsigned char * grab_macmem_ptr; extern unsigned char * grab_macmem_ptr;
/**
struct pte {
uint32_t page_index_no;
uint32_t entry[];
pte *next;
} PTE;
**/
extern void ibat_update(uint32_t bat_reg); extern void ibat_update(uint32_t bat_reg);
extern void dbat_update(uint32_t bat_reg); extern void dbat_update(uint32_t bat_reg);
extern void msr_status_update();
extern void address_quickinsert_translate(uint32_t value_insert, uint32_t address_grab, uint8_t num_bytes); extern void address_quickinsert_translate(uint32_t value_insert, uint32_t address_grab, uint8_t num_bytes);
extern void address_quickgrab_translate(uint32_t address_grab, uint8_t num_bytes); extern void address_quickgrab_translate(uint32_t address_grab, uint8_t num_bytes);
extern void quickinstruction_translate(uint32_t address_grab); extern uint8_t *quickinstruction_translate(uint32_t address_grab);
#endif // PPCMEMORY_H #endif // PPCMEMORY_H

View File

@ -1283,7 +1283,6 @@ void ppc_mtmsr(){
//if ((ppc_state.ppc_msr && 0x4000) == 0){ //if ((ppc_state.ppc_msr && 0x4000) == 0){
reg_s = (ppc_cur_instruction >> 21) & 31; reg_s = (ppc_cur_instruction >> 21) & 31;
ppc_state.ppc_msr = ppc_state.ppc_gpr[reg_s]; ppc_state.ppc_msr = ppc_state.ppc_gpr[reg_s];
msr_status_update();
//} //}
} }