Compare commits
28 Commits
9c95bc17fe
...
c6ea3a374e
Author | SHA1 | Date |
---|---|---|
joevt | c6ea3a374e | |
joevt | e8ce805f2a | |
joevt | 3d898ebdf3 | |
joevt | f45b7c47c8 | |
joevt | 916cb47b9d | |
joevt | bce816139b | |
joevt | 24bce16c4d | |
joevt | a928c67913 | |
joevt | 2b8f510603 | |
joevt | e8273ecc61 | |
joevt | e1f31a2da3 | |
joevt | d897acfd3c | |
joevt | 1e57ac408a | |
joevt | ef8522e101 | |
joevt | c71d856a08 | |
joevt | df7ff76404 | |
joevt | 0d1ce68d19 | |
joevt | 88aa249ce1 | |
joevt | ff626ae0b5 | |
joevt | 529f23d836 | |
joevt | cb88bab67d | |
joevt | 67a5c39b1c | |
joevt | 0273867c49 | |
joevt | 1e50d88183 | |
joevt | 29a832c68d | |
joevt | cb05bd05eb | |
joevt | 4f45d7de35 | |
joevt | a6ba9a0554 |
|
@ -27,20 +27,10 @@ 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 = 0xFFFFFFFFUL >> rot_mb;
|
||||
uint32_t m2 = uint32_t(0xFFFFFFFFUL << (31 - rot_me));
|
||||
uint32_t m1 = 0xFFFFFFFFU >> rot_mb;
|
||||
uint32_t m2 = 0xFFFFFFFFU << (31 - rot_me);
|
||||
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
||||
}
|
||||
|
||||
|
@ -52,9 +42,10 @@ 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 = ppc_result_a & 0x7FFFFFFF;
|
||||
ppc_result_d = (int32_t(ppc_result_a) < 0) ? -ppc_result_a : ppc_result_a;
|
||||
if (ov)
|
||||
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
||||
}
|
||||
|
||||
if (rec)
|
||||
|
@ -76,10 +67,17 @@ void dppc_interpreter::power_clcs() {
|
|||
case 13: //data cache line size
|
||||
case 14: //minimum line size
|
||||
case 15: //maximum line size
|
||||
ppc_result_d = 64;
|
||||
break;
|
||||
default:
|
||||
ppc_result_d = 0;
|
||||
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_store_iresult_reg(reg_d, ppc_result_d);
|
||||
|
@ -90,23 +88,39 @@ void dppc_interpreter::power_div() {
|
|||
uint32_t ppc_result_d;
|
||||
ppc_grab_regsdab(ppc_cur_instruction);
|
||||
|
||||
uint64_t dividend = ((uint64_t)ppc_result_a << 32) | ppc_state.spr[SPR::MQ];
|
||||
int32_t divisor = ppc_result_b;
|
||||
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;
|
||||
|
||||
if ((ppc_result_a == 0x80000000UL && divisor == -1) || !divisor) {
|
||||
ppc_state.spr[SPR::MQ] = 0;
|
||||
ppc_result_d = 0x80000000UL; // -2^31 aka INT32_MIN
|
||||
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;
|
||||
} else {
|
||||
ppc_result_d = uint32_t(dividend / divisor);
|
||||
ppc_state.spr[SPR::MQ] = dividend % divisor;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ov)
|
||||
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
ppc_changecrf0(remainder);
|
||||
|
||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||
ppc_state.spr[SPR::MQ] = remainder;
|
||||
}
|
||||
|
||||
template void dppc_interpreter::power_div<RC0, OV0>();
|
||||
|
@ -116,16 +130,31 @@ 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 (ov)
|
||||
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
||||
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 (rec)
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
ppc_changecrf0(remainder);
|
||||
|
||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||
ppc_state.spr[SPR::MQ] = remainder;
|
||||
}
|
||||
|
||||
template void dppc_interpreter::power_divs<RC0, OV0>();
|
||||
|
@ -136,13 +165,18 @@ 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)) ? 0 :
|
||||
ppc_result_b - ppc_result_a;
|
||||
uint32_t ppc_result_d = (int32_t(ppc_result_a) < int32_t(ppc_result_b)) ?
|
||||
ppc_result_b - ppc_result_a : 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -168,47 +202,50 @@ 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_copied = 0;
|
||||
uint32_t bytes_remaining = bytes_to_load;
|
||||
uint8_t matching_byte = (uint8_t)(ppc_state.spr[SPR::XER] >> 8);
|
||||
uint32_t ppc_result_d = 0;
|
||||
uint32_t ppc_result_d = 0;
|
||||
bool is_match = false;
|
||||
|
||||
// for storing each byte
|
||||
uint32_t bitmask = 0xFF000000;
|
||||
uint8_t shift_amount = 24;
|
||||
|
||||
while (bytes_to_load > 0) {
|
||||
return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
||||
while (bytes_remaining > 0) {
|
||||
uint8_t return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
||||
|
||||
ppc_result_d = (ppc_result_d & ~bitmask) | (return_value << shift_amount);
|
||||
ppc_result_d |= 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;
|
||||
bitmask = 0xFF000000;
|
||||
ppc_result_d = 0;
|
||||
shift_amount = 24;
|
||||
} else {
|
||||
bitmask >>= 8;
|
||||
shift_amount -= 8;
|
||||
}
|
||||
|
||||
ppc_effective_address++;
|
||||
bytes_copied++;
|
||||
bytes_to_load--;
|
||||
bytes_remaining--;
|
||||
|
||||
if (return_value == matching_byte)
|
||||
if (return_value == matching_byte) {
|
||||
is_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// store partiallly loaded register if any
|
||||
// store partially 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_copied;
|
||||
ppc_state.spr[SPR::XER] = (ppc_state.spr[SPR::XER] & ~0x7F) | (bytes_to_load - bytes_remaining);
|
||||
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
if (rec) {
|
||||
ppc_state.cr =
|
||||
(ppc_state.cr & 0x0FFFFFFFUL) |
|
||||
(is_match ? CRx_bit::CR_EQ : 0) |
|
||||
((ppc_state.spr[SPR::XER] & XER::SO) >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
template void dppc_interpreter::power_lscbx<RC0>();
|
||||
|
@ -234,7 +271,7 @@ void dppc_interpreter::power_maskg() {
|
|||
ppc_result_a = insert_mask;
|
||||
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
|
||||
ppc_store_iresult_reg(reg_a, ppc_result_a);
|
||||
}
|
||||
|
@ -259,17 +296,19 @@ 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);
|
||||
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));
|
||||
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);
|
||||
|
||||
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(ppc_result_d);
|
||||
if (ov)
|
||||
power_setsoov(ppc_result_a, ppc_result_b, ppc_result_d);
|
||||
|
||||
ppc_changecrf0(uint32_t(product));
|
||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||
}
|
||||
|
||||
|
@ -281,12 +320,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 = ppc_result_a & 0x80000000 ? ppc_result_a : -ppc_result_a;
|
||||
uint32_t ppc_result_d = (int32_t(ppc_result_a) < 0) ? ppc_result_a : -ppc_result_a;
|
||||
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
if (ov)
|
||||
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
|
||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||
}
|
||||
|
@ -316,11 +355,12 @@ 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 (ppc_result_d & 0x80000000) {
|
||||
ppc_result_a |= ((ppc_result_d & 0x80000000) >> ppc_result_b);
|
||||
if (int32_t(ppc_result_d) < 0) {
|
||||
ppc_result_a |= (0x80000000U >> rot_sh);
|
||||
} else {
|
||||
ppc_result_a &= ~((ppc_result_d & 0x80000000) >> ppc_result_b);
|
||||
ppc_result_a &= ~(0x80000000U >> rot_sh);
|
||||
}
|
||||
|
||||
if (rec)
|
||||
|
@ -372,8 +412,7 @@ template void dppc_interpreter::power_sleq<RC1>();
|
|||
|
||||
template <field_rc rec>
|
||||
void dppc_interpreter::power_sliq() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
|
||||
ppc_result_a = ppc_result_d << rot_sh;
|
||||
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||
|
@ -389,8 +428,7 @@ template void dppc_interpreter::power_sliq<RC1>();
|
|||
|
||||
template <field_rc rec>
|
||||
void dppc_interpreter::power_slliq() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||
uint32_t mask = power_rot_mask(0, 31 - rot_sh);
|
||||
|
||||
|
@ -410,14 +448,11 @@ 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] & mask);
|
||||
}
|
||||
else {
|
||||
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
|
||||
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 (rec)
|
||||
|
@ -434,16 +469,17 @@ 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 = ppc_result_d << rot_sh;
|
||||
} else {
|
||||
if (ppc_result_b & 0x20) {
|
||||
ppc_result_a = 0;
|
||||
} else {
|
||||
ppc_result_a = ppc_result_d << rot_sh;
|
||||
}
|
||||
|
||||
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>();
|
||||
|
@ -451,13 +487,12 @@ template void dppc_interpreter::power_slq<RC1>();
|
|||
|
||||
template <field_rc rec>
|
||||
void dppc_interpreter::power_sraiq() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
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 ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
|
||||
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & mask)) {
|
||||
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||
} else {
|
||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||
|
@ -476,11 +511,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 = (1 << rot_sh) - 1;
|
||||
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
|
||||
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);
|
||||
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||
|
||||
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
|
||||
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & mask)) {
|
||||
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||
} else {
|
||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||
|
@ -520,9 +555,10 @@ 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;
|
||||
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||
uint32_t r = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
|
||||
uint32_t mask = -1U >> rot_sh;
|
||||
|
||||
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & rot_sh)) {
|
||||
if ((int32_t(ppc_result_d) < 0) && (r & ~mask)) {
|
||||
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||
} else {
|
||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||
|
@ -532,6 +568,7 @@ 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>();
|
||||
|
@ -541,10 +578,10 @@ template <field_rc rec>
|
|||
void dppc_interpreter::power_sreq() {
|
||||
ppc_grab_regssab(ppc_cur_instruction);
|
||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
||||
unsigned mask = power_rot_mask(rot_sh, 31);
|
||||
uint32_t mask = -1U >> rot_sh;
|
||||
|
||||
ppc_result_a = ((rot_sh & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
|
||||
ppc_state.spr[SPR::MQ] = rot_sh;
|
||||
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));
|
||||
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
|
@ -557,8 +594,7 @@ template void dppc_interpreter::power_sreq<RC1>();
|
|||
|
||||
template <field_rc rec>
|
||||
void dppc_interpreter::power_sriq() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
ppc_result_a = ppc_result_d >> rot_sh;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
|
||||
|
||||
|
@ -573,8 +609,7 @@ template void dppc_interpreter::power_sriq<RC1>();
|
|||
|
||||
template <field_rc rec>
|
||||
void dppc_interpreter::power_srliq() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
|
||||
unsigned mask = power_rot_mask(rot_sh, 31);
|
||||
|
||||
|
@ -597,10 +632,9 @@ 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));
|
||||
}
|
||||
|
||||
|
@ -618,7 +652,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;
|
||||
|
|
|
@ -85,17 +85,18 @@ extern SetPRS ppc_state;
|
|||
|
||||
/** symbolic names for frequently used SPRs */
|
||||
enum SPR : int {
|
||||
MQ = 0,
|
||||
MQ = 0, // MQ (601)
|
||||
XER = 1,
|
||||
RTCU_U = 4, // user RTCU
|
||||
RTCL_U = 5, // user RTCL
|
||||
RTCU_U = 4, // user mode RTCU (601)
|
||||
RTCL_U = 5, // user mode RTCL (601)
|
||||
DEC_U = 6, // user mode decrementer (601)
|
||||
LR = 8,
|
||||
CTR = 9,
|
||||
DSISR = 18,
|
||||
DAR = 19,
|
||||
RTCU_S = 20, // supervisor RTCU
|
||||
RTCL_S = 21, // supervisor RTCL
|
||||
DEC = 22, // decrementer
|
||||
RTCU_S = 20, // supervisor RTCU (601)
|
||||
RTCL_S = 21, // supervisor RTCL (601)
|
||||
DEC_S = 22, // supervisor decrementer
|
||||
SDR1 = 25,
|
||||
SRR0 = 26,
|
||||
SRR1 = 27,
|
||||
|
@ -398,7 +399,7 @@ typedef enum {
|
|||
} field_601;
|
||||
|
||||
// Function prototypes
|
||||
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq);
|
||||
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601, uint64_t tb_freq);
|
||||
extern void ppc_mmu_init();
|
||||
|
||||
void ppc_illegalop();
|
||||
|
@ -414,7 +415,7 @@ void ppc_opcode31();
|
|||
void ppc_opcode59();
|
||||
void ppc_opcode63();
|
||||
|
||||
void initialize_ppc_opcode_tables();
|
||||
void initialize_ppc_opcode_tables(bool include_601);
|
||||
|
||||
extern double fp_return_double(uint32_t reg);
|
||||
extern uint64_t fp_return_uint64(uint32_t reg);
|
||||
|
|
|
@ -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() {
|
||||
void initialize_ppc_opcode_tables(bool include_601) {
|
||||
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) OP(9, power_dozi);
|
||||
if (is_601 || include_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() {
|
|||
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) OP(22, power_rlmi);
|
||||
if (is_601 || include_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() {
|
|||
OP31(470, ppc_dcbi);
|
||||
OP31(1014, ppc_dcbz);
|
||||
|
||||
if (is_601) {
|
||||
if (is_601 || include_601) {
|
||||
OP31d(29, power_maskg);
|
||||
OP31od(107, power_mul);
|
||||
OP31d(152, power_slq);
|
||||
|
@ -822,7 +822,7 @@ void initialize_ppc_opcode_tables() {
|
|||
}
|
||||
}
|
||||
|
||||
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
||||
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601, uint64_t tb_freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -834,7 +834,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
|||
ppc_state.spr[SPR::PVR] = cpu_version;
|
||||
is_601 = (cpu_version >> 16) == 1;
|
||||
|
||||
initialize_ppc_opcode_tables();
|
||||
initialize_ppc_opcode_tables(include_601);
|
||||
|
||||
// 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, uint64_t tb_freq)
|
|||
/* 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] = 0xFFFFFFFFUL;
|
||||
ppc_state.msr = MSR::IP;
|
||||
ppc_state.spr[SPR::DEC_S] = 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}, {"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_S}, {"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_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},
|
||||
{"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},
|
||||
{"MMCR0", SPR::MMCR0}, {"PMC1", SPR::PMC1}, {"PMC2", SPR::PMC2},
|
||||
{"SDA", SPR::SDA}, {"SIA", SPR::SIA}, {"MMCR1", SPR::MMCR1}
|
||||
};
|
||||
|
@ -974,6 +974,13 @@ 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];
|
||||
|
|
|
@ -74,6 +74,12 @@ 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; \
|
||||
|
@ -169,4 +175,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
|
||||
|
|
|
@ -33,20 +33,17 @@ 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 &= 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;
|
||||
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].
|
||||
}
|
||||
|
||||
// Affects the XER register's Carry Bit
|
||||
|
@ -69,7 +66,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 ((a ^ b) & (a ^ d) & 0x80000000UL) {
|
||||
if (int32_t((a ^ b) & (a ^ d)) < 0) {
|
||||
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||
} else {
|
||||
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
||||
|
@ -533,7 +530,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 = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
|
||||
// ppc_result_d = (int32_t(ppc_result_a) < 0) ? -1 : 0; /* UNDOCUMENTED! */
|
||||
|
||||
if (ov)
|
||||
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||
|
@ -632,7 +629,7 @@ void dppc_interpreter::ppc_sraw() {
|
|||
} else {
|
||||
uint32_t shift = ppc_result_b & 0x1F;
|
||||
ppc_result_a = int32_t(ppc_result_d) >> shift;
|
||||
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & ((1U << shift) - 1)))
|
||||
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & ((1U << shift) - 1)))
|
||||
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||
}
|
||||
|
||||
|
@ -647,16 +644,15 @@ template void dppc_interpreter::ppc_sraw<RC1>();
|
|||
|
||||
template <field_rc rec>
|
||||
void dppc_interpreter::ppc_srawi() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
uint32_t shift = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
|
||||
// clear XER[CA] by default
|
||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||
|
||||
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & ((1U << shift) - 1)))
|
||||
if ((int32_t(ppc_result_d) < 0) && (ppc_result_d & ((1U << rot_sh) - 1)))
|
||||
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||
|
||||
ppc_result_a = int32_t(ppc_result_d) >> shift;
|
||||
ppc_result_a = int32_t(ppc_result_d) >> rot_sh;
|
||||
|
||||
if (rec)
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
|
@ -675,8 +671,7 @@ static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) {
|
|||
}
|
||||
|
||||
void dppc_interpreter::ppc_rlwimi() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
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);
|
||||
|
@ -690,8 +685,7 @@ void dppc_interpreter::ppc_rlwimi() {
|
|||
}
|
||||
|
||||
void dppc_interpreter::ppc_rlwinm() {
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
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);
|
||||
|
@ -891,74 +885,118 @@ static void update_decrementer(uint32_t val) {
|
|||
}
|
||||
|
||||
void dppc_interpreter::ppc_mfspr() {
|
||||
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
|
||||
((ppc_cur_instruction >> 16) & 0x1F);
|
||||
ppc_grab_dab(ppc_cur_instruction);
|
||||
uint32_t ref_spr = (reg_b << 5) | reg_a;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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.spr[SPR::RTCL_U] = rtc_lo & 0x3FFFFF80UL;
|
||||
ppc_state.gpr[reg_d] =
|
||||
ppc_state.spr[SPR::RTCL_S] = rtc_lo & 0x3FFFFF80UL;
|
||||
ppc_state.spr[SPR::RTCU_S] = rtc_hi;
|
||||
break;
|
||||
case SPR::RTCU_U:
|
||||
if (!is_601) {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||
}
|
||||
calc_rtcl_value();
|
||||
ppc_state.spr[SPR::RTCU_U] = rtc_hi;
|
||||
ppc_state.gpr[reg_d] =
|
||||
ppc_state.spr[SPR::RTCU_S] = rtc_hi;
|
||||
ppc_state.spr[SPR::RTCL_S] = rtc_lo;
|
||||
break;
|
||||
case SPR::DEC:
|
||||
ppc_state.spr[SPR::DEC] = calc_dec_value();
|
||||
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();
|
||||
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() {
|
||||
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
|
||||
((ppc_cur_instruction >> 16) & 0x1F);
|
||||
ppc_grab_dab(ppc_cur_instruction);
|
||||
uint32_t ref_spr = (reg_b << 5) | reg_a;
|
||||
|
||||
if (ref_spr & 0x10) {
|
||||
#ifdef CPU_PROFILING
|
||||
if (ref_spr > 31) {
|
||||
num_supervisor_instrs++;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ref_spr == SPR::PVR || (
|
||||
ref_spr == SPR::MQ && !is_601
|
||||
)) { // prevent writes to the read-only registers
|
||||
return;
|
||||
if (ppc_state.msr & MSR::PR) {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t val = ppc_state.gpr[(ppc_cur_instruction >> 21) & 0x1F];
|
||||
ppc_state.spr[ref_spr] = val;
|
||||
uint32_t val = ppc_state.gpr[reg_d];
|
||||
|
||||
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();
|
||||
rtc_lo = val & 0x3FFFFF80UL;
|
||||
ppc_state.spr[RTCL_S] = rtc_lo = val & 0x3FFFFF80UL;
|
||||
ppc_state.spr[RTCU_S] = rtc_hi;
|
||||
break;
|
||||
case SPR::RTCU_S:
|
||||
calc_rtcl_value();
|
||||
rtc_hi = val;
|
||||
ppc_state.spr[RTCL_S] = rtc_lo;
|
||||
ppc_state.spr[RTCU_S] = rtc_hi = val;
|
||||
break;
|
||||
case SPR::DEC:
|
||||
case SPR::DEC_S:
|
||||
ppc_state.spr[DEC_S] = val;
|
||||
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:
|
||||
|
@ -968,6 +1006,7 @@ void dppc_interpreter::ppc_mtspr() {
|
|||
case 533:
|
||||
case 534:
|
||||
case 535:
|
||||
ppc_state.spr[ref_spr] = val;
|
||||
ibat_update(ref_spr);
|
||||
break;
|
||||
case 536:
|
||||
|
@ -978,23 +1017,30 @@ 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() {
|
||||
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
|
||||
((ppc_cur_instruction >> 16) & 0x1F);
|
||||
int reg_d = (ppc_cur_instruction >> 21) & 0x1F;
|
||||
ppc_grab_dab(ppc_cur_instruction);
|
||||
uint32_t ref_spr = (reg_b << 5) | reg_a;
|
||||
|
||||
uint64_t tbr_value = calc_tbr_value();
|
||||
|
||||
switch (ref_spr) {
|
||||
case SPR::TBL_U:
|
||||
ppc_state.gpr[reg_d] = uint32_t(tbr_value);
|
||||
ppc_state.gpr[reg_d] =
|
||||
ppc_state.spr[TBL_S] = uint32_t(tbr_value);
|
||||
ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32);
|
||||
break;
|
||||
case SPR::TBU_U:
|
||||
ppc_state.gpr[reg_d] = uint32_t(tbr_value >> 32);
|
||||
ppc_state.gpr[reg_d] =
|
||||
ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32);
|
||||
ppc_state.spr[TBL_S] = uint32_t(tbr_value);
|
||||
break;
|
||||
default:
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||
|
@ -1820,10 +1866,9 @@ void dppc_interpreter::ppc_stswi() {
|
|||
#ifdef CPU_PROFILING
|
||||
num_int_stores++;
|
||||
#endif
|
||||
ppc_grab_regssa(ppc_cur_instruction);
|
||||
ppc_grab_regssash(ppc_cur_instruction);
|
||||
ppc_effective_address = reg_a ? ppc_result_a : 0;
|
||||
uint32_t grab_inb = (ppc_cur_instruction >> 11) & 0x1F;
|
||||
grab_inb = grab_inb ? grab_inb : 32;
|
||||
uint32_t grab_inb = rot_sh ? rot_sh : 32;
|
||||
|
||||
while (grab_inb >= 4) {
|
||||
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_state.gpr[reg_s]);
|
||||
|
|
|
@ -315,7 +315,7 @@ static void read_test_float_data() {
|
|||
}
|
||||
|
||||
int main() {
|
||||
initialize_ppc_opcode_tables(); //kludge
|
||||
initialize_ppc_opcode_tables(true); //kludge
|
||||
|
||||
cout << "Running DingusPPC emulator tests..." << endl << endl;
|
||||
|
||||
|
|
|
@ -586,6 +586,9 @@ 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) {
|
||||
|
@ -650,7 +653,10 @@ 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);
|
||||
LOG_F(INFO, "Control: refresh rate set to %f Hz", this->refresh_rate);
|
||||
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);
|
||||
|
||||
this->start_refresh_task();
|
||||
|
||||
|
|
|
@ -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, 7833600ULL);
|
||||
ppc_cpu_init(platinum_obj, PPC_VER::MPC601, true, 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, timebase_freq);
|
||||
ppc_cpu_init(platinum_obj, PPC_VER::MPC750, false, timebase_freq);
|
||||
|
||||
// set CPU PLL ratio to 3.5
|
||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||
|
|
|
@ -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, timebase_freq);
|
||||
ppc_cpu_init(psx_obj, PPC_VER::MPC603EV, false, timebase_freq);
|
||||
|
||||
// CPU frequency is hardcoded to 225 MHz for now
|
||||
ppc_state.spr[SPR::HID1] = get_cpu_pll_value(225000000) << 28;
|
||||
|
|
|
@ -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, timebase_freq);
|
||||
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, false, timebase_freq);
|
||||
|
||||
// set CPU PLL ratio to 3.5
|
||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||
|
|
|
@ -90,7 +90,7 @@ int initialize_pdm(std::string& id)
|
|||
}
|
||||
|
||||
// Init virtual CPU and request MPC601
|
||||
ppc_cpu_init(hmc_obj, PPC_VER::MPC601, 7812500ULL);
|
||||
ppc_cpu_init(hmc_obj, PPC_VER::MPC601, true, 7812500ULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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, 16500000ULL);
|
||||
ppc_cpu_init(aspen_obj, PPC_VER::MPC603, false, 16500000ULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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, 12500000ULL);
|
||||
ppc_cpu_init(memctrl_obj, PPC_VER::MPC604E, false, 12500000ULL);
|
||||
else if (cpu == "601")
|
||||
ppc_cpu_init(memctrl_obj, PPC_VER::MPC601, 7833600ULL);
|
||||
ppc_cpu_init(memctrl_obj, PPC_VER::MPC601, true, 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, timebase_freq);
|
||||
ppc_cpu_init(memctrl_obj, PPC_VER::MPC750, false, timebase_freq);
|
||||
|
||||
// set CPU PLL ratio to 3.5
|
||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||
|
|
|
@ -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, timebase_freq);
|
||||
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, false, timebase_freq);
|
||||
|
||||
// set CPU PLL ratio to 3.5
|
||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||
|
|
101
memaccess.h
101
memaccess.h
|
@ -31,110 +31,127 @@ 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) (((addr)[0] << 8) | (addr)[1])
|
||||
#define READ_WORD_BE_U( addr) ((((uint8_t*)(addr))[0] << 8) | ((uint8_t*)(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])
|
||||
((((uint8_t*)(addr))[0] << 24) | (((uint8_t*)(addr))[1] << 16) | \
|
||||
(((uint8_t*)(addr))[2] << 8) | ((uint8_t*)(addr))[3] )
|
||||
|
||||
/* read an unaligned big-endian QWORD (32bit) */
|
||||
#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) | \
|
||||
(uint64_t((addr)[4]) << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
|
||||
((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] )
|
||||
|
||||
/* read an unaligned little-endian WORD (16bit) */
|
||||
#define READ_WORD_LE_U(addr) (((addr)[1] << 8) | (addr)[0])
|
||||
#define READ_WORD_LE_U( addr) ((((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(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])
|
||||
((((uint8_t*)(addr))[3] << 24) | (((uint8_t*)(addr))[2] << 16) | \
|
||||
(((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(addr))[0] )
|
||||
|
||||
/* 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) | \
|
||||
(uint64_t((addr)[3]) << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||
((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] )
|
||||
|
||||
/* 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 { \
|
||||
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[1] = (val) & 0xFF; \
|
||||
((uint8_t*)(addr))[0] = ((val) >> 8); \
|
||||
((uint8_t*)(addr))[1] = (uint8_t)(val); \
|
||||
} 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; \
|
||||
((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); \
|
||||
} 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] = ((uint64_t)(val) >> 24) & 0xFF; \
|
||||
(addr)[5] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[6] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[7] = (val) & 0xFF; \
|
||||
((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) ; \
|
||||
} 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 { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
((uint8_t*)(addr))[0] = (uint8_t)(val); \
|
||||
((uint8_t*)(addr))[1] = ((val) >> 8); \
|
||||
} 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; \
|
||||
((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); \
|
||||
} while (0)
|
||||
|
||||
/* read value of the specified size from memory starting at addr,
|
||||
|
|
Loading…
Reference in New Issue