mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-09-28 10:55:27 +00:00
Compare commits
No commits in common. "c6ea3a374e930655a7c827b52111d520678698e5" and "9c95bc17fefd73b085282cb634f0f4e303ed5d8a" have entirely different histories.
c6ea3a374e
...
9c95bc17fe
@ -27,10 +27,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include "ppcmmu.h"
|
#include "ppcmmu.h"
|
||||||
#include <stdint.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) */
|
/** 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) {
|
static inline uint32_t power_rot_mask(unsigned rot_mb, unsigned rot_me) {
|
||||||
uint32_t m1 = 0xFFFFFFFFU >> rot_mb;
|
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
||||||
uint32_t m2 = 0xFFFFFFFFU << (31 - rot_me);
|
uint32_t m2 = uint32_t(0xFFFFFFFFUL << (31 - rot_me));
|
||||||
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +52,9 @@ void dppc_interpreter::power_abs() {
|
|||||||
ppc_result_d = ppc_result_a;
|
ppc_result_d = ppc_result_a;
|
||||||
if (ov)
|
if (ov)
|
||||||
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ppc_result_d = (int32_t(ppc_result_a) < 0) ? -ppc_result_a : ppc_result_a;
|
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
|
||||||
if (ov)
|
|
||||||
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
@ -67,17 +76,10 @@ void dppc_interpreter::power_clcs() {
|
|||||||
case 13: //data cache line size
|
case 13: //data cache line size
|
||||||
case 14: //minimum line size
|
case 14: //minimum line size
|
||||||
case 15: //maximum line size
|
case 15: //maximum line size
|
||||||
default: ppc_result_d = is_601 ? 64 : 32; break;
|
ppc_result_d = 64;
|
||||||
case 7:
|
break;
|
||||||
case 23: ppc_result_d = is_601 ? 64 : 0; break;
|
default:
|
||||||
case 8:
|
ppc_result_d = 0;
|
||||||
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);
|
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||||
@ -88,39 +90,23 @@ void dppc_interpreter::power_div() {
|
|||||||
uint32_t ppc_result_d;
|
uint32_t ppc_result_d;
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
ppc_grab_regsdab(ppc_cur_instruction);
|
||||||
|
|
||||||
int64_t dividend = (uint64_t(ppc_result_a) << 32) | ppc_state.spr[SPR::MQ];
|
uint64_t dividend = ((uint64_t)ppc_result_a << 32) | ppc_state.spr[SPR::MQ];
|
||||||
int32_t divisor = ppc_result_b;
|
int32_t divisor = ppc_result_b;
|
||||||
int64_t quotient;
|
|
||||||
int32_t remainder;
|
|
||||||
|
|
||||||
if (dividend == -0x80000000 && divisor == -1) {
|
if ((ppc_result_a == 0x80000000UL && divisor == -1) || !divisor) {
|
||||||
remainder = 0;
|
ppc_state.spr[SPR::MQ] = 0;
|
||||||
ppc_result_d = 0x80000000U; // -2^31 aka INT32_MIN
|
ppc_result_d = 0x80000000UL; // -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 {
|
} else {
|
||||||
quotient = dividend / divisor;
|
ppc_result_d = uint32_t(dividend / divisor);
|
||||||
remainder = dividend % divisor;
|
ppc_state.spr[SPR::MQ] = 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)
|
if (rec)
|
||||||
ppc_changecrf0(remainder);
|
ppc_changecrf0(ppc_result_d);
|
||||||
|
|
||||||
ppc_store_iresult_reg(reg_d, 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>();
|
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>
|
template <field_rc rec, field_ov ov>
|
||||||
void dppc_interpreter::power_divs() {
|
void dppc_interpreter::power_divs() {
|
||||||
uint32_t ppc_result_d;
|
|
||||||
int32_t remainder;
|
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
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)
|
if (ov)
|
||||||
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
||||||
} 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)
|
if (rec)
|
||||||
ppc_changecrf0(remainder);
|
ppc_changecrf0(ppc_result_d);
|
||||||
|
|
||||||
ppc_store_iresult_reg(reg_d, 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>();
|
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>
|
template <field_rc rec, field_ov ov>
|
||||||
void dppc_interpreter::power_doz() {
|
void dppc_interpreter::power_doz() {
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
ppc_grab_regsdab(ppc_cur_instruction);
|
||||||
uint32_t ppc_result_d = (int32_t(ppc_result_a) < int32_t(ppc_result_b)) ?
|
uint32_t ppc_result_d = (int32_t(ppc_result_a) >= int32_t(ppc_result_b)) ? 0 :
|
||||||
ppc_result_b - ppc_result_a : 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)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_d);
|
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);
|
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_grab_regsdab(ppc_cur_instruction);
|
||||||
ppc_effective_address = ppc_result_b + (reg_a ? ppc_result_a : 0);
|
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_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);
|
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
|
// for storing each byte
|
||||||
|
uint32_t bitmask = 0xFF000000;
|
||||||
uint8_t shift_amount = 24;
|
uint8_t shift_amount = 24;
|
||||||
|
|
||||||
while (bytes_remaining > 0) {
|
while (bytes_to_load > 0) {
|
||||||
uint8_t return_value = mmu_read_vmem<uint8_t>(ppc_effective_address);
|
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 (!shift_amount) {
|
||||||
if (reg_d != reg_a && reg_d != reg_b)
|
if (reg_d != reg_a && reg_d != reg_b)
|
||||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||||
reg_d = (reg_d + 1) & 0x1F;
|
reg_d = (reg_d + 1) & 0x1F;
|
||||||
ppc_result_d = 0;
|
bitmask = 0xFF000000;
|
||||||
shift_amount = 24;
|
shift_amount = 24;
|
||||||
} else {
|
} else {
|
||||||
|
bitmask >>= 8;
|
||||||
shift_amount -= 8;
|
shift_amount -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppc_effective_address++;
|
ppc_effective_address++;
|
||||||
bytes_remaining--;
|
bytes_copied++;
|
||||||
|
bytes_to_load--;
|
||||||
|
|
||||||
if (return_value == matching_byte) {
|
if (return_value == matching_byte)
|
||||||
is_match = true;
|
|
||||||
break;
|
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)
|
if (shift_amount != 24 && reg_d != reg_a && reg_d != reg_b)
|
||||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
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) {
|
if (rec)
|
||||||
ppc_state.cr =
|
ppc_changecrf0(ppc_result_d);
|
||||||
(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>();
|
template void dppc_interpreter::power_lscbx<RC0>();
|
||||||
@ -271,7 +234,7 @@ void dppc_interpreter::power_maskg() {
|
|||||||
ppc_result_a = insert_mask;
|
ppc_result_a = insert_mask;
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_a);
|
ppc_changecrf0(ppc_result_d);
|
||||||
|
|
||||||
ppc_store_iresult_reg(reg_a, ppc_result_a);
|
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>
|
template <field_rc rec, field_ov ov>
|
||||||
void dppc_interpreter::power_mul() {
|
void dppc_interpreter::power_mul() {
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
ppc_grab_regsdab(ppc_cur_instruction);
|
||||||
int64_t product = int64_t(int32_t(ppc_result_a)) * int32_t(ppc_result_b);
|
uint64_t product;
|
||||||
uint32_t ppc_result_d = uint32_t(uint64_t(product) >> 32);
|
|
||||||
ppc_state.spr[SPR::MQ] = uint32_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)
|
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);
|
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>
|
template <field_rc rec, field_ov ov>
|
||||||
void dppc_interpreter::power_nabs() {
|
void dppc_interpreter::power_nabs() {
|
||||||
ppc_grab_regsda(ppc_cur_instruction);
|
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)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_d);
|
ppc_changecrf0(ppc_result_d);
|
||||||
|
if (ov)
|
||||||
|
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
||||||
|
|
||||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||||
}
|
}
|
||||||
@ -355,12 +316,11 @@ void dppc_interpreter::power_rlmi() {
|
|||||||
template <field_rc rec>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::power_rrib() {
|
void dppc_interpreter::power_rrib() {
|
||||||
ppc_grab_regssab(ppc_cur_instruction);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
|
||||||
|
|
||||||
if (int32_t(ppc_result_d) < 0) {
|
if (ppc_result_d & 0x80000000) {
|
||||||
ppc_result_a |= (0x80000000U >> rot_sh);
|
ppc_result_a |= ((ppc_result_d & 0x80000000) >> ppc_result_b);
|
||||||
} else {
|
} else {
|
||||||
ppc_result_a &= ~(0x80000000U >> rot_sh);
|
ppc_result_a &= ~((ppc_result_d & 0x80000000) >> ppc_result_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
@ -412,7 +372,8 @@ template void dppc_interpreter::power_sleq<RC1>();
|
|||||||
|
|
||||||
template <field_rc rec>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::power_sliq() {
|
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_result_a = ppc_result_d << rot_sh;
|
||||||
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - 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>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::power_slliq() {
|
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 r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||||
uint32_t mask = power_rot_mask(0, 31 - 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() {
|
void dppc_interpreter::power_sllq() {
|
||||||
ppc_grab_regssab(ppc_cur_instruction);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
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) {
|
if (ppc_result_b >= 0x20) {
|
||||||
ppc_result_a = ppc_state.spr[SPR::MQ] & (-1U << rot_sh);
|
ppc_result_a = (ppc_state.spr[SPR::MQ] & mask);
|
||||||
} else {
|
}
|
||||||
ppc_result_a = ((ppc_result_d << rot_sh) | (ppc_state.spr[SPR::MQ] & ((1 << rot_sh) - 1)));
|
else {
|
||||||
|
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
@ -469,17 +434,16 @@ void dppc_interpreter::power_slq() {
|
|||||||
ppc_grab_regssab(ppc_cur_instruction);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
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;
|
ppc_result_a = ppc_result_d << rot_sh;
|
||||||
|
} else {
|
||||||
|
ppc_result_a = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_a);
|
ppc_changecrf0(ppc_result_a);
|
||||||
|
|
||||||
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
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>();
|
template void dppc_interpreter::power_slq<RC0>();
|
||||||
@ -487,12 +451,13 @@ template void dppc_interpreter::power_slq<RC1>();
|
|||||||
|
|
||||||
template <field_rc rec>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::power_sraiq() {
|
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;
|
uint32_t mask = (1 << rot_sh) - 1;
|
||||||
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
|
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));
|
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;
|
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||||
} else {
|
} else {
|
||||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||||
@ -511,11 +476,11 @@ template <field_rc rec>
|
|||||||
void dppc_interpreter::power_sraq() {
|
void dppc_interpreter::power_sraq() {
|
||||||
ppc_grab_regssab(ppc_cur_instruction);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
unsigned rot_sh = ppc_result_b & 0x1F;
|
||||||
uint32_t mask = (ppc_result_b & 0x20) ? -1 : (1 << rot_sh) - 1;
|
uint32_t mask = (1 << rot_sh) - 1;
|
||||||
ppc_result_a = (int32_t)ppc_result_d >> ((ppc_result_b & 0x20) ? 31 : rot_sh);
|
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)));
|
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;
|
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||||
} else {
|
} else {
|
||||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||||
@ -555,10 +520,9 @@ void dppc_interpreter::power_srea() {
|
|||||||
ppc_grab_regssab(ppc_cur_instruction);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
unsigned rot_sh = ppc_result_b & 0x1F;
|
||||||
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
|
ppc_result_a = (int32_t)ppc_result_d >> rot_sh;
|
||||||
uint32_t r = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
|
ppc_state.spr[SPR::MQ] = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||||
uint32_t mask = -1U >> 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;
|
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||||
} else {
|
} else {
|
||||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
||||||
@ -568,7 +532,6 @@ void dppc_interpreter::power_srea() {
|
|||||||
ppc_changecrf0(ppc_result_a);
|
ppc_changecrf0(ppc_result_a);
|
||||||
|
|
||||||
ppc_store_iresult_reg(reg_a, 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>();
|
template void dppc_interpreter::power_srea<RC0>();
|
||||||
@ -578,10 +541,10 @@ template <field_rc rec>
|
|||||||
void dppc_interpreter::power_sreq() {
|
void dppc_interpreter::power_sreq() {
|
||||||
ppc_grab_regssab(ppc_cur_instruction);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
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_result_a = ((rot_sh & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
|
||||||
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
|
ppc_state.spr[SPR::MQ] = rot_sh;
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_a);
|
ppc_changecrf0(ppc_result_a);
|
||||||
@ -594,7 +557,8 @@ template void dppc_interpreter::power_sreq<RC1>();
|
|||||||
|
|
||||||
template <field_rc rec>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::power_sriq() {
|
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_result_a = ppc_result_d >> rot_sh;
|
||||||
ppc_state.spr[SPR::MQ] = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - 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>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::power_srliq() {
|
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));
|
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
|
||||||
unsigned mask = power_rot_mask(rot_sh, 31);
|
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));
|
uint32_t r = (ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh));
|
||||||
unsigned mask = power_rot_mask(rot_sh, 31);
|
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);
|
ppc_result_a = (ppc_state.spr[SPR::MQ] & mask);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
ppc_result_a = ((r & mask) | (ppc_state.spr[SPR::MQ] & ~mask));
|
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);
|
ppc_grab_regssab(ppc_cur_instruction);
|
||||||
unsigned rot_sh = ppc_result_b & 0x1F;
|
unsigned rot_sh = ppc_result_b & 0x1F;
|
||||||
|
|
||||||
if (ppc_result_b & 0x20) {
|
if (ppc_result_b >= 0x20) {
|
||||||
ppc_result_a = 0;
|
ppc_result_a = 0;
|
||||||
} else {
|
} else {
|
||||||
ppc_result_a = ppc_result_d >> rot_sh;
|
ppc_result_a = ppc_result_d >> rot_sh;
|
||||||
|
@ -85,18 +85,17 @@ extern SetPRS ppc_state;
|
|||||||
|
|
||||||
/** symbolic names for frequently used SPRs */
|
/** symbolic names for frequently used SPRs */
|
||||||
enum SPR : int {
|
enum SPR : int {
|
||||||
MQ = 0, // MQ (601)
|
MQ = 0,
|
||||||
XER = 1,
|
XER = 1,
|
||||||
RTCU_U = 4, // user mode RTCU (601)
|
RTCU_U = 4, // user RTCU
|
||||||
RTCL_U = 5, // user mode RTCL (601)
|
RTCL_U = 5, // user RTCL
|
||||||
DEC_U = 6, // user mode decrementer (601)
|
|
||||||
LR = 8,
|
LR = 8,
|
||||||
CTR = 9,
|
CTR = 9,
|
||||||
DSISR = 18,
|
DSISR = 18,
|
||||||
DAR = 19,
|
DAR = 19,
|
||||||
RTCU_S = 20, // supervisor RTCU (601)
|
RTCU_S = 20, // supervisor RTCU
|
||||||
RTCL_S = 21, // supervisor RTCL (601)
|
RTCL_S = 21, // supervisor RTCL
|
||||||
DEC_S = 22, // supervisor decrementer
|
DEC = 22, // decrementer
|
||||||
SDR1 = 25,
|
SDR1 = 25,
|
||||||
SRR0 = 26,
|
SRR0 = 26,
|
||||||
SRR1 = 27,
|
SRR1 = 27,
|
||||||
@ -399,7 +398,7 @@ typedef enum {
|
|||||||
} field_601;
|
} field_601;
|
||||||
|
|
||||||
// Function prototypes
|
// 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();
|
extern void ppc_mmu_init();
|
||||||
|
|
||||||
void ppc_illegalop();
|
void ppc_illegalop();
|
||||||
@ -415,7 +414,7 @@ void ppc_opcode31();
|
|||||||
void ppc_opcode59();
|
void ppc_opcode59();
|
||||||
void ppc_opcode63();
|
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 double fp_return_double(uint32_t reg);
|
||||||
extern uint64_t fp_return_uint64(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 OP63d(subopcode, fn) OPXd(SubOpcode63, subopcode, fn)
|
||||||
#define OP63dc(subopcode, fn, carry) OPXdc(SubOpcode63, subopcode, fn, carry)
|
#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);
|
std::fill_n(OpcodeGrabber, 64, ppc_illegalop);
|
||||||
OP(3, ppc_twi);
|
OP(3, ppc_twi);
|
||||||
//OP(4, ppc_opcode4); - Altivec instructions not emulated yet. Uncomment once they're implemented.
|
//OP(4, ppc_opcode4); - Altivec instructions not emulated yet. Uncomment once they're implemented.
|
||||||
OP(7, ppc_mulli);
|
OP(7, ppc_mulli);
|
||||||
OP(8, ppc_subfic);
|
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(10, ppc_cmpli);
|
||||||
OP(11, ppc_cmpi);
|
OP(11, ppc_cmpi);
|
||||||
OP(12, ppc_addic<RC0>);
|
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>);
|
if (is_601) OP(19, ppc_opcode19<IS601>); else OP(19, ppc_opcode19<NOT601>);
|
||||||
OP(20, ppc_rlwimi);
|
OP(20, ppc_rlwimi);
|
||||||
OP(21, ppc_rlwinm);
|
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(23, ppc_rlwnm);
|
||||||
OP(24, ppc_ori<SHFT0>);
|
OP(24, ppc_ori<SHFT0>);
|
||||||
OP(25, ppc_ori<SHFT1>);
|
OP(25, ppc_ori<SHFT1>);
|
||||||
@ -741,7 +741,7 @@ void initialize_ppc_opcode_tables(bool include_601) {
|
|||||||
OP31(470, ppc_dcbi);
|
OP31(470, ppc_dcbi);
|
||||||
OP31(1014, ppc_dcbz);
|
OP31(1014, ppc_dcbz);
|
||||||
|
|
||||||
if (is_601 || include_601) {
|
if (is_601) {
|
||||||
OP31d(29, power_maskg);
|
OP31d(29, power_maskg);
|
||||||
OP31od(107, power_mul);
|
OP31od(107, power_mul);
|
||||||
OP31d(152, power_slq);
|
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;
|
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;
|
ppc_state.spr[SPR::PVR] = cpu_version;
|
||||||
is_601 = (cpu_version >> 16) == 1;
|
is_601 = (cpu_version >> 16) == 1;
|
||||||
|
|
||||||
initialize_ppc_opcode_tables(include_601);
|
initialize_ppc_opcode_tables();
|
||||||
|
|
||||||
// initialize emulator timers
|
// initialize emulator timers
|
||||||
TimerManager::get_instance()->set_time_now_cb(&get_virt_time_ns);
|
TimerManager::get_instance()->set_time_now_cb(&get_virt_time_ns);
|
||||||
@ -865,7 +865,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601,
|
|||||||
ppc_state.msr = (MSR::ME + MSR::IP);
|
ppc_state.msr = (MSR::ME + MSR::IP);
|
||||||
} else {
|
} else {
|
||||||
ppc_state.msr = MSR::IP;
|
ppc_state.msr = MSR::IP;
|
||||||
ppc_state.spr[SPR::DEC_S] = 0xFFFFFFFFUL;
|
ppc_state.spr[SPR::DEC] = 0xFFFFFFFFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppc_mmu_init();
|
ppc_mmu_init();
|
||||||
@ -886,7 +886,7 @@ void print_fprs() {
|
|||||||
|
|
||||||
static map<string, int> SPRName2Num = {
|
static map<string, int> SPRName2Num = {
|
||||||
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR},
|
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR},
|
||||||
{"DEC", SPR::DEC_S}, {"PVR", SPR::PVR}, {"SPRG0", SPR::SPRG0},
|
{"DEC", SPR::DEC}, {"PVR", SPR::PVR}, {"SPRG0", SPR::SPRG0},
|
||||||
{"SPRG1", SPR::SPRG1}, {"SPRG2", SPR::SPRG2}, {"SPRG3", SPR::SPRG3},
|
{"SPRG1", SPR::SPRG1}, {"SPRG2", SPR::SPRG2}, {"SPRG3", SPR::SPRG3},
|
||||||
{"SRR0", SPR::SRR0}, {"SRR1", SPR::SRR1}, {"IBAT0U", 528},
|
{"SRR0", SPR::SRR0}, {"SRR1", SPR::SRR1}, {"IBAT0U", 528},
|
||||||
{"IBAT0L", 529}, {"IBAT1U", 530}, {"IBAT1L", 531},
|
{"IBAT0L", 529}, {"IBAT1U", 530}, {"IBAT1L", 531},
|
||||||
@ -897,9 +897,9 @@ static map<string, int> SPRName2Num = {
|
|||||||
{"HID0", SPR::HID0}, {"HID1", SPR::HID1}, {"IABR", 1010},
|
{"HID0", SPR::HID0}, {"HID1", SPR::HID1}, {"IABR", 1010},
|
||||||
{"DABR", 1013}, {"L2CR", 1017}, {"ICTC", 1019},
|
{"DABR", 1013}, {"L2CR", 1017}, {"ICTC", 1019},
|
||||||
{"THRM1", 1020}, {"THRM2", 1021}, {"THRM3", 1022},
|
{"THRM1", 1020}, {"THRM2", 1021}, {"THRM3", 1022},
|
||||||
{"PIR", 1023}, {"TBL", SPR::TBL_S}, {"TBU", SPR::TBU_S},
|
{"PIR", 1023}, {"TBL", SPR::TBL_U}, {"TBU", SPR::TBU_U},
|
||||||
{"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_S},
|
{"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_U},
|
||||||
{"RTCL", SPR::RTCL_S}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR},
|
{"RTCL", SPR::RTCL_U}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR},
|
||||||
{"MMCR0", SPR::MMCR0}, {"PMC1", SPR::PMC1}, {"PMC2", SPR::PMC2},
|
{"MMCR0", SPR::MMCR0}, {"PMC1", SPR::PMC1}, {"PMC2", SPR::PMC2},
|
||||||
{"SDA", SPR::SDA}, {"SIA", SPR::SIA}, {"MMCR1", SPR::MMCR1}
|
{"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_str = reg_name_u.substr(3);
|
||||||
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
|
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
|
||||||
if (reg_num < 1024) {
|
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)
|
if (is_write)
|
||||||
ppc_state.spr[reg_num] = (uint32_t)val;
|
ppc_state.spr[reg_num] = (uint32_t)val;
|
||||||
return ppc_state.spr[reg_num];
|
return ppc_state.spr[reg_num];
|
||||||
|
@ -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_d = ppc_state.gpr[reg_s]; \
|
||||||
uint32_t ppc_result_a = ppc_state.gpr[reg_a];
|
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) \
|
#define ppc_grab_regssb(opcode) \
|
||||||
uint32_t reg_s = (opcode >> 21) & 31; \
|
uint32_t reg_s = (opcode >> 21) & 31; \
|
||||||
|
@ -33,17 +33,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
// Affects CR Field 0 - For integer operations
|
// Affects CR Field 0 - For integer operations
|
||||||
void ppc_changecrf0(uint32_t set_result) {
|
void ppc_changecrf0(uint32_t set_result) {
|
||||||
ppc_state.cr =
|
ppc_state.cr &= 0x0FFFFFFFUL;
|
||||||
(ppc_state.cr & 0x0FFFFFFFU) // clear CR0
|
|
||||||
| (
|
if (set_result == 0) {
|
||||||
(set_result == 0) ?
|
ppc_state.cr |= 0x20000000UL;
|
||||||
CRx_bit::CR_EQ
|
} else {
|
||||||
: (int32_t(set_result) < 0) ?
|
if (set_result & 0x80000000) {
|
||||||
CRx_bit::CR_LT
|
ppc_state.cr |= 0x80000000UL;
|
||||||
:
|
} else {
|
||||||
CRx_bit::CR_GT
|
ppc_state.cr |= 0x40000000UL;
|
||||||
)
|
}
|
||||||
| ((ppc_state.spr[SPR::XER] & XER::SO) >> 3); // copy XER[SO] into CR0[SO].
|
}
|
||||||
|
|
||||||
|
/* copy XER[SO] into CR0[SO]. */
|
||||||
|
ppc_state.cr |= (ppc_state.spr[SPR::XER] >> 3) & 0x10000000UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Affects the XER register's Carry Bit
|
// 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
|
// Affects the XER register's SO and OV Bits
|
||||||
|
|
||||||
inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) {
|
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;
|
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||||
} else {
|
} else {
|
||||||
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
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
|
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 = 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)
|
if (ov)
|
||||||
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||||
@ -629,7 +632,7 @@ void dppc_interpreter::ppc_sraw() {
|
|||||||
} else {
|
} else {
|
||||||
uint32_t shift = ppc_result_b & 0x1F;
|
uint32_t shift = ppc_result_b & 0x1F;
|
||||||
ppc_result_a = int32_t(ppc_result_d) >> shift;
|
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;
|
ppc_state.spr[SPR::XER] |= XER::CA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,15 +647,16 @@ template void dppc_interpreter::ppc_sraw<RC1>();
|
|||||||
|
|
||||||
template <field_rc rec>
|
template <field_rc rec>
|
||||||
void dppc_interpreter::ppc_srawi() {
|
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
|
// clear XER[CA] by default
|
||||||
ppc_state.spr[SPR::XER] &= ~XER::CA;
|
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_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)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_a);
|
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() {
|
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_mb = (ppc_cur_instruction >> 6) & 0x1F;
|
||||||
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
|
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
|
||||||
uint32_t mask = rot_mask(rot_mb, rot_me);
|
uint32_t mask = rot_mask(rot_mb, rot_me);
|
||||||
@ -685,7 +690,8 @@ void dppc_interpreter::ppc_rlwimi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dppc_interpreter::ppc_rlwinm() {
|
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_mb = (ppc_cur_instruction >> 6) & 0x1F;
|
||||||
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
|
unsigned rot_me = (ppc_cur_instruction >> 1) & 0x1F;
|
||||||
uint32_t mask = rot_mask(rot_mb, rot_me);
|
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() {
|
void dppc_interpreter::ppc_mfspr() {
|
||||||
ppc_grab_dab(ppc_cur_instruction);
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
|
||||||
uint32_t ref_spr = (reg_b << 5) | reg_a;
|
((ppc_cur_instruction >> 16) & 0x1F);
|
||||||
|
|
||||||
if (ref_spr & 0x10) {
|
|
||||||
#ifdef CPU_PROFILING
|
#ifdef CPU_PROFILING
|
||||||
|
if (ref_spr > 31) {
|
||||||
num_supervisor_instrs++;
|
num_supervisor_instrs++;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ppc_state.msr & MSR::PR) {
|
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::NOT_ALLOWED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ref_spr) {
|
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:
|
case SPR::RTCL_U:
|
||||||
if (!is_601) {
|
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
|
||||||
}
|
|
||||||
calc_rtcl_value();
|
calc_rtcl_value();
|
||||||
ppc_state.gpr[reg_d] =
|
ppc_state.spr[SPR::RTCL_U] = rtc_lo & 0x3FFFFF80UL;
|
||||||
ppc_state.spr[SPR::RTCL_S] = rtc_lo & 0x3FFFFF80UL;
|
|
||||||
ppc_state.spr[SPR::RTCU_S] = rtc_hi;
|
|
||||||
break;
|
break;
|
||||||
case SPR::RTCU_U:
|
case SPR::RTCU_U:
|
||||||
if (!is_601) {
|
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
|
||||||
}
|
|
||||||
calc_rtcl_value();
|
calc_rtcl_value();
|
||||||
ppc_state.gpr[reg_d] =
|
ppc_state.spr[SPR::RTCU_U] = rtc_hi;
|
||||||
ppc_state.spr[SPR::RTCU_S] = rtc_hi;
|
|
||||||
ppc_state.spr[SPR::RTCL_S] = rtc_lo;
|
|
||||||
break;
|
break;
|
||||||
case SPR::DEC_U:
|
case SPR::DEC:
|
||||||
if (!is_601) {
|
ppc_state.spr[SPR::DEC] = calc_dec_value();
|
||||||
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;
|
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() {
|
void dppc_interpreter::ppc_mtspr() {
|
||||||
ppc_grab_dab(ppc_cur_instruction);
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
|
||||||
uint32_t ref_spr = (reg_b << 5) | reg_a;
|
((ppc_cur_instruction >> 16) & 0x1F);
|
||||||
|
|
||||||
if (ref_spr & 0x10) {
|
|
||||||
#ifdef CPU_PROFILING
|
#ifdef CPU_PROFILING
|
||||||
|
if (ref_spr > 31) {
|
||||||
num_supervisor_instrs++;
|
num_supervisor_instrs++;
|
||||||
#endif
|
|
||||||
if (ppc_state.msr & MSR::PR) {
|
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::NOT_ALLOWED);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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) {
|
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:
|
case SPR::XER:
|
||||||
ppc_state.spr[ref_spr] = val & 0xe000ff7f;
|
ppc_state.spr[ref_spr] = val & 0xe000ff7f;
|
||||||
break;
|
break;
|
||||||
case SPR::SDR1:
|
case SPR::SDR1:
|
||||||
ppc_state.spr[ref_spr] = val;
|
|
||||||
mmu_pat_ctx_changed(); // adapt to SDR1 changes
|
mmu_pat_ctx_changed(); // adapt to SDR1 changes
|
||||||
break;
|
break;
|
||||||
case SPR::RTCL_S:
|
case SPR::RTCL_S:
|
||||||
calc_rtcl_value();
|
calc_rtcl_value();
|
||||||
ppc_state.spr[RTCL_S] = rtc_lo = val & 0x3FFFFF80UL;
|
rtc_lo = val & 0x3FFFFF80UL;
|
||||||
ppc_state.spr[RTCU_S] = rtc_hi;
|
|
||||||
break;
|
break;
|
||||||
case SPR::RTCU_S:
|
case SPR::RTCU_S:
|
||||||
calc_rtcl_value();
|
calc_rtcl_value();
|
||||||
ppc_state.spr[RTCL_S] = rtc_lo;
|
rtc_hi = val;
|
||||||
ppc_state.spr[RTCU_S] = rtc_hi = val;
|
|
||||||
break;
|
break;
|
||||||
case SPR::DEC_S:
|
case SPR::DEC:
|
||||||
ppc_state.spr[DEC_S] = val;
|
|
||||||
update_decrementer(val);
|
update_decrementer(val);
|
||||||
break;
|
break;
|
||||||
case SPR::TBL_S:
|
case SPR::TBL_S:
|
||||||
update_timebase(0xFFFFFFFF00000000ULL, val);
|
update_timebase(0xFFFFFFFF00000000ULL, val);
|
||||||
ppc_state.spr[TBL_S] = val;
|
|
||||||
ppc_state.spr[TBU_S] = tbr_wr_value >> 32;
|
|
||||||
break;
|
break;
|
||||||
case SPR::TBU_S:
|
case SPR::TBU_S:
|
||||||
update_timebase(0x00000000FFFFFFFFULL, uint64_t(val) << 32);
|
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;
|
break;
|
||||||
case 528:
|
case 528:
|
||||||
case 529:
|
case 529:
|
||||||
@ -1006,7 +968,6 @@ void dppc_interpreter::ppc_mtspr() {
|
|||||||
case 533:
|
case 533:
|
||||||
case 534:
|
case 534:
|
||||||
case 535:
|
case 535:
|
||||||
ppc_state.spr[ref_spr] = val;
|
|
||||||
ibat_update(ref_spr);
|
ibat_update(ref_spr);
|
||||||
break;
|
break;
|
||||||
case 536:
|
case 536:
|
||||||
@ -1017,30 +978,23 @@ void dppc_interpreter::ppc_mtspr() {
|
|||||||
case 541:
|
case 541:
|
||||||
case 542:
|
case 542:
|
||||||
case 543:
|
case 543:
|
||||||
ppc_state.spr[ref_spr] = val;
|
|
||||||
dbat_update(ref_spr);
|
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() {
|
void dppc_interpreter::ppc_mftb() {
|
||||||
ppc_grab_dab(ppc_cur_instruction);
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 0x1F) << 5) |
|
||||||
uint32_t ref_spr = (reg_b << 5) | reg_a;
|
((ppc_cur_instruction >> 16) & 0x1F);
|
||||||
|
int reg_d = (ppc_cur_instruction >> 21) & 0x1F;
|
||||||
|
|
||||||
uint64_t tbr_value = calc_tbr_value();
|
uint64_t tbr_value = calc_tbr_value();
|
||||||
|
|
||||||
switch (ref_spr) {
|
switch (ref_spr) {
|
||||||
case SPR::TBL_U:
|
case SPR::TBL_U:
|
||||||
ppc_state.gpr[reg_d] =
|
ppc_state.gpr[reg_d] = uint32_t(tbr_value);
|
||||||
ppc_state.spr[TBL_S] = uint32_t(tbr_value);
|
|
||||||
ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32);
|
|
||||||
break;
|
break;
|
||||||
case SPR::TBU_U:
|
case SPR::TBU_U:
|
||||||
ppc_state.gpr[reg_d] =
|
ppc_state.gpr[reg_d] = uint32_t(tbr_value >> 32);
|
||||||
ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32);
|
|
||||||
ppc_state.spr[TBL_S] = uint32_t(tbr_value);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
||||||
@ -1866,9 +1820,10 @@ void dppc_interpreter::ppc_stswi() {
|
|||||||
#ifdef CPU_PROFILING
|
#ifdef CPU_PROFILING
|
||||||
num_int_stores++;
|
num_int_stores++;
|
||||||
#endif
|
#endif
|
||||||
ppc_grab_regssash(ppc_cur_instruction);
|
ppc_grab_regssa(ppc_cur_instruction);
|
||||||
ppc_effective_address = reg_a ? ppc_result_a : 0;
|
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) {
|
while (grab_inb >= 4) {
|
||||||
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_state.gpr[reg_s]);
|
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() {
|
int main() {
|
||||||
initialize_ppc_opcode_tables(true); //kludge
|
initialize_ppc_opcode_tables(); //kludge
|
||||||
|
|
||||||
cout << "Running DingusPPC emulator tests..." << endl << endl;
|
cout << "Running DingusPPC emulator tests..." << endl << endl;
|
||||||
|
|
||||||
|
@ -586,9 +586,6 @@ void ControlVideo::enable_display()
|
|||||||
// set framebuffer parameters
|
// set framebuffer parameters
|
||||||
this->fb_ptr = &this->vram_ptr[this->fb_base];
|
this->fb_ptr = &this->vram_ptr[this->fb_base];
|
||||||
this->fb_pitch = this->row_words;
|
this->fb_pitch = this->row_words;
|
||||||
if (~this->enables & SCAN_CONTROL) {
|
|
||||||
this->fb_pitch >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->pixel_depth = this->radacal->get_pix_width();
|
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) {
|
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
|
// set up periodic timer for display updates
|
||||||
if (this->active_width > 0 && this->active_height > 0 && this->pixel_clock > 0) {
|
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);
|
this->refresh_rate = (double)(this->pixel_clock) / (this->hori_total * this->vert_total);
|
||||||
if (~this->enables & SCAN_CONTROL) {
|
LOG_F(INFO, "Control: refresh rate set to %f Hz", this->refresh_rate);
|
||||||
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();
|
this->start_refresh_task();
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ int initialize_catalyst(std::string& id)
|
|||||||
std::string cpu = GET_STR_PROP("cpu");
|
std::string cpu = GET_STR_PROP("cpu");
|
||||||
if (cpu == "601") {
|
if (cpu == "601") {
|
||||||
// init virtual CPU and request MPC601
|
// 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") {
|
else if (cpu == "750") {
|
||||||
// configure CPU clocks
|
// configure CPU clocks
|
||||||
@ -87,7 +87,7 @@ int initialize_catalyst(std::string& id)
|
|||||||
uint64_t timebase_freq = bus_freq / 4;
|
uint64_t timebase_freq = bus_freq / 4;
|
||||||
|
|
||||||
// initialize virtual CPU and request MPC750 CPU aka G3
|
// 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
|
// set CPU PLL ratio to 3.5
|
||||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||||
|
@ -77,7 +77,7 @@ int initialize_gazelle(std::string& id)
|
|||||||
uint64_t timebase_freq = bus_freq / 4;
|
uint64_t timebase_freq = bus_freq / 4;
|
||||||
|
|
||||||
// init virtual CPU and request MPC603ev
|
// 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
|
// CPU frequency is hardcoded to 225 MHz for now
|
||||||
ppc_state.spr[SPR::HID1] = get_cpu_pll_value(225000000) << 28;
|
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;
|
uint64_t timebase_freq = bus_freq / 4;
|
||||||
|
|
||||||
// initialize virtual CPU and request MPC750 CPU aka G3
|
// 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
|
// set CPU PLL ratio to 3.5
|
||||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||||
|
@ -90,7 +90,7 @@ int initialize_pdm(std::string& id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init virtual CPU and request MPC601
|
// 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;
|
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
|
aspen_obj->insert_ram_dimm(3, GET_INT_PROP("rambank4_size")); // RAM expansion slot
|
||||||
|
|
||||||
// init virtual CPU
|
// init virtual CPU
|
||||||
ppc_cpu_init(aspen_obj, PPC_VER::MPC603, false, 16500000ULL);
|
ppc_cpu_init(aspen_obj, PPC_VER::MPC603, 16500000ULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -101,16 +101,16 @@ int initialize_tnt(std::string& id)
|
|||||||
// init virtual CPU
|
// init virtual CPU
|
||||||
std::string cpu = GET_STR_PROP("cpu");
|
std::string cpu = GET_STR_PROP("cpu");
|
||||||
if (cpu == "604e")
|
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")
|
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") {
|
else if (cpu == "750") {
|
||||||
// configure CPU clocks
|
// configure CPU clocks
|
||||||
uint64_t bus_freq = 50000000ULL;
|
uint64_t bus_freq = 50000000ULL;
|
||||||
uint64_t timebase_freq = bus_freq / 4;
|
uint64_t timebase_freq = bus_freq / 4;
|
||||||
|
|
||||||
// initialize virtual CPU and request MPC750 CPU aka G3
|
// 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
|
// set CPU PLL ratio to 3.5
|
||||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||||
|
@ -76,7 +76,7 @@ int initialize_yosemite(std::string& id)
|
|||||||
uint64_t timebase_freq = bus_freq / 4;
|
uint64_t timebase_freq = bus_freq / 4;
|
||||||
|
|
||||||
// initialize virtual CPU and request MPC750 CPU aka G3
|
// 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
|
// set CPU PLL ratio to 3.5
|
||||||
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
ppc_state.spr[SPR::HID1] = 0xE << 28;
|
||||||
|
101
memaccess.h
101
memaccess.h
@ -31,127 +31,110 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
|
|
||||||
/* read an aligned big-endian WORD (16bit) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* read an unaligned big-endian DWORD (32bit) */
|
||||||
#define READ_DWORD_BE_U(addr) \
|
#define READ_DWORD_BE_U(addr) \
|
||||||
((((uint8_t*)(addr))[0] << 24) | (((uint8_t*)(addr))[1] << 16) | \
|
(((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
|
||||||
(((uint8_t*)(addr))[2] << 8) | ((uint8_t*)(addr))[3] )
|
|
||||||
|
|
||||||
/* read an unaligned big-endian QWORD (32bit) */
|
/* read an unaligned big-endian QWORD (32bit) */
|
||||||
#define READ_QWORD_BE_U(addr) \
|
#define READ_QWORD_BE_U(addr) \
|
||||||
((uint64_t(((uint8_t*)(addr))[0]) << 56) | (uint64_t(((uint8_t*)(addr))[1]) << 48) | \
|
((uint64_t((addr)[0]) << 56) | (uint64_t((addr)[1]) << 48) | \
|
||||||
(uint64_t(((uint8_t*)(addr))[2]) << 40) | (uint64_t(((uint8_t*)(addr))[3]) << 32) | \
|
(uint64_t((addr)[2]) << 40) | (uint64_t((addr)[3]) << 32) | \
|
||||||
(uint64_t(((uint8_t*)(addr))[4]) << 24) | ( ((uint8_t*)(addr))[5] << 16) | \
|
(uint64_t((addr)[4]) << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
|
||||||
( ((uint8_t*)(addr))[6] << 8) | ((uint8_t*)(addr))[7] )
|
|
||||||
|
|
||||||
/* read an unaligned little-endian WORD (16bit) */
|
/* 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) */
|
/* read an unaligned little-endian DWORD (32bit) */
|
||||||
#define READ_DWORD_LE_U(addr) \
|
#define READ_DWORD_LE_U(addr) \
|
||||||
((((uint8_t*)(addr))[3] << 24) | (((uint8_t*)(addr))[2] << 16) | \
|
(((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||||
(((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(addr))[0] )
|
|
||||||
|
|
||||||
/* read an unaligned little-endian DWORD (64bit) */
|
/* read an unaligned little-endian DWORD (64bit) */
|
||||||
#define READ_QWORD_LE_U(addr) \
|
#define READ_QWORD_LE_U(addr) \
|
||||||
((uint64_t(((uint8_t*)(addr))[7]) << 56) | (uint64_t(((uint8_t*)(addr))[6]) << 48) | \
|
((uint64_t((addr)[7]) << 56) | (uint64_t((addr)[6]) << 48) | \
|
||||||
(uint64_t(((uint8_t*)(addr))[5]) << 40) | (uint64_t(((uint8_t*)(addr))[4]) << 32) | \
|
(uint64_t((addr)[5]) << 40) | (uint64_t((addr)[4]) << 32) | \
|
||||||
(uint64_t(((uint8_t*)(addr))[3]) << 24) | ( ((uint8_t*)(addr))[2] << 16) | \
|
(uint64_t((addr)[3]) << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||||
( ((uint8_t*)(addr))[1] << 8) | ((uint8_t*)(addr))[0] )
|
|
||||||
|
|
||||||
/* write an aligned big-endian WORD (16bit) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* write an unaligned big-endian WORD (16bit) */
|
||||||
#define WRITE_WORD_BE_U(addr, val) \
|
#define WRITE_WORD_BE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
((uint8_t*)(addr))[0] = ((val) >> 8); \
|
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||||
((uint8_t*)(addr))[1] = (uint8_t)(val); \
|
(addr)[1] = (val) & 0xFF; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* write an unaligned big-endian DWORD (32bit) */
|
/* write an unaligned big-endian DWORD (32bit) */
|
||||||
#define WRITE_DWORD_BE_U(addr, val) \
|
#define WRITE_DWORD_BE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
((uint8_t*)(addr))[0] = ((val) >> 24); \
|
(addr)[0] = ((val) >> 24) & 0xFF; \
|
||||||
((uint8_t*)(addr))[1] = ((val) >> 16); \
|
(addr)[1] = ((val) >> 16) & 0xFF; \
|
||||||
((uint8_t*)(addr))[2] = ((val) >> 8); \
|
(addr)[2] = ((val) >> 8) & 0xFF; \
|
||||||
((uint8_t*)(addr))[3] = (uint8_t)(val); \
|
(addr)[3] = (val) & 0xFF; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* write an unaligned big-endian DWORD (64bit) */
|
/* write an unaligned big-endian DWORD (64bit) */
|
||||||
#define WRITE_QWORD_BE_U(addr, val) \
|
#define WRITE_QWORD_BE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
((uint8_t*)(addr))[0] = ((uint64_t)(val) >> 56); \
|
(addr)[0] = ((uint64_t)(val) >> 56) & 0xFF; \
|
||||||
((uint8_t*)(addr))[1] = ((uint64_t)(val) >> 48); \
|
(addr)[1] = ((uint64_t)(val) >> 48) & 0xFF; \
|
||||||
((uint8_t*)(addr))[2] = ((uint64_t)(val) >> 40); \
|
(addr)[2] = ((uint64_t)(val) >> 40) & 0xFF; \
|
||||||
((uint8_t*)(addr))[3] = ((uint64_t)(val) >> 32); \
|
(addr)[3] = ((uint64_t)(val) >> 32) & 0xFF; \
|
||||||
((uint8_t*)(addr))[4] = ( (val) >> 24); \
|
(addr)[4] = ((uint64_t)(val) >> 24) & 0xFF; \
|
||||||
((uint8_t*)(addr))[5] = ( (val) >> 16); \
|
(addr)[5] = ((val) >> 16) & 0xFF; \
|
||||||
((uint8_t*)(addr))[6] = ( (val) >> 8); \
|
(addr)[6] = ((val) >> 8) & 0xFF; \
|
||||||
((uint8_t*)(addr))[7] = (uint8_t)(val) ; \
|
(addr)[7] = (val) & 0xFF; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* write an aligned little-endian WORD (16bit) */
|
/* 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) */
|
/* 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) */
|
/* 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) */
|
/* write an unaligned little-endian WORD (16bit) */
|
||||||
#define WRITE_WORD_LE_U(addr, val) \
|
#define WRITE_WORD_LE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
((uint8_t*)(addr))[0] = (uint8_t)(val); \
|
(addr)[0] = (val)&0xFF; \
|
||||||
((uint8_t*)(addr))[1] = ((val) >> 8); \
|
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* write an unaligned little-endian DWORD (32bit) */
|
/* write an unaligned little-endian DWORD (32bit) */
|
||||||
#define WRITE_DWORD_LE_U(addr, val) \
|
#define WRITE_DWORD_LE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
((uint8_t*)(addr))[0] = (uint8_t)(val); \
|
(addr)[0] = (val)&0xFF; \
|
||||||
((uint8_t*)(addr))[1] = ((val) >> 8); \
|
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||||
((uint8_t*)(addr))[2] = ((val) >> 16); \
|
(addr)[2] = ((val) >> 16) & 0xFF; \
|
||||||
((uint8_t*)(addr))[3] = ((val) >> 24); \
|
(addr)[3] = ((val) >> 24) & 0xFF; \
|
||||||
} 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)
|
} while (0)
|
||||||
|
|
||||||
/* read value of the specified size from memory starting at addr,
|
/* read value of the specified size from memory starting at addr,
|
||||||
|
Loading…
Reference in New Issue
Block a user