mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 06:29:38 +00:00
ppcmmu: handle unaligned reads and writes.
This commit is contained in:
parent
f364efb4b0
commit
354b7b65be
@ -13,7 +13,6 @@
|
|||||||
- implement BAT access check
|
- implement BAT access check
|
||||||
- add proper error and exception handling
|
- add proper error and exception handling
|
||||||
- clarify what to do in the case of unaligned memory accesses
|
- clarify what to do in the case of unaligned memory accesses
|
||||||
- remove dependency on MPC106 (use generic memory controller interface instead)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -98,56 +97,6 @@ void ppc_set_cur_instruction(const uint8_t* ptr)
|
|||||||
ppc_cur_instruction = READ_DWORD_BE_A(ptr);
|
ppc_cur_instruction = READ_DWORD_BE_A(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ppc_memstore_16bit(unsigned char* ptr, uint16_t value, uint32_t offset) {
|
|
||||||
if (ppc_state.ppc_msr & 1) { /* little-endian byte ordering */
|
|
||||||
ptr[offset] = value & 0xFF;
|
|
||||||
ptr[offset + 1] = (value >> 8) & 0xFF;
|
|
||||||
}
|
|
||||||
else { /* big-endian byte ordering */
|
|
||||||
ptr[offset] = (value >> 8) & 0xFF;
|
|
||||||
ptr[offset + 1] = value & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ppc_memstore_32bit(unsigned char* ptr, uint32_t value, uint32_t offset) {
|
|
||||||
if (ppc_state.ppc_msr & 1) { /* little-endian byte ordering */
|
|
||||||
ptr[offset] = value & 0xFF;
|
|
||||||
ptr[offset + 1] = (value >> 8) & 0xFF;
|
|
||||||
ptr[offset + 2] = (value >> 16) & 0xFF;
|
|
||||||
ptr[offset + 3] = (value >> 24) & 0xFF;
|
|
||||||
}
|
|
||||||
else { /* big-endian byte ordering */
|
|
||||||
ptr[offset] = (value >> 24) & 0xFF;
|
|
||||||
ptr[offset + 1] = (value >> 16) & 0xFF;
|
|
||||||
ptr[offset + 2] = (value >> 8) & 0xFF;
|
|
||||||
ptr[offset + 3] = value & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ppc_memstore_64bit(unsigned char* ptr, uint64_t value, uint32_t offset) {
|
|
||||||
if (ppc_state.ppc_msr & 1) { /* little-endian byte ordering */
|
|
||||||
ptr[offset] = value & 0xFF;
|
|
||||||
ptr[offset + 1] = (value >> 8) & 0xFF;
|
|
||||||
ptr[offset + 2] = (value >> 16) & 0xFF;
|
|
||||||
ptr[offset + 3] = (value >> 24) & 0xFF;
|
|
||||||
ptr[offset + 4] = (value >> 32) & 0xFF;
|
|
||||||
ptr[offset + 5] = (value >> 40) & 0xFF;
|
|
||||||
ptr[offset + 6] = (value >> 48) & 0xFF;
|
|
||||||
ptr[offset + 7] = (value >> 56) & 0xFF;
|
|
||||||
}
|
|
||||||
else { /* big-endian byte ordering */
|
|
||||||
ptr[offset] = (value >> 56) & 0xFF;
|
|
||||||
ptr[offset + 1] = (value >> 48) & 0xFF;
|
|
||||||
ptr[offset + 2] = (value >> 40) & 0xFF;
|
|
||||||
ptr[offset + 3] = (value >> 32) & 0xFF;
|
|
||||||
ptr[offset + 4] = (value >> 24) & 0xFF;
|
|
||||||
ptr[offset + 5] = (value >> 16) & 0xFF;
|
|
||||||
ptr[offset + 6] = (value >> 8) & 0xFF;
|
|
||||||
ptr[offset + 7] = value & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ibat_update(uint32_t bat_reg)
|
void ibat_update(uint32_t bat_reg)
|
||||||
{
|
{
|
||||||
int upper_reg_num;
|
int upper_reg_num;
|
||||||
@ -401,6 +350,27 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write)
|
|||||||
return pa;
|
return pa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size)
|
||||||
|
{
|
||||||
|
printf("WARNING! Attempt to write unaligned %d bytes to 0x%08X\n", size, addr);
|
||||||
|
|
||||||
|
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||||
|
printf("SOS! Cross-page unaligned write, addr=%08X, size=%d\n", addr, size);
|
||||||
|
exit(-1); //FIXME!
|
||||||
|
} else {
|
||||||
|
/* data address translation if enabled */
|
||||||
|
if (ppc_state.ppc_msr & 0x10) {
|
||||||
|
addr = ppc_mmu_addr_translate(addr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 2) {
|
||||||
|
WRITE_PHYS_MEM(last_write_area, addr, WRITE_WORD_BE_U, value, 2);
|
||||||
|
} else {
|
||||||
|
WRITE_PHYS_MEM(last_write_area, addr, WRITE_DWORD_BE_U, value, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mem_write_byte(uint32_t addr, uint8_t value)
|
void mem_write_byte(uint32_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
/* data address translation if enabled */
|
/* data address translation if enabled */
|
||||||
@ -415,6 +385,10 @@ void mem_write_byte(uint32_t addr, uint8_t value)
|
|||||||
|
|
||||||
void mem_write_word(uint32_t addr, uint16_t value)
|
void mem_write_word(uint32_t addr, uint16_t value)
|
||||||
{
|
{
|
||||||
|
if (addr & 1) {
|
||||||
|
mem_write_unaligned(addr, value, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, 1);
|
addr = ppc_mmu_addr_translate(addr, 1);
|
||||||
@ -425,6 +399,10 @@ void mem_write_word(uint32_t addr, uint16_t value)
|
|||||||
|
|
||||||
void mem_write_dword(uint32_t addr, uint32_t value)
|
void mem_write_dword(uint32_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
|
if (addr & 3) {
|
||||||
|
mem_write_unaligned(addr, value, 4);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, 1);
|
addr = ppc_mmu_addr_translate(addr, 1);
|
||||||
@ -435,6 +413,11 @@ void mem_write_dword(uint32_t addr, uint32_t value)
|
|||||||
|
|
||||||
void mem_write_qword(uint32_t addr, uint64_t value)
|
void mem_write_qword(uint32_t addr, uint64_t value)
|
||||||
{
|
{
|
||||||
|
if (addr & 7) {
|
||||||
|
printf("SOS! Attempt to write unaligned QWORD to 0x%08X\n", addr);
|
||||||
|
exit(-1); //FIXME!
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, 1);
|
addr = ppc_mmu_addr_translate(addr, 1);
|
||||||
@ -443,6 +426,31 @@ void mem_write_qword(uint32_t addr, uint64_t value)
|
|||||||
WRITE_PHYS_MEM(last_write_area, addr, WRITE_QWORD_BE_A, value, 8);
|
WRITE_PHYS_MEM(last_write_area, addr, WRITE_QWORD_BE_A, value, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
printf("WARNING! Attempt to read unaligned %d bytes from 0x%08X\n", size, addr);
|
||||||
|
|
||||||
|
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||||
|
printf("SOS! Cross-page unaligned read, addr=%08X, size=%d\n", addr, size);
|
||||||
|
exit(-1); //FIXME!
|
||||||
|
} else {
|
||||||
|
/* data address translation if enabled */
|
||||||
|
if (ppc_state.ppc_msr & 0x10) {
|
||||||
|
addr = ppc_mmu_addr_translate(addr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 2) {
|
||||||
|
READ_PHYS_MEM(last_read_area, addr, READ_WORD_BE_U, 2, 0xFFFFU);
|
||||||
|
} else {
|
||||||
|
READ_PHYS_MEM(last_read_area, addr, READ_DWORD_BE_U, 4, 0xFFFFFFFFUL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/** Grab a value from memory into a register */
|
/** Grab a value from memory into a register */
|
||||||
uint8_t mem_grab_byte(uint32_t addr)
|
uint8_t mem_grab_byte(uint32_t addr)
|
||||||
{
|
{
|
||||||
@ -461,6 +469,10 @@ uint16_t mem_grab_word(uint32_t addr)
|
|||||||
{
|
{
|
||||||
uint16_t ret;
|
uint16_t ret;
|
||||||
|
|
||||||
|
if (addr & 1) {
|
||||||
|
return mem_grab_unaligned(addr, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, 0);
|
||||||
@ -474,6 +486,10 @@ uint32_t mem_grab_dword(uint32_t addr)
|
|||||||
{
|
{
|
||||||
uint32_t ret;
|
uint32_t ret;
|
||||||
|
|
||||||
|
if (addr & 3) {
|
||||||
|
return mem_grab_unaligned(addr, 4);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, 0);
|
||||||
@ -487,6 +503,11 @@ uint64_t mem_grab_qword(uint32_t addr)
|
|||||||
{
|
{
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
|
|
||||||
|
if (addr & 7) {
|
||||||
|
printf("SOS! Attempt to read unaligned QWORD at 0x%08X\n", addr);
|
||||||
|
exit(-1); //FIXME!
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, 0);
|
||||||
|
@ -62,4 +62,20 @@
|
|||||||
/* write an aligned big-endian QWORD (64bit) */
|
/* write an aligned big-endian QWORD (64bit) */
|
||||||
#define WRITE_QWORD_BE_A(addr,val) (*((uint64_t *)((addr))) = BYTESWAP_64(val))
|
#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; \
|
||||||
|
} 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; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#endif /* MEM_READ_WRITE_H */
|
#endif /* MEM_READ_WRITE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user