Compare commits

..

No commits in common. "c6ea3a374e930655a7c827b52111d520678698e5" and "9c95bc17fefd73b085282cb634f0f4e303ed5d8a" have entirely different histories.

15 changed files with 237 additions and 353 deletions

View File

@ -27,10 +27,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "ppcmmu.h"
#include <stdint.h>
// Affects the XER register's SO and OV Bits
inline void power_setsoov(uint32_t a, uint32_t b, uint32_t d) {
if ((a ^ b) & (a ^ d) & 0x80000000UL) {
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
}
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
static inline uint32_t power_rot_mask(unsigned rot_mb, unsigned rot_me) {
uint32_t m1 = 0xFFFFFFFFU >> rot_mb;
uint32_t m2 = 0xFFFFFFFFU << (31 - rot_me);
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
uint32_t m2 = uint32_t(0xFFFFFFFFUL << (31 - rot_me));
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
}
@ -42,10 +52,9 @@ void dppc_interpreter::power_abs() {
ppc_result_d = ppc_result_a;
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_result_d = (int32_t(ppc_result_a) < 0) ? -ppc_result_a : ppc_result_a;
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
}
if (rec)
@ -67,17 +76,10 @@ void dppc_interpreter::power_clcs() {
case 13: //data cache line size
case 14: //minimum line size
case 15: //maximum line size
default: ppc_result_d = is_601 ? 64 : 32; break;
case 7:
case 23: ppc_result_d = is_601 ? 64 : 0; break;
case 8:
case 9:
case 24:
case 25: ppc_result_d = is_601 ? 64 : 4; break;
case 10:
case 11:
case 26:
case 27: ppc_result_d = is_601 ? 64 : 0x4000; break;
ppc_result_d = 64;
break;
default:
ppc_result_d = 0;
}
ppc_store_iresult_reg(reg_d, ppc_result_d);
@ -88,39 +90,23 @@ void dppc_interpreter::power_div() {
uint32_t ppc_result_d;
ppc_grab_regsdab(ppc_cur_instruction);
int64_t dividend = (uint64_t(ppc_result_a) << 32) | ppc_state.spr[SPR::MQ];
int32_t divisor = ppc_result_b;
int64_t quotient;
int32_t remainder;
uint64_t dividend = ((uint64_t)ppc_result_a << 32) | ppc_state.spr[SPR::MQ];
int32_t divisor = ppc_result_b;
if (dividend == -0x80000000 && divisor == -1) {
remainder = 0;
ppc_result_d = 0x80000000U; // -2^31 aka INT32_MIN
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else if (!divisor) {
remainder = 0;
ppc_result_d = 0x80000000U; // -2^31 aka INT32_MIN
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
if ((ppc_result_a == 0x80000000UL && divisor == -1) || !divisor) {
ppc_state.spr[SPR::MQ] = 0;
ppc_result_d = 0x80000000UL; // -2^31 aka INT32_MIN
} else {
quotient = dividend / divisor;
remainder = dividend % divisor;
ppc_result_d = uint32_t(quotient);
if (ov) {
if (((quotient >> 31) + 1) & ~1) {
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
}
ppc_result_d = uint32_t(dividend / divisor);
ppc_state.spr[SPR::MQ] = dividend % divisor;
}
if (ov)
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
if (rec)
ppc_changecrf0(remainder);
ppc_changecrf0(ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_state.spr[SPR::MQ] = remainder;
}
template void dppc_interpreter::power_div<RC0, OV0>();
@ -130,31 +116,16 @@ template void dppc_interpreter::power_div<RC1, OV1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_divs() {
uint32_t ppc_result_d;
int32_t remainder;
ppc_grab_regsdab(ppc_cur_instruction);
uint32_t ppc_result_d = ppc_result_a / ppc_result_b;
ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
if (!ppc_result_b) { // handle the "anything / 0" case
ppc_result_d = -1;
remainder = ppc_result_a;
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else if (ppc_result_a == 0x80000000U && ppc_result_b == 0xFFFFFFFFU) {
ppc_result_d = 0x80000000U;
remainder = 0;
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else { // normal signed devision
ppc_result_d = int32_t(ppc_result_a) / int32_t(ppc_result_b);
remainder = (int32_t(ppc_result_a) % int32_t(ppc_result_b));
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
if (ov)
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
if (rec)
ppc_changecrf0(remainder);
ppc_changecrf0(ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_state.spr[SPR::MQ] = remainder;
}
template void dppc_interpreter::power_divs<RC0, OV0>();
@ -165,18 +136,13 @@ template void dppc_interpreter::power_divs<RC1, OV1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_doz() {
ppc_grab_regsdab(ppc_cur_instruction);
uint32_t ppc_result_d = (int32_t(ppc_result_a) < int32_t(ppc_result_b)) ?
ppc_result_b - ppc_result_a : 0;
uint32_t ppc_result_d = (int32_t(ppc_result_a) >= int32_t(ppc_result_b)) ? 0 :
ppc_result_b - ppc_result_a;
if (ov) {
if (int32_t(ppc_result_d) < 0) {
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
}
if (rec)
ppc_changecrf0(ppc_result_d);
if (ov)
power_setsoov(ppc_result_a, ppc_result_b, ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
}
@ -202,50 +168,47 @@ void dppc_interpreter::power_lscbx() {
ppc_grab_regsdab(ppc_cur_instruction);
ppc_effective_address = ppc_result_b + (reg_a ? ppc_result_a : 0);
uint8_t return_value = 0;
uint32_t bytes_to_load = (ppc_state.spr[SPR::XER] & 0x7F);
uint32_t bytes_remaining = bytes_to_load;
uint32_t bytes_copied = 0;
uint8_t matching_byte = (uint8_t)(ppc_state.spr[SPR::XER] >> 8);
uint32_t ppc_result_d = 0;
bool is_match = false;
uint32_t ppc_result_d = 0;
// for storing each byte
uint32_t bitmask = 0xFF000000;
uint8_t shift_amount = 24;
while (bytes_remaining > 0) {
uint8_t return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
while (bytes_to_load > 0) {
return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
ppc_result_d |= return_value << shift_amount;
ppc_result_d = (ppc_result_d & ~bitmask) | (return_value << shift_amount);
if (!shift_amount) {
if (reg_d != reg_a && reg_d != reg_b)
ppc_store_iresult_reg(reg_d, ppc_result_d);
reg_d = (reg_d + 1) & 0x1F;
ppc_result_d = 0;
bitmask = 0xFF000000;
shift_amount = 24;
} else {
bitmask >>= 8;
shift_amount -= 8;
}
ppc_effective_address++;
bytes_remaining--;
bytes_copied++;
bytes_to_load--;
if (return_value == matching_byte) {
is_match = true;
if (return_value == matching_byte)
break;
}
}
// store partially loaded register if any
// store partiallly loaded register if any
if (shift_amount != 24 && reg_d != reg_a && reg_d != reg_b)
ppc_store_iresult_reg(reg_d, ppc_result_d);
ppc_state.spr[SPR::XER] = (ppc_state.spr[SPR::XER] & ~0x7F) | (bytes_to_load - bytes_remaining);
ppc_state.spr[SPR::XER] = (ppc_state.spr[SPR::XER] & ~0x7F) | bytes_copied;
if (rec) {
ppc_state.cr =
(ppc_state.cr & 0x0FFFFFFFUL) |
(is_match ? CRx_bit::CR_EQ : 0) |
((ppc_state.spr[SPR::XER] & XER::SO) >> 3);
}
if (rec)
ppc_changecrf0(ppc_result_d);
}
template void dppc_interpreter::power_lscbx<RC0>();
@ -271,7 +234,7 @@ void dppc_interpreter::power_maskg() {
ppc_result_a = insert_mask;
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_changecrf0(ppc_result_d);
ppc_store_iresult_reg(reg_a, ppc_result_a);
}
@ -296,19 +259,17 @@ template void dppc_interpreter::power_maskir<RC1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_mul() {
ppc_grab_regsdab(ppc_cur_instruction);
int64_t product = int64_t(int32_t(ppc_result_a)) * int32_t(ppc_result_b);
uint32_t ppc_result_d = uint32_t(uint64_t(product) >> 32);
ppc_state.spr[SPR::MQ] = uint32_t(product);
uint64_t product;
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
uint32_t ppc_result_d = ((uint32_t)(product >> 32));
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
if (ov) {
if (uint64_t(product >> 31) + 1 & ~1) {
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_state.spr[SPR::XER] &= ~XER::OV;
}
}
if (rec)
ppc_changecrf0(uint32_t(product));
ppc_changecrf0(ppc_result_d);
if (ov)
power_setsoov(ppc_result_a, ppc_result_b, ppc_result_d);
ppc_store_iresult_reg(reg_d, ppc_result_d);
}
@ -320,12 +281,12 @@ template void dppc_interpreter::power_mul<RC1, OV1>();
template <field_rc rec, field_ov ov>
void dppc_interpreter::power_nabs() {
ppc_grab_regsda(ppc_cur_instruction);
uint32_t ppc_result_d = (int32_t(ppc_result_a) < 0) ? ppc_result_a : -ppc_result_a;
uint32_t ppc_result_d = ppc_result_a & 0x80000000 ? ppc_result_a : -ppc_result_a;
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
if (rec)
ppc_changecrf0(ppc_result_d);
if (ov)
ppc_state.spr[SPR::XER] &= ~XER::OV;
ppc_store_iresult_reg(reg_d, ppc_result_d);
}
@ -355,12 +316,11 @@ void dppc_interpreter::power_rlmi() {
template <field_rc rec>
void dppc_interpreter::power_rrib() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
if (int32_t(ppc_result_d) < 0) {
ppc_result_a |= (0x80000000U >> rot_sh);
if (ppc_result_d & 0x80000000) {
ppc_result_a |= ((ppc_result_d & 0x80000000) >> ppc_result_b);
} else {
ppc_result_a &= ~(0x80000000U >> rot_sh);
ppc_result_a &= ~((ppc_result_d & 0x80000000) >> ppc_result_b);
}
if (rec)
@ -412,7 +372,8 @@ template void dppc_interpreter::power_sleq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sliq() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
ppc_result_a = ppc_result_d << rot_sh;
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
@ -428,7 +389,8 @@ template void dppc_interpreter::power_sliq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_slliq() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
uint32_t mask = power_rot_mask(0, 31 - rot_sh);
@ -448,11 +410,14 @@ template <field_rc rec>
void dppc_interpreter::power_sllq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
uint32_t mask = power_rot_mask(0, 31 - rot_sh);
if (ppc_result_b & 0x20) {
ppc_result_a = ppc_state.spr[SPR::MQ] & (-1U << rot_sh);
} else {
ppc_result_a = ((ppc_result_d << rot_sh) | (ppc_state.spr[SPR::MQ] & ((1 << rot_sh) - 1)));
if (ppc_result_b >= 0x20) {
ppc_result_a = (ppc_state.spr[SPR::MQ] & mask);
}
else {
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
}
if (rec)
@ -469,17 +434,16 @@ void dppc_interpreter::power_slq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
if (ppc_result_b & 0x20) {
ppc_result_a = 0;
} else {
if (ppc_result_b >= 0x20) {
ppc_result_a = ppc_result_d << rot_sh;
} else {
ppc_result_a = 0;
}
if (rec)
ppc_changecrf0(ppc_result_a);
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
ppc_store_iresult_reg(reg_a, ppc_result_a);
}
template void dppc_interpreter::power_slq<RC0>();
@ -487,12 +451,13 @@ template void dppc_interpreter::power_slq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sraiq() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
uint32_t mask = (1 << rot_sh) - 1;
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & mask)) {
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
ppc_state.spr[SPR::XER] |= XER::CA;
} else {
ppc_state.spr[SPR::XER] &= ~XER::CA;
@ -511,11 +476,11 @@ template <field_rc rec>
void dppc_interpreter::power_sraq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
uint32_t mask = (ppc_result_b & 0x20) ? -1 : (1 << rot_sh) - 1;
ppc_result_a = (int32_t)ppc_result_d >> ((ppc_result_b & 0x20) ? 31 : rot_sh);
uint32_t mask = (1 << rot_sh) - 1;
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & mask)) {
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
ppc_state.spr[SPR::XER] |= XER::CA;
} else {
ppc_state.spr[SPR::XER] &= ~XER::CA;
@ -555,10 +520,9 @@ void dppc_interpreter::power_srea() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
uint32_t r = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
uint32_t mask = -1U >> rot_sh;
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
if ((int32_t(ppc_result_d) < 0) && (r & ~mask)) {
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & rot_sh)) {
ppc_state.spr[SPR::XER] |= XER::CA;
} else {
ppc_state.spr[SPR::XER] &= ~XER::CA;
@ -568,7 +532,6 @@ void dppc_interpreter::power_srea() {
ppc_changecrf0(ppc_result_a);
ppc_store_iresult_reg(reg_a, ppc_result_a);
ppc_state.spr[SPR::MQ] = r;
}
template void dppc_interpreter::power_srea<RC0>();
@ -578,10 +541,10 @@ template <field_rc rec>
void dppc_interpreter::power_sreq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
uint32_t mask = -1U >> rot_sh;
unsigned mask = power_rot_mask(rot_sh, 31);
ppc_result_a = (ppc_result_d >> rot_sh) | (ppc_state.spr[SPR::MQ] & ~mask);
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
ppc_result_a = ((rot_sh & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
ppc_state.spr[SPR::MQ] = rot_sh;
if (rec)
ppc_changecrf0(ppc_result_a);
@ -594,7 +557,8 @@ template void dppc_interpreter::power_sreq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_sriq() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
ppc_result_a = ppc_result_d >> rot_sh;
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
@ -609,7 +573,8 @@ template void dppc_interpreter::power_sriq<RC1>();
template <field_rc rec>
void dppc_interpreter::power_srliq() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
unsigned mask = power_rot_mask(rot_sh, 31);
@ -632,9 +597,10 @@ void dppc_interpreter::power_srlq() {
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
unsigned mask = power_rot_mask(rot_sh, 31);
if (ppc_result_b & 0x20) {
if (ppc_result_b >= 0x20) {
ppc_result_a = (ppc_state.spr[SPR::MQ] & mask);
} else {
}
else {
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
}
@ -652,7 +618,7 @@ void dppc_interpreter::power_srq() {
ppc_grab_regssab(ppc_cur_instruction);
unsigned rot_sh = ppc_result_b & 0x1F;
if (ppc_result_b & 0x20) {
if (ppc_result_b >= 0x20) {
ppc_result_a = 0;
} else {
ppc_result_a = ppc_result_d >> rot_sh;

View File

@ -85,18 +85,17 @@ extern SetPRS ppc_state;
/** symbolic names for frequently used SPRs */
enum SPR : int {
MQ = 0, // MQ (601)
MQ = 0,
XER = 1,
RTCU_U = 4, // user mode RTCU (601)
RTCL_U = 5, // user mode RTCL (601)
DEC_U = 6, // user mode decrementer (601)
RTCU_U = 4, // user RTCU
RTCL_U = 5, // user RTCL
LR = 8,
CTR = 9,
DSISR = 18,
DAR = 19,
RTCU_S = 20, // supervisor RTCU (601)
RTCL_S = 21, // supervisor RTCL (601)
DEC_S = 22, // supervisor decrementer
RTCU_S = 20, // supervisor RTCU
RTCL_S = 21, // supervisor RTCL
DEC = 22, // decrementer
SDR1 = 25,
SRR0 = 26,
SRR1 = 27,
@ -399,7 +398,7 @@ typedef enum {
} field_601;
// Function prototypes
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601, uint64_t tb_freq);
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq);
extern void ppc_mmu_init();
void ppc_illegalop();
@ -415,7 +414,7 @@ void ppc_opcode31();
void ppc_opcode59();
void ppc_opcode63();
void initialize_ppc_opcode_tables(bool include_601);
void initialize_ppc_opcode_tables();
extern double fp_return_double(uint32_t reg);
extern uint64_t fp_return_uint64(uint32_t reg);

View File

@ -586,13 +586,13 @@ do { \
#define OP63d(subopcode, fn) OPXd(SubOpcode63, subopcode, fn)
#define OP63dc(subopcode, fn, carry) OPXdc(SubOpcode63, subopcode, fn, carry)
void initialize_ppc_opcode_tables(bool include_601) {
void initialize_ppc_opcode_tables() {
std::fill_n(OpcodeGrabber, 64, ppc_illegalop);
OP(3, ppc_twi);
//OP(4, ppc_opcode4); - Altivec instructions not emulated yet. Uncomment once they're implemented.
OP(7, ppc_mulli);
OP(8, ppc_subfic);
if (is_601 || include_601) OP(9, power_dozi);
if (is_601) OP(9, power_dozi);
OP(10, ppc_cmpli);
OP(11, ppc_cmpi);
OP(12, ppc_addic<RC0>);
@ -605,7 +605,7 @@ void initialize_ppc_opcode_tables(bool include_601) {
if (is_601) OP(19, ppc_opcode19<IS601>); else OP(19, ppc_opcode19<NOT601>);
OP(20, ppc_rlwimi);
OP(21, ppc_rlwinm);
if (is_601 || include_601) OP(22, power_rlmi);
if (is_601) OP(22, power_rlmi);
OP(23, ppc_rlwnm);
OP(24, ppc_ori<SHFT0>);
OP(25, ppc_ori<SHFT1>);
@ -741,7 +741,7 @@ void initialize_ppc_opcode_tables(bool include_601) {
OP31(470, ppc_dcbi);
OP31(1014, ppc_dcbz);
if (is_601 || include_601) {
if (is_601) {
OP31d(29, power_maskg);
OP31od(107, power_mul);
OP31d(152, power_slq);
@ -822,7 +822,7 @@ void initialize_ppc_opcode_tables(bool include_601) {
}
}
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601, uint64_t tb_freq)
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
{
int i;
@ -834,7 +834,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601,
ppc_state.spr[SPR::PVR] = cpu_version;
is_601 = (cpu_version >> 16) == 1;
initialize_ppc_opcode_tables(include_601);
initialize_ppc_opcode_tables();
// initialize emulator timers
TimerManager::get_instance()->set_time_now_cb(&get_virt_time_ns);
@ -864,8 +864,8 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601,
/* MPC601 sets MSR[ME] bit during hard reset / Power-On */
ppc_state.msr = (MSR::ME + MSR::IP);
} else {
ppc_state.msr = MSR::IP;
ppc_state.spr[SPR::DEC_S] = 0xFFFFFFFFUL;
ppc_state.msr = MSR::IP;
ppc_state.spr[SPR::DEC] = 0xFFFFFFFFUL;
}
ppc_mmu_init();
@ -885,10 +885,10 @@ void print_fprs() {
}
static map<string, int> SPRName2Num = {
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR},
{"DEC", SPR::DEC_S}, {"PVR", SPR::PVR}, {"SPRG0", SPR::SPRG0},
{"SPRG1", SPR::SPRG1}, {"SPRG2", SPR::SPRG2}, {"SPRG3", SPR::SPRG3},
{"SRR0", SPR::SRR0}, {"SRR1", SPR::SRR1}, {"IBAT0U", 528},
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR},
{"DEC", SPR::DEC}, {"PVR", SPR::PVR}, {"SPRG0", SPR::SPRG0},
{"SPRG1", SPR::SPRG1}, {"SPRG2", SPR::SPRG2}, {"SPRG3", SPR::SPRG3},
{"SRR0", SPR::SRR0}, {"SRR1", SPR::SRR1}, {"IBAT0U", 528},
{"IBAT0L", 529}, {"IBAT1U", 530}, {"IBAT1L", 531},
{"IBAT2U", 532}, {"IBAT2L", 533}, {"IBAT3U", 534},
{"IBAT3L", 535}, {"DBAT0U", 536}, {"DBAT0L", 537},
@ -897,9 +897,9 @@ static map<string, int> SPRName2Num = {
{"HID0", SPR::HID0}, {"HID1", SPR::HID1}, {"IABR", 1010},
{"DABR", 1013}, {"L2CR", 1017}, {"ICTC", 1019},
{"THRM1", 1020}, {"THRM2", 1021}, {"THRM3", 1022},
{"PIR", 1023}, {"TBL", SPR::TBL_S}, {"TBU", SPR::TBU_S},
{"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_S},
{"RTCL", SPR::RTCL_S}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR},
{"PIR", 1023}, {"TBL", SPR::TBL_U}, {"TBU", SPR::TBU_U},
{"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_U},
{"RTCL", SPR::RTCL_U}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR},
{"MMCR0", SPR::MMCR0}, {"PMC1", SPR::PMC1}, {"PMC2", SPR::PMC2},
{"SDA", SPR::SDA}, {"SIA", SPR::SIA}, {"MMCR1", SPR::MMCR1}
};
@ -974,13 +974,6 @@ uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
reg_num_str = reg_name_u.substr(3);
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
if (reg_num < 1024) {
switch (reg_num) {
case SPR::DEC_U : reg_num = SPR::DEC_S ; break;
case SPR::RTCL_U : reg_num = SPR::RTCL_S ; break;
case SPR::RTCU_U : reg_num = SPR::RTCU_S ; break;
case SPR::TBL_U : reg_num = SPR::TBL_S ; break;
case SPR::TBU_U : reg_num = SPR::TBU_S ; break;
}
if (is_write)
ppc_state.spr[reg_num] = (uint32_t)val;
return ppc_state.spr[reg_num];

View File

@ -74,12 +74,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regssash(opcode) \
uint32_t reg_s = (opcode >> 21) & 31; \
uint32_t reg_a = (opcode >> 16) & 31; \
uint32_t rot_sh = (opcode >> 11) & 31; \
uint32_t ppc_result_d = ppc_state.gpr[reg_s]; \
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
#define ppc_grab_regssb(opcode) \
uint32_t reg_s = (opcode >> 21) & 31; \
@ -175,4 +169,4 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
double val_reg_b = GET_FPR(reg_b); \
double val_reg_c = GET_FPR(reg_c);
#endif // PPC_MACROS_H
#endif // PPC_MACROS_H

View File

@ -33,17 +33,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// Affects CR Field 0 - For integer operations
void ppc_changecrf0(uint32_t set_result) {
ppc_state.cr =
(ppc_state.cr & 0x0FFFFFFFU) // clear CR0
| (
(set_result == 0) ?
CRx_bit::CR_EQ
: (int32_t(set_result) < 0) ?
CRx_bit::CR_LT
:
CRx_bit::CR_GT
)
| ((ppc_state.spr[SPR::XER] & XER::SO) >> 3); // copy XER[SO] into CR0[SO].
ppc_state.cr &= 0x0FFFFFFFUL;
if (set_result == 0) {
ppc_state.cr |= 0x20000000UL;
} else {
if (set_result & 0x80000000) {
ppc_state.cr |= 0x80000000UL;
} else {
ppc_state.cr |= 0x40000000UL;
}
}
/* copy XER[SO] into CR0[SO]. */
ppc_state.cr |= (ppc_state.spr[SPR::XER] >> 3) & 0x10000000UL;
}
// Affects the XER register's Carry Bit
@ -66,7 +69,7 @@ inline void ppc_carry_sub(uint32_t a, uint32_t b) {
// Affects the XER register's SO and OV Bits
inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) {
if (int32_t((a ^ b) & (a ^ d)) < 0) {
if ((a ^ b) & (a ^ d) & 0x80000000UL) {
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
} else {
ppc_state.spr[SPR::XER] &= ~XER::OV;
@ -530,7 +533,7 @@ void dppc_interpreter::ppc_divw() {
if (!ppc_result_b) { // handle the "anything / 0" case
ppc_result_d = 0; // tested on G4 in Mac OS X 10.4 and Open Firmware.
// ppc_result_d = (int32_t(ppc_result_a) < 0) ? -1 : 0; /* UNDOCUMENTED! */
// ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
if (ov)
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
@ -629,7 +632,7 @@ void dppc_interpreter::ppc_sraw() {
} else {
uint32_t shift = ppc_result_b & 0x1F;
ppc_result_a = int32_t(ppc_result_d) >> shift;
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & ((1U << shift) - 1)))
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & ((1U << shift) - 1)))
ppc_state.spr[SPR::XER] |= XER::CA;
}
@ -644,15 +647,16 @@ template void dppc_interpreter::ppc_sraw<RC1>();
template <field_rc rec>
void dppc_interpreter::ppc_srawi() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
uint32_t shift = (ppc_cur_instruction >> 11) & 0x1F;
// clear XER[CA] by default
ppc_state.spr[SPR::XER] &= ~XER::CA;
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & ((1U << rot_sh) - 1)))
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & ((1U << shift) - 1)))
ppc_state.spr[SPR::XER] |= XER::CA;
ppc_result_a = int32_t(ppc_result_d) >> rot_sh;
ppc_result_a = int32_t(ppc_result_d) >> shift;
if (rec)
ppc_changecrf0(ppc_result_a);
@ -671,7 +675,8 @@ static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) {
}
void dppc_interpreter::ppc_rlwimi() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
unsigned rot_mb = (ppc_cur_instruction >> 6) & 0x1F;
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
uint32_t mask = rot_mask(rot_mb, rot_me);
@ -685,7 +690,8 @@ void dppc_interpreter::ppc_rlwimi() {
}
void dppc_interpreter::ppc_rlwinm() {
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
unsigned rot_mb = (ppc_cur_instruction >> 6) & 0x1F;
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
uint32_t mask = rot_mask(rot_mb, rot_me);
@ -885,118 +891,74 @@ static void update_decrementer(uint32_t val) {
}
void dppc_interpreter::ppc_mfspr() {
ppc_grab_dab(ppc_cur_instruction);
uint32_t ref_spr = (reg_b << 5) | reg_a;
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
((ppc_cur_instruction >> 16) & 0x1F);
if (ref_spr & 0x10) {
#ifdef CPU_PROFILING
if (ref_spr > 31) {
num_supervisor_instrs++;
#endif
if (ppc_state.msr & MSR::PR) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::NOT_ALLOWED);
}
}
#endif
switch (ref_spr) {
case SPR::MQ:
if (!is_601) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr];
break;
case SPR::RTCL_U:
if (!is_601) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
calc_rtcl_value();
ppc_state.gpr[reg_d] =
ppc_state.spr[SPR::RTCL_S] = rtc_lo & 0x3FFFFF80UL;
ppc_state.spr[SPR::RTCU_S] = rtc_hi;
ppc_state.spr[SPR::RTCL_U] = rtc_lo & 0x3FFFFF80UL;
break;
case SPR::RTCU_U:
if (!is_601) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
calc_rtcl_value();
ppc_state.gpr[reg_d] =
ppc_state.spr[SPR::RTCU_S] = rtc_hi;
ppc_state.spr[SPR::RTCL_S] = rtc_lo;
ppc_state.spr[SPR::RTCU_U] = rtc_hi;
break;
case SPR::DEC_U:
if (!is_601) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
// fallthrough
case SPR::DEC_S:
ppc_state.gpr[reg_d] = ppc_state.spr[SPR::DEC_S] = calc_dec_value();
case SPR::DEC:
ppc_state.spr[SPR::DEC] = calc_dec_value();
break;
default:
// FIXME: Unknown SPR should be noop or illegal instruction.
ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr];
}
ppc_state.gpr[(ppc_cur_instruction >> 21) & 0x1F] = ppc_state.spr[ref_spr];
}
void dppc_interpreter::ppc_mtspr() {
ppc_grab_dab(ppc_cur_instruction);
uint32_t ref_spr = (reg_b << 5) | reg_a;
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
((ppc_cur_instruction >> 16) & 0x1F);
if (ref_spr & 0x10) {
#ifdef CPU_PROFILING
if (ref_spr > 31) {
num_supervisor_instrs++;
}
#endif
if (ppc_state.msr & MSR::PR) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::NOT_ALLOWED);
}
if (ref_spr == SPR::PVR || (
ref_spr == SPR::MQ && !is_601
)) { // prevent writes to the read-only registers
return;
}
uint32_t val = ppc_state.gpr[reg_d];
uint32_t val = ppc_state.gpr[(ppc_cur_instruction >> 21) & 0x1F];
ppc_state.spr[ref_spr] = val;
switch (ref_spr) {
case SPR::MQ:
if (!is_601) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
ppc_state.spr[ref_spr] = val;
break;
case SPR::RTCL_U:
case SPR::RTCU_U:
case SPR::DEC_U:
if (!is_601) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
break;
case SPR::XER:
ppc_state.spr[ref_spr] = val & 0xe000ff7f;
break;
case SPR::SDR1:
ppc_state.spr[ref_spr] = val;
mmu_pat_ctx_changed(); // adapt to SDR1 changes
break;
case SPR::RTCL_S:
calc_rtcl_value();
ppc_state.spr[RTCL_S] = rtc_lo = val & 0x3FFFFF80UL;
ppc_state.spr[RTCU_S] = rtc_hi;
rtc_lo = val & 0x3FFFFF80UL;
break;
case SPR::RTCU_S:
calc_rtcl_value();
ppc_state.spr[RTCL_S] = rtc_lo;
ppc_state.spr[RTCU_S] = rtc_hi = val;
rtc_hi = val;
break;
case SPR::DEC_S:
ppc_state.spr[DEC_S] = val;
case SPR::DEC:
update_decrementer(val);
break;
case SPR::TBL_S:
update_timebase(0xFFFFFFFF00000000ULL, val);
ppc_state.spr[TBL_S] = val;
ppc_state.spr[TBU_S] = tbr_wr_value >> 32;
break;
case SPR::TBU_S:
update_timebase(0x00000000FFFFFFFFULL, uint64_t(val) << 32);
ppc_state.spr[TBL_S] = (uint32_t)tbr_wr_value;
ppc_state.spr[TBU_S] = val;
break;
case SPR::PVR:
break;
case 528:
case 529:
@ -1006,7 +968,6 @@ void dppc_interpreter::ppc_mtspr() {
case 533:
case 534:
case 535:
ppc_state.spr[ref_spr] = val;
ibat_update(ref_spr);
break;
case 536:
@ -1017,30 +978,23 @@ void dppc_interpreter::ppc_mtspr() {
case 541:
case 542:
case 543:
ppc_state.spr[ref_spr] = val;
dbat_update(ref_spr);
default:
// FIXME: Unknown SPR should be noop or illegal instruction.
ppc_state.spr[ref_spr] = val;
}
}
void dppc_interpreter::ppc_mftb() {
ppc_grab_dab(ppc_cur_instruction);
uint32_t ref_spr = (reg_b << 5) | reg_a;
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
((ppc_cur_instruction >> 16) & 0x1F);
int reg_d = (ppc_cur_instruction >> 21) & 0x1F;
uint64_t tbr_value = calc_tbr_value();
switch (ref_spr) {
case SPR::TBL_U:
ppc_state.gpr[reg_d] =
ppc_state.spr[TBL_S] = uint32_t(tbr_value);
ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32);
ppc_state.gpr[reg_d] = uint32_t(tbr_value);
break;
case SPR::TBU_U:
ppc_state.gpr[reg_d] =
ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32);
ppc_state.spr[TBL_S] = uint32_t(tbr_value);
ppc_state.gpr[reg_d] = uint32_t(tbr_value >> 32);
break;
default:
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
@ -1866,9 +1820,10 @@ void dppc_interpreter::ppc_stswi() {
#ifdef CPU_PROFILING
num_int_stores++;
#endif
ppc_grab_regssash(ppc_cur_instruction);
ppc_grab_regssa(ppc_cur_instruction);
ppc_effective_address = reg_a ? ppc_result_a : 0;
uint32_t grab_inb = rot_sh ? rot_sh : 32;
uint32_t grab_inb = (ppc_cur_instruction >> 11) & 0x1F;
grab_inb = grab_inb ? grab_inb : 32;
while (grab_inb >= 4) {
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_state.gpr[reg_s]);

View File

@ -315,7 +315,7 @@ static void read_test_float_data() {
}
int main() {
initialize_ppc_opcode_tables(true); //kludge
initialize_ppc_opcode_tables(); //kludge
cout << "Running DingusPPC emulator tests..." << endl << endl;

View File

@ -586,9 +586,6 @@ void ControlVideo::enable_display()
// set framebuffer parameters
this->fb_ptr = &this->vram_ptr[this->fb_base];
this->fb_pitch = this->row_words;
if (~this->enables & SCAN_CONTROL) {
this->fb_pitch >>= 1;
}
this->pixel_depth = this->radacal->get_pix_width();
if (swatch_params[ControlRegs::HAL-1] != swatch_params[ControlRegs::PIPE_DELAY-1] + 1 || this->pixel_depth == 32) {
@ -653,10 +650,7 @@ void ControlVideo::enable_display()
// set up periodic timer for display updates
if (this->active_width > 0 && this->active_height > 0 && this->pixel_clock > 0) {
this->refresh_rate = (double)(this->pixel_clock) / (this->hori_total * this->vert_total);
if (~this->enables & SCAN_CONTROL) {
this->refresh_rate *= 2;
}
LOG_F(INFO, "%s: refresh rate set to %f Hz", this->name.c_str(), this->refresh_rate);
LOG_F(INFO, "Control: refresh rate set to %f Hz", this->refresh_rate);
this->start_refresh_task();

View File

@ -79,7 +79,7 @@ int initialize_catalyst(std::string& id)
std::string cpu = GET_STR_PROP("cpu");
if (cpu == "601") {
// init virtual CPU and request MPC601
ppc_cpu_init(platinum_obj, PPC_VER::MPC601, true, 7833600ULL);
ppc_cpu_init(platinum_obj, PPC_VER::MPC601, 7833600ULL);
}
else if (cpu == "750") {
// configure CPU clocks
@ -87,7 +87,7 @@ int initialize_catalyst(std::string& id)
uint64_t timebase_freq = bus_freq / 4;
// initialize virtual CPU and request MPC750 CPU aka G3
ppc_cpu_init(platinum_obj, PPC_VER::MPC750, false, timebase_freq);
ppc_cpu_init(platinum_obj, PPC_VER::MPC750, timebase_freq);
// set CPU PLL ratio to 3.5
ppc_state.spr[SPR::HID1] = 0xE << 28;

View File

@ -77,7 +77,7 @@ int initialize_gazelle(std::string& id)
uint64_t timebase_freq = bus_freq / 4;
// init virtual CPU and request MPC603ev
ppc_cpu_init(psx_obj, PPC_VER::MPC603EV, false, timebase_freq);
ppc_cpu_init(psx_obj, PPC_VER::MPC603EV, timebase_freq);
// CPU frequency is hardcoded to 225 MHz for now
ppc_state.spr[SPR::HID1] = get_cpu_pll_value(225000000) << 28;

View File

@ -146,7 +146,7 @@ int initialize_gossamer(std::string& id)
uint64_t timebase_freq = bus_freq / 4;
// initialize virtual CPU and request MPC750 CPU aka G3
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, false, timebase_freq);
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, timebase_freq);
// set CPU PLL ratio to 3.5
ppc_state.spr[SPR::HID1] = 0xE << 28;

View File

@ -90,7 +90,7 @@ int initialize_pdm(std::string& id)
}
// Init virtual CPU and request MPC601
ppc_cpu_init(hmc_obj, PPC_VER::MPC601, true, 7812500ULL);
ppc_cpu_init(hmc_obj, PPC_VER::MPC601, 7812500ULL);
return 0;
}

View File

@ -58,7 +58,7 @@ int initialize_pippin(std::string& id) {
aspen_obj->insert_ram_dimm(3, GET_INT_PROP("rambank4_size")); // RAM expansion slot
// init virtual CPU
ppc_cpu_init(aspen_obj, PPC_VER::MPC603, false, 16500000ULL);
ppc_cpu_init(aspen_obj, PPC_VER::MPC603, 16500000ULL);
return 0;
}

View File

@ -101,16 +101,16 @@ int initialize_tnt(std::string& id)
// init virtual CPU
std::string cpu = GET_STR_PROP("cpu");
if (cpu == "604e")
ppc_cpu_init(memctrl_obj, PPC_VER::MPC604E, false, 12500000ULL);
ppc_cpu_init(memctrl_obj, PPC_VER::MPC604E, 12500000ULL);
else if (cpu == "601")
ppc_cpu_init(memctrl_obj, PPC_VER::MPC601, true, 7833600ULL);
ppc_cpu_init(memctrl_obj, PPC_VER::MPC601, 7833600ULL);
else if (cpu == "750") {
// configure CPU clocks
uint64_t bus_freq = 50000000ULL;
uint64_t timebase_freq = bus_freq / 4;
// initialize virtual CPU and request MPC750 CPU aka G3
ppc_cpu_init(memctrl_obj, PPC_VER::MPC750, false, timebase_freq);
ppc_cpu_init(memctrl_obj, PPC_VER::MPC750, timebase_freq);
// set CPU PLL ratio to 3.5
ppc_state.spr[SPR::HID1] = 0xE << 28;

View File

@ -76,7 +76,7 @@ int initialize_yosemite(std::string& id)
uint64_t timebase_freq = bus_freq / 4;
// initialize virtual CPU and request MPC750 CPU aka G3
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, false, timebase_freq);
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, timebase_freq);
// set CPU PLL ratio to 3.5
ppc_state.spr[SPR::HID1] = 0xE << 28;

View File

@ -31,127 +31,110 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <loguru.hpp>
/* read an aligned big-endian WORD (16bit) */
#define READ_WORD_BE_A( addr) (BYTESWAP_16(*((uint16_t*)(addr))))
#define READ_WORD_BE_A(addr) (BYTESWAP_16(*((uint16_t*)((addr)))))
/* read an aligned big-endian DWORD (32bit) */
#define READ_DWORD_BE_A(addr) (BYTESWAP_32(*((uint32_t*)(addr))))
#define READ_DWORD_BE_A(addr) (BYTESWAP_32(*((uint32_t*)((addr)))))
/* read an aligned big-endian QWORD (64bit) */
#define READ_QWORD_BE_A(addr) (BYTESWAP_64(*((uint64_t*)(addr))))
#define READ_QWORD_BE_A(addr) (BYTESWAP_64(*((uint64_t*)((addr)))))
/* read an aligned little-endian WORD (16bit) */
#define READ_WORD_LE_A( addr) (*(uint16_t*)(addr))
#define READ_WORD_LE_A(addr) (*(uint16_t*)((addr)))
/* read an aligned little-endian DWORD (32bit) */
#define READ_DWORD_LE_A(addr) (*(uint32_t*)(addr))
#define READ_DWORD_LE_A(addr) (*(uint32_t*)((addr)))
/* read an aligned little-endian QWORD (64bit) */
#define READ_QWORD_LE_A(addr) (*(uint64_t*)(addr))
#define READ_QWORD_LE_A(addr) (*(uint64_t*)((addr)))
/* read an unaligned big-endian WORD (16bit) */
#define READ_WORD_BE_U( addr) ((((uint8_t*)(addr))[0] << 8) | ((uint8_t*)(addr))[1])
#define READ_WORD_BE_U(addr) (((addr)[0] << 8) | (addr)[1])
/* read an unaligned big-endian DWORD (32bit) */
#define READ_DWORD_BE_U(addr) \
((((uint8_t*)(addr))[0] << 24) | (((uint8_t*)(addr))[1] << 16) | \
(((uint8_t*)(addr))[2] << 8) | ((uint8_t*)(addr))[3] )
(((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
/* read an unaligned big-endian QWORD (32bit) */
#define READ_QWORD_BE_U(addr) \
((uint64_t(((uint8_t*)(addr))[0]) << 56) | (uint64_t(((uint8_t*)(addr))[1]) << 48) | \
(uint64_t(((uint8_t*)(addr))[2]) << 40) | (uint64_t(((uint8_t*)(addr))[3]) << 32) | \
(uint64_t(((uint8_t*)(addr))[4]) << 24) | ( ((uint8_t*)(addr))[5] << 16) | \
( ((uint8_t*)(addr))[6] << 8) | ((uint8_t*)(addr))[7] )
((uint64_t((addr)[0]) << 56) | (uint64_t((addr)[1]) << 48) | \
(uint64_t((addr)[2]) << 40) | (uint64_t((addr)[3]) << 32) | \
(uint64_t((addr)[4]) << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
/* read an unaligned little-endian WORD (16bit) */
#define READ_WORD_LE_U( addr) ((((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(addr))[0])
#define READ_WORD_LE_U(addr) (((addr)[1] << 8) | (addr)[0])
/* read an unaligned little-endian DWORD (32bit) */
#define READ_DWORD_LE_U(addr) \
((((uint8_t*)(addr))[3] << 24) | (((uint8_t*)(addr))[2] << 16) | \
(((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(addr))[0] )
(((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
/* read an unaligned little-endian DWORD (64bit) */
#define READ_QWORD_LE_U(addr) \
((uint64_t(((uint8_t*)(addr))[7]) << 56) | (uint64_t(((uint8_t*)(addr))[6]) << 48) | \
(uint64_t(((uint8_t*)(addr))[5]) << 40) | (uint64_t(((uint8_t*)(addr))[4]) << 32) | \
(uint64_t(((uint8_t*)(addr))[3]) << 24) | ( ((uint8_t*)(addr))[2] << 16) | \
( ((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(addr))[0] )
((uint64_t((addr)[7]) << 56) | (uint64_t((addr)[6]) << 48) | \
(uint64_t((addr)[5]) << 40) | (uint64_t((addr)[4]) << 32) | \
(uint64_t((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))
#define WRITE_WORD_BE_A(addr, val) (*((uint16_t*)((addr))) = BYTESWAP_16(val))
/* write an aligned big-endian DWORD (32bit) */
#define WRITE_DWORD_BE_A(addr, val) (*((uint32_t*)(addr)) = BYTESWAP_32(val))
#define WRITE_DWORD_BE_A(addr, val) (*((uint32_t*)((addr))) = BYTESWAP_32(val))
/* 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 { \
((uint8_t*)(addr))[0] = ((val) >> 8); \
((uint8_t*)(addr))[1] = (uint8_t)(val); \
(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 { \
((uint8_t*)(addr))[0] = ((val) >> 24); \
((uint8_t*)(addr))[1] = ((val) >> 16); \
((uint8_t*)(addr))[2] = ((val) >> 8); \
((uint8_t*)(addr))[3] = (uint8_t)(val); \
(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 { \
((uint8_t*)(addr))[0] = ((uint64_t)(val) >> 56); \
((uint8_t*)(addr))[1] = ((uint64_t)(val) >> 48); \
((uint8_t*)(addr))[2] = ((uint64_t)(val) >> 40); \
((uint8_t*)(addr))[3] = ((uint64_t)(val) >> 32); \
((uint8_t*)(addr))[4] = ( (val) >> 24); \
((uint8_t*)(addr))[5] = ( (val) >> 16); \
((uint8_t*)(addr))[6] = ( (val) >> 8); \
((uint8_t*)(addr))[7] = (uint8_t)(val) ; \
(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] = ((uint64_t)(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) */
#define WRITE_WORD_LE_A( addr, val) (*((uint16_t*)(addr)) = (val))
#define WRITE_WORD_LE_A(addr, val) (*((uint16_t*)((addr))) = (val))
/* write an aligned little-endian DWORD (32bit) */
#define WRITE_DWORD_LE_A(addr, val) (*((uint32_t*)(addr)) = (val))
#define WRITE_DWORD_LE_A(addr, val) (*((uint32_t*)((addr))) = (val))
/* write an aligned little-endian QWORD (64bit) */
#define WRITE_QWORD_LE_A(addr, val) (*((uint64_t*)(addr)) = (val))
#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 { \
((uint8_t*)(addr))[0] = (uint8_t)(val); \
((uint8_t*)(addr))[1] = ((val) >> 8); \
(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 { \
((uint8_t*)(addr))[0] = (uint8_t)(val); \
((uint8_t*)(addr))[1] = ((val) >> 8); \
((uint8_t*)(addr))[2] = ((val) >> 16); \
((uint8_t*)(addr))[3] = ((val) >> 24); \
} while (0)
/* write an unaligned little-endian DWORD (64bit) */
#define WRITE_QWORD_LE_U(addr, val) \
do { \
((uint8_t*)(addr))[0] = (uint8_t)(val) ; \
((uint8_t*)(addr))[1] = ( (val) >> 8); \
((uint8_t*)(addr))[2] = ( (val) >> 16); \
((uint8_t*)(addr))[3] = ( (val) >> 24); \
((uint8_t*)(addr))[4] = ((uint64_t)(val) >> 32); \
((uint8_t*)(addr))[5] = ((uint64_t)(val) >> 40); \
((uint8_t*)(addr))[6] = ((uint64_t)(val) >> 48); \
((uint8_t*)(addr))[7] = ((uint64_t)(val) >> 56); \
(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,