dingusppc/cpu/ppc/ppcexec.cpp

947 lines
43 KiB
C++
Raw Normal View History

/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-20 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2020-01-05 17:38:32 +00:00
#include <algorithm>
2020-05-12 18:55:45 +00:00
#include <iostream>
#include <map>
#include <setjmp.h>
2020-05-12 18:55:45 +00:00
#include <stdexcept>
#include <stdio.h>
#include <string>
#include <thirdparty/loguru/loguru.hpp>
#include <unordered_map>
#include "ppcemu.h"
#include "ppcmmu.h"
2020-05-31 22:46:00 +00:00
#define NEW_TBR_UPDATE_ALGO
using namespace std;
2020-05-12 18:55:45 +00:00
MemCtrlBase* mem_ctrl_instance = 0;
2020-01-31 03:08:22 +00:00
bool power_on = 1;
SetPRS ppc_state;
bool grab_exception;
bool grab_return;
bool grab_breakpoint;
2020-05-12 18:55:45 +00:00
uint32_t ppc_cur_instruction; // Current instruction for the PPC
uint32_t ppc_effective_address;
2020-05-12 18:55:45 +00:00
uint32_t ppc_next_instruction_address; // Used for branching, setting up the NIA
BB_end_kind bb_kind; /* basic block end */
/* copy of local variable bb_start_la. Need for correct
calculation of CPU cycles after setjmp that clobbers
non-volatile local variables. */
uint32_t glob_bb_start_la;
2020-05-31 22:46:00 +00:00
/* variables related to virtual time */
uint64_t cycles_count; /* contains number of cycles executed so far */
uint64_t old_cycles_count; /* previous value for cycles_count */
uint64_t timebase_counter; /* internal timebase counter */
uint32_t decr; /* current value of PPC DEC register */
uint8_t old_decr_msb; /* MSB value for previous DEC value */
uint8_t tbr_factor; /* cycles_count to TBR freq ratio in 2^x units */
/** Opcode lookup tables. */
/** Primary opcode (bits 0...5) lookup table. */
static PPCOpcode OpcodeGrabber[] = {
2020-05-12 18:55:45 +00:00
ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_twi, ppc_opcode4, ppc_illegalop,
ppc_illegalop, ppc_mulli, ppc_subfic, power_dozi, ppc_cmpli, ppc_cmpi,
ppc_addic, ppc_addicdot, ppc_addi, ppc_addis, ppc_opcode16, ppc_sc,
ppc_opcode18, ppc_opcode19, ppc_rlwimi, ppc_rlwinm, power_rlmi, ppc_rlwnm,
ppc_ori, ppc_oris, ppc_xori, ppc_xoris, ppc_andidot, ppc_andisdot,
ppc_illegalop, ppc_opcode31, ppc_lwz, ppc_lwzu, ppc_lbz, ppc_lbzu,
ppc_stw, ppc_stwu, ppc_stb, ppc_stbu, ppc_lhz, ppc_lhzu,
ppc_lha, ppc_lhau, ppc_sth, ppc_sthu, ppc_lmw, ppc_stmw,
ppc_lfs, ppc_lfsu, ppc_lfd, ppc_lfdu, ppc_stfs, ppc_stfsu,
ppc_stfd, ppc_stfdu, ppc_psq_l, ppc_psq_lu, ppc_illegalop, ppc_illegalop,
ppc_psq_st, ppc_psq_stu, ppc_illegalop, ppc_opcode63};
/** Lookup tables for branch instructions. */
2020-07-13 21:39:31 +00:00
static PPCOpcode SubOpcode16Grabber[] = {ppc_bc1, ppc_bcl, ppc_bca, ppc_bcla};
2020-05-12 18:55:45 +00:00
static PPCOpcode SubOpcode18Grabber[] = {ppc_b, ppc_bl, ppc_ba, ppc_bla};
/** General conditional register instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode19Grabber = {
2020-05-12 18:55:45 +00:00
{32, &ppc_bclr},
{33, &ppc_bclrl},
{66, &ppc_crnor},
{100, &ppc_rfi},
{258, &ppc_crandc},
{300, &ppc_isync},
{386, &ppc_crxor},
{450, &ppc_crnand},
{514, &ppc_crand},
{578, &ppc_creqv},
{834, &ppc_crorc},
{898, &ppc_cror},
{1056, &ppc_bcctr},
{1057, &ppc_bcctrl}};
/** General integer instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode31Grabber = {
2020-05-12 18:55:45 +00:00
{0, &ppc_cmp}, {8, &ppc_tw},
{16, &ppc_subfc}, {17, &ppc_subfcdot},
{20, &ppc_addc}, {21, &ppc_addcdot},
{22, &ppc_mulhwu}, {23, &ppc_mulhwudot},
{38, &ppc_mfcr}, {40, &ppc_lwarx},
{46, &ppc_lwzx}, {48, &ppc_slw},
{49, &ppc_slwdot}, {52, &ppc_cntlzw},
{53, &ppc_cntlzwdot}, {56, &ppc_and},
{57, &ppc_anddot}, {58, &power_maskg},
{59, &power_maskgdot}, {64, &ppc_cmpl},
{80, &ppc_subf}, {81, &ppc_subfdot},
{108, &ppc_dcbst}, {110, &ppc_lwzux},
{120, &ppc_andc}, {121, &ppc_andcdot},
{150, &ppc_mulhw}, {151, &ppc_mulhwdot},
{166, &ppc_mfmsr}, {172, &ppc_dcbf},
{174, &ppc_lbzx}, {208, &ppc_neg},
{209, &ppc_negdot}, {214, &power_mul},
{215, &power_muldot}, {238, &ppc_lbzux},
{248, &ppc_nor}, {249, &ppc_nordot},
{272, &ppc_subfe}, {273, &ppc_subfedot},
{276, &ppc_adde}, {277, &ppc_addedot},
{288, &ppc_mtcrf}, {292, &ppc_mtmsr},
{301, &ppc_stwcx}, {302, &ppc_stwx},
{304, &power_slq}, {305, &power_slqdot},
{306, &power_sle}, {307, &power_sledot},
{366, &ppc_stwux}, {368, &power_sliq},
{400, &ppc_subfze}, {401, &ppc_subfzedot},
{404, &ppc_addze}, {405, &ppc_addzedot},
{420, &ppc_mtsr}, {430, &ppc_stbx},
{432, &power_sllq}, {433, &power_sllqdot},
{434, &power_sleq}, {436, &power_sleqdot},
{464, &ppc_subfme}, {465, &ppc_subfmedot},
{468, &ppc_addme}, {469, &ppc_addmedot},
{470, &ppc_mullw}, {471, &ppc_mullwdot},
{484, &ppc_mtsrin}, {492, &ppc_dcbtst},
{494, &ppc_stbux}, {496, &power_slliq},
{497, &power_slliqdot}, {528, &power_doz},
{529, &power_dozdot}, {532, &ppc_add},
{533, &ppc_adddot}, {554, &power_lscbx},
{555, &power_lscbxdot}, {556, &ppc_dcbt},
{558, &ppc_lhzx}, {568, &ppc_eqv},
{569, &ppc_eqvdot}, {612, &ppc_tlbie},
{622, &ppc_lhzux}, {632, &ppc_xor},
{633, &ppc_xordot}, {662, &power_div},
{663, &power_divdot}, {678, &ppc_mfspr},
{686, &ppc_lhax}, {720, &power_abs},
{721, &power_absdot}, {726, &power_divs},
{727, &power_divsdot}, {740, &ppc_tlbia},
{742, &ppc_mftb}, {750, &ppc_lhaux},
{814, &ppc_sthx}, {824, &ppc_orc},
{825, &ppc_orcdot}, {878, &ppc_sthx},
{888, &ppc_or}, {889, &ppc_ordot},
{918, &ppc_divwu}, {919, &ppc_divwudot},
{934, &ppc_mtspr}, {940, &ppc_dcbi},
{952, &ppc_nand}, {953, &ppc_nanddot},
{976, &power_nabs}, {977, &power_nabsdot},
{982, &ppc_divw}, {983, &ppc_divwdot},
{1024, &ppc_mcrxr}, {1040, &ppc_subfco},
{1041, &ppc_subfcodot}, {1044, &ppc_addco},
{1045, &ppc_addcodot}, {1062, &power_clcs},
{1063, &power_clcsdot}, {1066, &ppc_lswx},
{1068, &ppc_lwbrx}, {1070, &ppc_lfsx},
{1072, &ppc_srw}, {1073, &ppc_srwdot},
{1074, &power_rrib}, {1075, &power_rribdot},
{1082, &power_maskir}, {1083, &power_maskirdot},
{1104, &ppc_subfo}, {1105, &ppc_subfodot},
{1132, &ppc_tlbsync}, {1134, &ppc_lfsux},
{1190, &ppc_mfsr}, {1194, &ppc_lswi},
{1196, &ppc_sync}, {1198, &ppc_lfdx},
{1232, &ppc_nego}, {1233, &ppc_negodot},
{1238, &power_mulo}, {1239, &power_mulodot},
{1262, &ppc_lfdux}, {1296, &ppc_subfeo},
{1297, &ppc_subfeodot}, {1300, &ppc_addeo},
{1301, &ppc_addeodot}, {1318, &ppc_mfsrin},
{1322, &ppc_stswx}, {1324, &ppc_stwbrx},
{1326, &ppc_stfsx}, {1328, &power_srq},
{1329, &power_srqdot}, {1330, &power_sre},
{1331, &power_sredot}, {1390, &ppc_stfsux},
{1392, &power_sriq}, {1393, &power_sriqdot},
{1424, &ppc_subfzeo}, {1425, &ppc_subfzeodot},
{1428, &ppc_addzeo}, {1429, &ppc_addzeodot},
{1450, &ppc_stswi}, {1454, &ppc_stfdx},
{1456, &power_srlq}, {1457, &power_srlqdot},
{1458, &power_sreq}, {1459, &power_sreqdot},
{1488, &ppc_subfmeo}, {1489, &ppc_subfmeodot},
{1492, &ppc_addmeo}, {1493, &ppc_addmeodot},
{1494, &ppc_mullwo}, {1495, &ppc_mullwodot},
{1518, &ppc_stfdux}, {1520, &power_srliq},
{1521, &power_srliqdot}, {1552, &power_dozo},
{1553, &power_dozodot}, {1556, &ppc_addo},
{1557, &ppc_addodot}, {1580, &ppc_lhbrx},
{1584, &ppc_sraw}, {1585, &ppc_srawdot},
{1648, &ppc_srawi}, {1649, &ppc_srawidot},
{1686, &power_divo}, {1687, &power_divodot},
{1708, &ppc_eieio}, {1744, &power_abso},
{1745, &power_absodot}, {1750, &power_divso},
{1751, &power_divsodot}, {1836, &ppc_sthbrx},
{1840, &power_sraq}, {1841, &power_sraqdot},
{1842, &power_srea}, {1843, &power_sreadot},
{1844, &ppc_extsh}, {1845, &ppc_extshdot},
{1904, &power_sraiq}, {1905, &power_sraiqdot},
{1908, &ppc_extsb}, {1909, &ppc_extsbdot},
{1942, &ppc_divwuo}, {1943, &ppc_divwuodot},
{1956, &ppc_tlbld}, {1964, &ppc_icbi},
{1966, &ppc_stfiwx}, {2000, &power_nabso},
{2001, &power_nabsodot}, {2006, &ppc_divwo},
{2007, &ppc_divwodot}, {2020, &ppc_tlbli},
{2028, &ppc_dcbz}};
/** Single-precision floating-point instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode59Grabber = {
2020-05-12 18:55:45 +00:00
{36, &ppc_fdivs}, {37, &ppc_fdivsdot}, {40, &ppc_fsubs}, {41, &ppc_fsubsdot},
{42, &ppc_fadds}, {43, &ppc_faddsdot}, {44, &ppc_fsqrts}, {45, &ppc_fsqrtsdot},
{48, &ppc_fres}, {49, &ppc_fresdot}, {50, &ppc_fmults}, {51, &ppc_fmultsdot},
{56, &ppc_fmsubs}, {57, &ppc_fmsubsdot}, {58, &ppc_fmadds}, {59, &ppc_fmaddsdot},
{60, &ppc_fnmsubs}, {61, &ppc_fnmsubsdot}, {62, &ppc_fnmadds}, {63, &ppc_fnmaddsdot},
{114, &ppc_fmults}, {115, &ppc_fmultsdot}, {120, &ppc_fmsubs}, {121, &ppc_fmsubsdot},
{122, &ppc_fmadds}, {123, &ppc_fmadds}, {124, &ppc_fnmsubs}, {125, &ppc_fnmsubsdot},
{126, &ppc_fnmadds}, {127, &ppc_fnmaddsdot}, {178, &ppc_fmults}, {179, &ppc_fmultsdot},
{184, &ppc_fmsubs}, {185, &ppc_fmsubsdot}, {186, &ppc_fmadds}, {187, &ppc_fmaddsdot},
{188, &ppc_fnmsubs}, {189, &ppc_fnmsubsdot}, {190, &ppc_fnmadds}, {191, &ppc_fnmaddsdot},
{242, &ppc_fmults}, {243, &ppc_fmultsdot}, {248, &ppc_fmsubs}, {249, &ppc_fmsubsdot},
{250, &ppc_fmadds}, {251, &ppc_fmaddsdot}, {252, &ppc_fnmsubs}, {253, &ppc_fnmsubsdot},
{254, &ppc_fnmadds}, {255, &ppc_fnmaddsdot}, {306, &ppc_fmults}, {307, &ppc_fmultsdot},
{312, &ppc_fmsubs}, {313, &ppc_fmsubsdot}, {314, &ppc_fmadds}, {315, &ppc_fmaddsdot},
{316, &ppc_fnmsubs}, {317, &ppc_fnmsubsdot}, {318, &ppc_fnmadds}, {319, &ppc_fnmaddsdot},
{370, &ppc_fmults}, {371, &ppc_fmultsdot}, {376, &ppc_fmsubs}, {377, &ppc_fmsubsdot},
{378, &ppc_fmadds}, {379, &ppc_fmaddsdot}, {380, &ppc_fnmsubs}, {381, &ppc_fnmsubsdot},
{382, &ppc_fnmadds}, {383, &ppc_fnmaddsdot}, {434, &ppc_fmults}, {435, &ppc_fmultsdot},
{440, &ppc_fmsubs}, {441, &ppc_fmsubsdot}, {442, &ppc_fmadds}, {443, &ppc_fmaddsdot},
{444, &ppc_fnmsubs}, {445, &ppc_fnmsubsdot}, {446, &ppc_fnmadds}, {447, &ppc_fnmaddsdot},
{498, &ppc_fmults}, {499, &ppc_fmultsdot}, {504, &ppc_fmsubs}, {505, &ppc_fmsubsdot},
{506, &ppc_fmadds}, {507, &ppc_fmaddsdot}, {508, &ppc_fnmsubs}, {509, &ppc_fnmsubsdot},
{510, &ppc_fnmadds}, {511, &ppc_fnmaddsdot}, {562, &ppc_fmults}, {563, &ppc_fmultsdot},
{568, &ppc_fmsubs}, {569, &ppc_fmsubsdot}, {570, &ppc_fmadds}, {571, &ppc_fmaddsdot},
{572, &ppc_fnmsubs}, {573, &ppc_fnmsubsdot}, {574, &ppc_fnmadds}, {575, &ppc_fnmaddsdot},
{626, &ppc_fmults}, {627, &ppc_fmultsdot}, {632, &ppc_fmsubs}, {633, &ppc_fmsubsdot},
{634, &ppc_fmadds}, {635, &ppc_fmaddsdot}, {636, &ppc_fnmsubs}, {637, &ppc_fnmsubsdot},
{638, &ppc_fnmadds}, {639, &ppc_fnmaddsdot}, {690, &ppc_fmults}, {691, &ppc_fmultsdot},
{696, &ppc_fmsubs}, {697, &ppc_fmsubsdot}, {698, &ppc_fmadds}, {699, &ppc_fmaddsdot},
{700, &ppc_fnmsubs}, {701, &ppc_fnmsubsdot}, {702, &ppc_fnmadds}, {703, &ppc_fnmaddsdot},
{754, &ppc_fmults}, {755, &ppc_fmultsdot}, {760, &ppc_fmsubs}, {761, &ppc_fmsubsdot},
{762, &ppc_fmadds}, {763, &ppc_fmaddsdot}, {764, &ppc_fnmsubs}, {765, &ppc_fnmsubsdot},
{766, &ppc_fnmadds}, {767, &ppc_fnmaddsdot}, {818, &ppc_fmults}, {819, &ppc_fmultsdot},
{824, &ppc_fmsubs}, {825, &ppc_fmsubsdot}, {826, &ppc_fmadds}, {827, &ppc_fmaddsdot},
{828, &ppc_fnmsubs}, {829, &ppc_fnmsubsdot}, {830, &ppc_fnmadds}, {831, &ppc_fnmaddsdot},
{882, &ppc_fmults}, {883, &ppc_fmultsdot}, {888, &ppc_fmsubs}, {889, &ppc_fmsubsdot},
{890, &ppc_fmadds}, {891, &ppc_fmaddsdot}, {892, &ppc_fnmsubs}, {893, &ppc_fnmsubsdot},
{894, &ppc_fnmadds}, {895, &ppc_fnmaddsdot}, {946, &ppc_fmults}, {947, &ppc_fmultsdot},
{952, &ppc_fmsubs}, {953, &ppc_fmsubsdot}, {954, &ppc_fmadds}, {955, &ppc_fmaddsdot},
{957, &ppc_fnmsubs}, {958, &ppc_fnmsubsdot}, {958, &ppc_fnmadds}, {959, &ppc_fnmaddsdot},
{1010, &ppc_fmults}, {1011, &ppc_fmultsdot}, {1016, &ppc_fmsubs}, {1017, &ppc_fmsubsdot},
{1018, &ppc_fmadds}, {1019, &ppc_fmaddsdot}, {1020, &ppc_fnmsubs}, {1021, &ppc_fnmsubsdot},
{1022, &ppc_fnmadds}, {1023, &ppc_fnmaddsdot}, {1074, &ppc_fmults}, {1075, &ppc_fmultsdot},
{1080, &ppc_fmsubs}, {1081, &ppc_fmsubsdot}, {1082, &ppc_fmadds}, {1083, &ppc_fmaddsdot},
{1084, &ppc_fnmsubs}, {1085, &ppc_fnmsubsdot}, {1086, &ppc_fnmadds}, {1087, &ppc_fnmaddsdot},
{1138, &ppc_fmults}, {1139, &ppc_fmultsdot}, {1144, &ppc_fmsubs}, {1145, &ppc_fmsubsdot},
{1146, &ppc_fmadds}, {1147, &ppc_fmaddsdot}, {1148, &ppc_fnmsubs}, {1149, &ppc_fnmsubsdot},
{1150, &ppc_fnmadds}, {1151, &ppc_fnmaddsdot}, {1202, &ppc_fmults}, {1203, &ppc_fmultsdot},
{1208, &ppc_fmsubs}, {1209, &ppc_fmsubsdot}, {1210, &ppc_fmadds}, {1211, &ppc_fmaddsdot},
{1212, &ppc_fnmsubs}, {1213, &ppc_fnmsubsdot}, {1214, &ppc_fnmadds}, {1215, &ppc_fnmaddsdot},
{1266, &ppc_fmults}, {1267, &ppc_fmultsdot}, {1272, &ppc_fmsubs}, {1273, &ppc_fmsubsdot},
{1274, &ppc_fmadds}, {1275, &ppc_fmaddsdot}, {1276, &ppc_fnmsubs}, {1277, &ppc_fnmsubsdot},
{1278, &ppc_fnmadds}, {1279, &ppc_fnmaddsdot}, {1330, &ppc_fmults}, {1331, &ppc_fmultsdot},
{1336, &ppc_fmsubs}, {1337, &ppc_fmsubsdot}, {1338, &ppc_fmadds}, {1339, &ppc_fmaddsdot},
{1340, &ppc_fnmsubs}, {1341, &ppc_fnmsubsdot}, {1342, &ppc_fnmadds}, {1343, &ppc_fnmaddsdot},
{1394, &ppc_fmults}, {1395, &ppc_fmultsdot}, {1400, &ppc_fmsubs}, {1401, &ppc_fmsubsdot},
{1402, &ppc_fmadds}, {1403, &ppc_fmaddsdot}, {1404, &ppc_fnmsubs}, {1405, &ppc_fnmsubsdot},
{1406, &ppc_fnmadds}, {1407, &ppc_fnmaddsdot}, {1458, &ppc_fmults}, {1459, &ppc_fmultsdot},
{1464, &ppc_fmsubs}, {1465, &ppc_fmsubsdot}, {1466, &ppc_fmadds}, {1467, &ppc_fmaddsdot},
{1468, &ppc_fnmsubs}, {1469, &ppc_fnmsubsdot}, {1470, &ppc_fnmadds}, {1471, &ppc_fnmaddsdot},
{1522, &ppc_fmults}, {1523, &ppc_fmultsdot}, {1528, &ppc_fmsubs}, {1529, &ppc_fmsubsdot},
{1530, &ppc_fmadds}, {1531, &ppc_fmaddsdot}, {1532, &ppc_fnmsubs}, {1533, &ppc_fnmsubsdot},
{1534, &ppc_fnmadds}, {1535, &ppc_fnmaddsdot}, {1586, &ppc_fmults}, {1587, &ppc_fmultsdot},
{1592, &ppc_fmsubs}, {1593, &ppc_fmsubsdot}, {1594, &ppc_fmadds}, {1595, &ppc_fmaddsdot},
{1596, &ppc_fnmsubs}, {1597, &ppc_fnmsubsdot}, {1598, &ppc_fnmadds}, {1599, &ppc_fnmaddsdot},
{1650, &ppc_fmults}, {1651, &ppc_fmultsdot}, {1656, &ppc_fmsubs}, {1657, &ppc_fmsubsdot},
{1658, &ppc_fmadds}, {1659, &ppc_fmaddsdot}, {1660, &ppc_fnmsubs}, {1661, &ppc_fnmsubsdot},
{1662, &ppc_fnmadds}, {1663, &ppc_fnmaddsdot}, {1714, &ppc_fmults}, {1715, &ppc_fmultsdot},
{1720, &ppc_fmsubs}, {1721, &ppc_fmsubsdot}, {1722, &ppc_fmadds}, {1723, &ppc_fmaddsdot},
{1724, &ppc_fnmsubs}, {1725, &ppc_fnmsubsdot}, {1726, &ppc_fnmadds}, {1727, &ppc_fnmaddsdot},
{1778, &ppc_fmults}, {1779, &ppc_fmultsdot}, {1784, &ppc_fmsubs}, {1785, &ppc_fmsubsdot},
{1786, &ppc_fmadds}, {1787, &ppc_fmaddsdot}, {1788, &ppc_fnmsubs}, {1789, &ppc_fnmsubsdot},
{1790, &ppc_fnmadds}, {1791, &ppc_fnmaddsdot}, {1842, &ppc_fmults}, {1843, &ppc_fmultsdot},
{1848, &ppc_fmsubs}, {1849, &ppc_fmsubsdot}, {1850, &ppc_fmadds}, {1851, &ppc_fmaddsdot},
{1852, &ppc_fnmsubs}, {1853, &ppc_fnmsubsdot}, {1854, &ppc_fnmadds}, {1855, &ppc_fnmaddsdot},
{1906, &ppc_fmults}, {1907, &ppc_fmultsdot}, {1912, &ppc_fmsubs}, {1913, &ppc_fmsubsdot},
{1914, &ppc_fmadds}, {1915, &ppc_fmaddsdot}, {1916, &ppc_fnmsubs}, {1917, &ppc_fnmsubsdot},
{1918, &ppc_fnmadds}, {1919, &ppc_fnmaddsdot}, {1970, &ppc_fmults}, {1971, &ppc_fmultsdot},
{1976, &ppc_fmsubs}, {1977, &ppc_fmsubsdot}, {1978, &ppc_fmadds}, {1979, &ppc_fmaddsdot},
{1980, &ppc_fnmsubs}, {1981, &ppc_fnmsubsdot}, {1982, &ppc_fnmadds}, {1983, &ppc_fnmaddsdot},
{2034, &ppc_fmults}, {2035, &ppc_fmultsdot}, {2040, &ppc_fmsubs}, {2041, &ppc_fmsubsdot},
{2042, &ppc_fmadds}, {2043, &ppc_fmaddsdot}, {2044, &ppc_fnmsubs}, {2045, &ppc_fnmsubsdot},
{2046, &ppc_fnmadds}, {2047, &ppc_fnmaddsdot}};
/** Double-precision floating-point instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode63Grabber = {
2020-05-12 18:55:45 +00:00
{0, &ppc_fcmpu}, {24, &ppc_frsp}, {25, &ppc_frspdot}, {28, &ppc_fctiw},
{29, &ppc_fctiwdot}, {30, &ppc_fctiwz}, {31, &ppc_fctiwzdot}, {36, &ppc_fdiv},
{37, &ppc_fdivdot}, {40, &ppc_fsub}, {41, &ppc_fsubdot}, {42, &ppc_fadd},
{43, &ppc_fadddot}, {44, &ppc_fsqrt}, {45, &ppc_fsqrtdot}, {46, &ppc_fsel},
{47, &ppc_fseldot}, {50, &ppc_fmult}, {51, &ppc_fmultdot}, {52, &ppc_frsqrte},
{53, &ppc_frsqrtedot}, {56, &ppc_fmsub}, {57, &ppc_fmsubdot}, {58, &ppc_fmadd},
{59, &ppc_fmadddot}, {60, &ppc_fnmsub}, {61, &ppc_fnmsubdot}, {62, &ppc_fnmadd},
{63, &ppc_fnmadddot}, {64, &ppc_fcmpo}, {76, &ppc_mtfsb1}, {77, &ppc_mtfsb1dot},
{80, &ppc_fneg}, {81, &ppc_fnegdot}, {110, &ppc_fsel}, {111, &ppc_fseldot},
{114, &ppc_fmult}, {115, &ppc_fmultdot}, {120, &ppc_fmsub}, {121, &ppc_fmsubdot},
{122, &ppc_fmadd}, {123, &ppc_fmadd}, {124, &ppc_fnmsub}, {125, &ppc_fnmsubdot},
{126, &ppc_fnmadd}, {127, &ppc_fnmadddot}, {128, &ppc_mcrfs}, {140, &ppc_mtfsb0},
{141, &ppc_mtfsb0dot}, {144, &ppc_fmr}, {174, &ppc_fsel}, {175, &ppc_fseldot},
{178, &ppc_fmult}, {179, &ppc_fmultdot}, {184, &ppc_fmsub}, {185, &ppc_fmsubdot},
{186, &ppc_fmadd}, {187, &ppc_fmadddot}, {188, &ppc_fnmsub}, {189, &ppc_fnmsubdot},
{190, &ppc_fnmadd}, {191, &ppc_fnmadddot}, {238, &ppc_fsel}, {239, &ppc_fseldot},
{242, &ppc_fmult}, {243, &ppc_fmultdot}, {248, &ppc_fmsub}, {249, &ppc_fmsubdot},
{250, &ppc_fmadd}, {251, &ppc_fmadddot}, {252, &ppc_fnmsub}, {253, &ppc_fnmsubdot},
{254, &ppc_fnmadd}, {255, &ppc_fnmadddot}, {268, &ppc_mtfsfi}, {272, &ppc_fnabs},
{273, &ppc_fnabsdot}, {302, &ppc_fsel}, {303, &ppc_fseldot}, {306, &ppc_fmult},
{307, &ppc_fmultdot}, {312, &ppc_fmsub}, {313, &ppc_fmsubdot}, {314, &ppc_fmadd},
{315, &ppc_fmadddot}, {316, &ppc_fnmsub}, {317, &ppc_fnmsubdot}, {318, &ppc_fnmadd},
{319, &ppc_fnmadddot}, {366, &ppc_fsel}, {367, &ppc_fseldot}, {370, &ppc_fmult},
{371, &ppc_fmultdot}, {376, &ppc_fmsub}, {377, &ppc_fmsubdot}, {378, &ppc_fmadd},
{379, &ppc_fmadddot}, {380, &ppc_fnmsub}, {381, &ppc_fnmsubdot}, {382, &ppc_fnmadd},
{383, &ppc_fnmadddot}, {430, &ppc_fsel}, {431, &ppc_fseldot}, {434, &ppc_fmult},
{435, &ppc_fmultdot}, {440, &ppc_fmsub}, {441, &ppc_fmsubdot}, {442, &ppc_fmadd},
{443, &ppc_fmadddot}, {444, &ppc_fnmsub}, {445, &ppc_fnmsubdot}, {446, &ppc_fnmadd},
{447, &ppc_fnmadddot}, {494, &ppc_fsel}, {495, &ppc_fseldot}, {498, &ppc_fmult},
{499, &ppc_fmultdot}, {504, &ppc_fmsub}, {505, &ppc_fmsubdot}, {506, &ppc_fmadd},
{507, &ppc_fmadddot}, {508, &ppc_fnmsub}, {509, &ppc_fnmsubdot}, {510, &ppc_fnmadd},
{511, &ppc_fnmadddot}, {528, &ppc_fabs}, {529, &ppc_fabsdot}, {536, &ppc_mtfsfidot},
{558, &ppc_fsel}, {559, &ppc_fseldot}, {562, &ppc_fmult}, {563, &ppc_fmultdot},
{568, &ppc_fmsub}, {569, &ppc_fmsubdot}, {570, &ppc_fmadd}, {571, &ppc_fmadddot},
{572, &ppc_fnmsub}, {573, &ppc_fnmsubdot}, {574, &ppc_fnmadd}, {575, &ppc_fnmadddot},
{622, &ppc_fsel}, {623, &ppc_fseldot}, {626, &ppc_fmult}, {627, &ppc_fmultdot},
{632, &ppc_fmsub}, {633, &ppc_fmsubdot}, {634, &ppc_fmadd}, {635, &ppc_fmadddot},
{636, &ppc_fnmsub}, {637, &ppc_fnmsubdot}, {638, &ppc_fnmadd}, {639, &ppc_fnmadddot},
{686, &ppc_fsel}, {687, &ppc_fseldot}, {690, &ppc_fmult}, {691, &ppc_fmultdot},
{696, &ppc_fmsub}, {697, &ppc_fmsubdot}, {698, &ppc_fmadd}, {699, &ppc_fmadddot},
{700, &ppc_fnmsub}, {701, &ppc_fnmsubdot}, {702, &ppc_fnmadd}, {703, &ppc_fnmadddot},
{750, &ppc_fsel}, {751, &ppc_fseldot}, {754, &ppc_fmult}, {755, &ppc_fmultdot},
{760, &ppc_fmsub}, {761, &ppc_fmsubdot}, {762, &ppc_fmadd}, {763, &ppc_fmadddot},
{764, &ppc_fnmsub}, {765, &ppc_fnmsubdot}, {766, &ppc_fnmadd}, {767, &ppc_fnmadddot},
{814, &ppc_fsel}, {815, &ppc_fseldot}, {818, &ppc_fmult}, {819, &ppc_fmultdot},
{824, &ppc_fmsub}, {825, &ppc_fmsubdot}, {826, &ppc_fmadd}, {827, &ppc_fmadddot},
{828, &ppc_fnmsub}, {829, &ppc_fnmsubdot}, {830, &ppc_fnmadd}, {831, &ppc_fnmadddot},
{878, &ppc_fsel}, {879, &ppc_fseldot}, {882, &ppc_fmult}, {883, &ppc_fmultdot},
{888, &ppc_fmsub}, {889, &ppc_fmsubdot}, {890, &ppc_fmadd}, {891, &ppc_fmadddot},
{892, &ppc_fnmsub}, {893, &ppc_fnmsubdot}, {894, &ppc_fnmadd}, {895, &ppc_fnmadddot},
{942, &ppc_fsel}, {943, &ppc_fseldot}, {946, &ppc_fmult}, {947, &ppc_fmultdot},
{952, &ppc_fmsub}, {953, &ppc_fmsubdot}, {954, &ppc_fmadd}, {955, &ppc_fmadddot},
{957, &ppc_fnmsub}, {958, &ppc_fnmsubdot}, {958, &ppc_fnmadd}, {959, &ppc_fnmadddot},
{1006, &ppc_fsel}, {1007, &ppc_fseldot}, {1010, &ppc_fmult}, {1011, &ppc_fmultdot},
{1016, &ppc_fmsub}, {1017, &ppc_fmsubdot}, {1018, &ppc_fmadd}, {1019, &ppc_fmadddot},
{1020, &ppc_fnmsub}, {1021, &ppc_fnmsubdot}, {1022, &ppc_fnmadd}, {1023, &ppc_fnmadddot},
{1070, &ppc_fsel}, {1071, &ppc_fseldot}, {1074, &ppc_fmult}, {1075, &ppc_fmultdot},
{1080, &ppc_fmsub}, {1081, &ppc_fmsubdot}, {1082, &ppc_fmadd}, {1083, &ppc_fmadddot},
{1084, &ppc_fnmsub}, {1085, &ppc_fnmsubdot}, {1086, &ppc_fnmadd}, {1087, &ppc_fnmadddot},
{1134, &ppc_fsel}, {1135, &ppc_fseldot}, {1138, &ppc_fmult}, {1139, &ppc_fmultdot},
{1144, &ppc_fmsub}, {1145, &ppc_fmsubdot}, {1146, &ppc_fmadd}, {1147, &ppc_fmadddot},
{1148, &ppc_fnmsub}, {1149, &ppc_fnmsubdot}, {1150, &ppc_fnmadd}, {1151, &ppc_fnmadddot},
{1166, &ppc_mffs}, {1167, &ppc_mffsdot}, {1198, &ppc_fsel}, {1199, &ppc_fseldot},
{1202, &ppc_fmult}, {1203, &ppc_fmultdot}, {1208, &ppc_fmsub}, {1209, &ppc_fmsubdot},
{1210, &ppc_fmadd}, {1211, &ppc_fmadddot}, {1212, &ppc_fnmsub}, {1213, &ppc_fnmsubdot},
{1214, &ppc_fnmadd}, {1215, &ppc_fnmadddot}, {1262, &ppc_fsel}, {1263, &ppc_fseldot},
{1266, &ppc_fmult}, {1267, &ppc_fmultdot}, {1272, &ppc_fmsub}, {1273, &ppc_fmsubdot},
{1274, &ppc_fmadd}, {1275, &ppc_fmadddot}, {1276, &ppc_fnmsub}, {1277, &ppc_fnmsubdot},
{1278, &ppc_fnmadd}, {1279, &ppc_fnmadddot}, {1326, &ppc_fsel}, {1327, &ppc_fseldot},
{1330, &ppc_fmult}, {1331, &ppc_fmultdot}, {1336, &ppc_fmsub}, {1337, &ppc_fmsubdot},
{1338, &ppc_fmadd}, {1339, &ppc_fmadddot}, {1340, &ppc_fnmsub}, {1341, &ppc_fnmsubdot},
{1342, &ppc_fnmadd}, {1343, &ppc_fnmadddot}, {1390, &ppc_fsel}, {1391, &ppc_fseldot},
{1394, &ppc_fmult}, {1395, &ppc_fmultdot}, {1400, &ppc_fmsub}, {1401, &ppc_fmsubdot},
{1402, &ppc_fmadd}, {1403, &ppc_fmadddot}, {1404, &ppc_fnmsub}, {1405, &ppc_fnmsubdot},
{1406, &ppc_fnmadd}, {1407, &ppc_fnmadddot}, {1422, &ppc_mtfsf}, {1423, &ppc_mtfsfdot},
{1454, &ppc_fsel}, {1455, &ppc_fseldot}, {1458, &ppc_fmult}, {1459, &ppc_fmultdot},
{1464, &ppc_fmsub}, {1465, &ppc_fmsubdot}, {1466, &ppc_fmadd}, {1467, &ppc_fmadddot},
{1468, &ppc_fnmsub}, {1469, &ppc_fnmsubdot}, {1470, &ppc_fnmadd}, {1471, &ppc_fnmadddot},
{1518, &ppc_fsel}, {1519, &ppc_fseldot}, {1522, &ppc_fmult}, {1523, &ppc_fmultdot},
{1528, &ppc_fmsub}, {1529, &ppc_fmsubdot}, {1530, &ppc_fmadd}, {1531, &ppc_fmadddot},
{1532, &ppc_fnmsub}, {1533, &ppc_fnmsubdot}, {1534, &ppc_fnmadd}, {1535, &ppc_fnmadddot},
{1582, &ppc_fsel}, {1583, &ppc_fseldot}, {1586, &ppc_fmult}, {1587, &ppc_fmultdot},
{1592, &ppc_fmsub}, {1593, &ppc_fmsubdot}, {1594, &ppc_fmadd}, {1595, &ppc_fmadddot},
{1596, &ppc_fnmsub}, {1597, &ppc_fnmsubdot}, {1598, &ppc_fnmadd}, {1599, &ppc_fnmadddot},
{1646, &ppc_fsel}, {1647, &ppc_fseldot}, {1650, &ppc_fmult}, {1651, &ppc_fmultdot},
{1656, &ppc_fmsub}, {1657, &ppc_fmsubdot}, {1658, &ppc_fmadd}, {1659, &ppc_fmadddot},
{1660, &ppc_fnmsub}, {1661, &ppc_fnmsubdot}, {1662, &ppc_fnmadd}, {1663, &ppc_fnmadddot},
{1710, &ppc_fsel}, {1711, &ppc_fseldot}, {1714, &ppc_fmult}, {1715, &ppc_fmultdot},
{1720, &ppc_fmsub}, {1721, &ppc_fmsubdot}, {1722, &ppc_fmadd}, {1723, &ppc_fmadddot},
{1724, &ppc_fnmsub}, {1725, &ppc_fnmsubdot}, {1726, &ppc_fnmadd}, {1727, &ppc_fnmadddot},
{1774, &ppc_fsel}, {1775, &ppc_fseldot}, {1778, &ppc_fmult}, {1779, &ppc_fmultdot},
{1784, &ppc_fmsub}, {1785, &ppc_fmsubdot}, {1786, &ppc_fmadd}, {1787, &ppc_fmadddot},
{1788, &ppc_fnmsub}, {1789, &ppc_fnmsubdot}, {1790, &ppc_fnmadd}, {1791, &ppc_fnmadddot},
{1838, &ppc_fsel}, {1839, &ppc_fseldot}, {1842, &ppc_fmult}, {1843, &ppc_fmultdot},
{1848, &ppc_fmsub}, {1849, &ppc_fmsubdot}, {1850, &ppc_fmadd}, {1851, &ppc_fmadddot},
{1852, &ppc_fnmsub}, {1853, &ppc_fnmsubdot}, {1854, &ppc_fnmadd}, {1855, &ppc_fnmadddot},
{1902, &ppc_fsel}, {1903, &ppc_fseldot}, {1906, &ppc_fmult}, {1907, &ppc_fmultdot},
{1912, &ppc_fmsub}, {1913, &ppc_fmsubdot}, {1914, &ppc_fmadd}, {1915, &ppc_fmadddot},
{1916, &ppc_fnmsub}, {1917, &ppc_fnmsubdot}, {1918, &ppc_fnmadd}, {1919, &ppc_fnmadddot},
{1966, &ppc_fsel}, {1967, &ppc_fseldot}, {1970, &ppc_fmult}, {1971, &ppc_fmultdot},
{1976, &ppc_fmsub}, {1977, &ppc_fmsubdot}, {1978, &ppc_fmadd}, {1979, &ppc_fmadddot},
{1980, &ppc_fnmsub}, {1981, &ppc_fnmsubdot}, {1982, &ppc_fnmadd}, {1983, &ppc_fnmadddot},
{2030, &ppc_fsel}, {2031, &ppc_fseldot}, {2034, &ppc_fmult}, {2035, &ppc_fmultdot},
{2040, &ppc_fmsub}, {2041, &ppc_fmsubdot}, {2042, &ppc_fmadd}, {2043, &ppc_fmadddot},
{2044, &ppc_fnmsub}, {2045, &ppc_fnmsubdot}, {2046, &ppc_fnmadd}, {2047, &ppc_fnmadddot}};
2020-05-31 22:46:00 +00:00
#define UPDATE_TBR_DEC \
if ((delta = (cycles_count - old_cycles_count) >> tbr_factor)) { \
timebase_counter += delta; \
decr -= delta; \
if ((decr & 0x80000000) && !old_decr_msb) { \
old_decr_msb = decr >> 31; \
/* signal_decr_int(); */ \
} \
old_cycles_count += delta << tbr_factor; \
}
/** Opcode decoding functions. */
void ppc_illegalop() {
2020-06-03 13:33:32 +00:00
LOG_F(ERROR, "Illegal opcode reported: 0x%X Report this! \n", ppc_cur_instruction);
exit(-1);
}
void ppc_opcode4() {
2020-02-24 14:54:29 +00:00
LOG_F(INFO, "Reading from Opcode 4 table \n");
uint8_t subop_grab = ppc_cur_instruction & 3;
uint32_t regrab = (uint32_t)subop_grab;
2020-02-24 14:54:29 +00:00
LOG_F(ERROR, "Executing subopcode entry %d \n"
".. or would if I bothered to implement it. SORRY!", regrab);
2020-06-03 13:33:32 +00:00
exit(-1);
}
void ppc_opcode16() {
SubOpcode16Grabber[ppc_cur_instruction & 3]();
}
void ppc_opcode18() {
SubOpcode18Grabber[ppc_cur_instruction & 3]();
}
void ppc_opcode19() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
2020-02-25 02:50:52 +00:00
LOG_F(INFO, "Executing Opcode 19 table subopcode entry \n", regrab);
if (SubOpcode19Grabber.count(subop_grab) == 1) {
SubOpcode19Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
} else {
2020-02-25 02:50:52 +00:00
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode19Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
#endif // EXHAUSTIVE_DEBUG
}
void ppc_opcode31() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
2020-02-25 02:50:52 +00:00
LOG_F(INFO, "Executing Opcode 31 table subopcode entry \n", regrab);
if (SubOpcode31Grabber.count(subop_grab) == 1) {
SubOpcode31Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
} else {
2020-02-25 02:50:52 +00:00
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode31Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
#endif // EXHAUSTIVE_DEBUG
}
void ppc_opcode59() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
2020-02-25 02:50:52 +00:00
LOG_F(INFO, "Executing Opcode 59 table subopcode entry \n", regrab);
if (SubOpcode59Grabber.count(subop_grab) == 1) {
SubOpcode59Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
} else {
2020-02-25 02:50:52 +00:00
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode59Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
#endif // EXHAUSTIVE_DEBUG
}
void ppc_opcode63() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
2020-02-25 02:50:52 +00:00
LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab);
if (SubOpcode63Grabber.count(subop_grab) == 1) {
SubOpcode63Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
} else {
2020-02-25 02:50:52 +00:00
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode63Grabber[subop_grab]();
2020-05-12 18:55:45 +00:00
#endif // EXHAUSTIVE_DEBUG
}
2020-06-03 13:33:32 +00:00
/* Dispatch using main opcode */
void ppc_main_opcode()
{
OpcodeGrabber[(ppc_cur_instruction >> 26) & 0x3F]();
}
/** Execute PPC code as long as power is on. */
void ppc_exec()
{
2020-05-31 22:46:00 +00:00
uint32_t bb_start_la, page_start, delta;
uint8_t* pc_real;
/* start new basic block */
glob_bb_start_la = bb_start_la = ppc_state.pc;
bb_kind = BB_end_kind::BB_NONE;
if (setjmp(exc_env)) {
/* reaching here means we got a low-level exception */
2020-05-31 22:46:00 +00:00
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
2020-05-31 22:46:00 +00:00
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
2020-05-31 22:46:00 +00:00
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
pc_real = quickinstruction_translate(bb_start_la);
page_start = bb_start_la & 0xFFFFF000;
2020-03-05 14:48:10 +00:00
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
goto again;
}
/* initial MMU translation for the current code page. */
pc_real = quickinstruction_translate(bb_start_la);
/* set current code page limits */
page_start = bb_start_la & 0xFFFFF000;
again:
while (power_on) {
ppc_main_opcode();
if (bb_kind != BB_end_kind::BB_NONE) {
2020-05-31 22:46:00 +00:00
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - bb_start_la) >> 2) + 1;
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - bb_start_la) >> 2) + 1;
2020-05-31 22:46:00 +00:00
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
page_start = bb_start_la & 0xFFFFF000;
pc_real = quickinstruction_translate(bb_start_la);
2020-05-12 18:55:45 +00:00
} else {
2020-03-05 14:48:10 +00:00
pc_real += (int)bb_start_la - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
}
2020-03-05 14:48:10 +00:00
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
2020-05-12 18:55:45 +00:00
} else {
2020-03-05 14:48:10 +00:00
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
}
}
}
/** Execute one PPC instruction. */
void ppc_exec_single()
{
2020-05-31 22:46:00 +00:00
uint32_t delta;
if (setjmp(exc_env)) {
/* reaching here means we got a low-level exception */
2020-05-31 22:46:00 +00:00
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count++;
UPDATE_TBR_DEC
#else
timebase_counter++;
#endif
2020-03-05 14:48:10 +00:00
ppc_state.pc = ppc_next_instruction_address;
bb_kind = BB_end_kind::BB_NONE;
return;
}
2020-03-05 14:48:10 +00:00
quickinstruction_translate(ppc_state.pc);
ppc_main_opcode();
if (bb_kind != BB_end_kind::BB_NONE) {
2020-03-05 14:48:10 +00:00
ppc_state.pc = ppc_next_instruction_address;
bb_kind = BB_end_kind::BB_NONE;
2020-05-12 18:55:45 +00:00
} else {
2020-03-05 14:48:10 +00:00
ppc_state.pc += 4;
}
2020-05-31 22:46:00 +00:00
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count++;
UPDATE_TBR_DEC
#else
timebase_counter++;
#endif
2020-05-31 22:46:00 +00:00
}
/** Execute PPC code until goal_addr is reached. */
void ppc_exec_until(uint32_t goal_addr)
{
2020-05-31 22:46:00 +00:00
uint32_t bb_start_la, page_start, delta;
uint8_t* pc_real;
/* start new basic block */
glob_bb_start_la = bb_start_la = ppc_state.pc;
bb_kind = BB_end_kind::BB_NONE;
if (setjmp(exc_env)) {
/* reaching here means we got a low-level exception */
2020-05-31 22:46:00 +00:00
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
2020-05-31 22:46:00 +00:00
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
2020-05-31 22:46:00 +00:00
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
pc_real = quickinstruction_translate(bb_start_la);
page_start = bb_start_la & 0xFFFFF000;
2020-03-05 14:48:10 +00:00
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
goto again;
}
/* initial MMU translation for the current code page. */
pc_real = quickinstruction_translate(bb_start_la);
/* set current code page limits */
page_start = bb_start_la & 0xFFFFF000;
again:
2020-03-05 14:48:10 +00:00
while (ppc_state.pc != goal_addr) {
ppc_main_opcode();
if (bb_kind != BB_end_kind::BB_NONE) {
2020-05-31 22:46:00 +00:00
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - bb_start_la) >> 2) + 1;
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - bb_start_la) >> 2) + 1;
2020-05-31 22:46:00 +00:00
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
page_start = bb_start_la & 0xFFFFF000;
pc_real = quickinstruction_translate(bb_start_la);
2020-05-12 18:55:45 +00:00
} else {
2020-03-05 14:48:10 +00:00
pc_real += (int)bb_start_la - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
}
2020-03-05 14:48:10 +00:00
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
2020-05-12 18:55:45 +00:00
} else {
2020-03-05 14:48:10 +00:00
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
}
}
}
2020-05-31 22:46:00 +00:00
/** Execute PPC code until control is reached the specified region. */
void ppc_exec_dbg(uint32_t start_addr, uint32_t size)
{
uint32_t bb_start_la, page_start, delta;
uint8_t* pc_real;
/* start new basic block */
glob_bb_start_la = bb_start_la = ppc_state.pc;
bb_kind = BB_end_kind::BB_NONE;
if (setjmp(exc_env)) {
/* reaching here means we got a low-level exception */
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
pc_real = quickinstruction_translate(bb_start_la);
page_start = bb_start_la & 0xFFFFF000;
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
goto again;
}
/* initial MMU translation for the current code page. */
pc_real = quickinstruction_translate(bb_start_la);
/* set current code page limits */
page_start = bb_start_la & 0xFFFFF000;
again:
while (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size) {
ppc_main_opcode();
if (bb_kind != BB_end_kind::BB_NONE) {
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - bb_start_la) >> 2) + 1;
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - bb_start_la) >> 2) + 1;
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
page_start = bb_start_la & 0xFFFFF000;
pc_real = quickinstruction_translate(bb_start_la);
} else {
pc_real += (int)bb_start_la - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
}
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
} else {
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
}
}
}
2020-05-31 22:46:00 +00:00
uint64_t instr_count, old_instr_count;
void test_timebase_update()
{
uint32_t delta, factor;
uint8_t old_decr_msb;
uint8_t intervals[10] = {4, 7, 10, 2, 16, 6, 3, 20, 12, 8};
timebase_counter = 0;
decr = 0x00000003;
old_decr_msb = decr >> 31;
old_instr_count = 0xFFFFFFFFFFFFFF80UL;//0xFFFFFFFFFFFFFFD0UL;
instr_count = 0xFFFFFFFFFFFFFF80UL;//0xFFFFFFFFFFFFFFD0UL;
factor = 4;
for (int i = 0; i < 10; i++) {
cycles_count += intervals[i];
if ((delta = (cycles_count - old_cycles_count) >> factor)) {
timebase_counter += delta;
decr -= delta;
if ((decr & 0x80000000) && !old_decr_msb) {
old_decr_msb = decr >> 31;
LOG_F(ERROR, "DEC exception signaled!\n");
}
old_instr_count += delta << factor;
LOG_F(INFO, "Iteration %d, TBR=0x%llX, DEC=0x%X", i, timebase_counter, decr);
LOG_F(INFO, " icount=0x%llX, old_icount=0x%llX\n", cycles_count, old_cycles_count);
}
}
}
2020-05-12 18:55:45 +00:00
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version) {
int i;
mem_ctrl_instance = mem_ctrl;
2020-05-31 22:46:00 +00:00
//test_timebase_update();
/* initialize timer variables */
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count = 0;
old_cycles_count = 0;
tbr_factor = 4;
#endif
timebase_counter = 0;
2020-05-31 22:46:00 +00:00
decr = 0;
old_decr_msb = decr >> 31;
/* zero all GPRs as prescribed for MPC601 */
/* For later PPC CPUs, GPR content is undefined */
for (i = 0; i < 32; i++) {
ppc_state.gpr[i] = 0;
}
/* zero all FPRs as prescribed for MPC601 */
/* For later PPC CPUs, GPR content is undefined */
for (i = 0; i < 32; i++) {
ppc_state.fpr[i].int64_r = 0;
}
/* zero all segment registers as prescribed for MPC601 */
/* For later PPC CPUs, SR content is undefined */
for (i = 0; i < 16; i++) {
ppc_state.sr[i] = 0;
}
2020-05-12 18:55:45 +00:00
ppc_state.cr = 0;
ppc_state.fpscr = 0;
2020-03-05 14:48:10 +00:00
ppc_state.pc = 0;
ppc_state.tbr[0] = 0;
ppc_state.tbr[1] = 0;
/* zero all SPRs */
for (i = 0; i < 1024; i++) {
ppc_state.spr[i] = 0;
}
ppc_state.spr[SPR::PVR] = proc_version;
if ((proc_version & 0xFFFF0000) == 0x00010000) {
/* MPC601 sets MSR[ME] bit during hard reset / Power-On */
ppc_state.msr = 0x1040;
} else {
2020-05-12 18:55:45 +00:00
ppc_state.msr = 0x40;
ppc_state.spr[SPR::DEC] = 0xFFFFFFFFUL;
}
ppc_mmu_init();
/* redirect code execution to reset vector */
2020-03-05 14:48:10 +00:00
ppc_state.pc = 0xFFF00100;
}
2020-05-12 18:55:45 +00:00
void print_gprs() {
for (int i = 0; i < 32; i++)
2020-05-12 18:55:45 +00:00
cout << "GPR " << dec << i << " : " << uppercase << hex << ppc_state.gpr[i] << endl;
2020-03-05 14:48:10 +00:00
cout << "PC: " << uppercase << hex << ppc_state.pc << endl;
cout << "LR: " << uppercase << hex << ppc_state.spr[SPR::LR] << endl;
cout << "CR: " << uppercase << hex << ppc_state.cr << endl;
cout << "CTR: " << uppercase << hex << ppc_state.spr[SPR::CTR] << endl;
cout << "XER: " << uppercase << hex << ppc_state.spr[SPR::XER] << endl;
cout << "MSR: " << uppercase << hex << ppc_state.msr << endl;
}
2020-05-12 18:55:45 +00:00
void print_fprs() {
for (int i = 0; i < 32; i++)
cout << "FPR " << dec << i << " : " << ppc_state.fpr[i].dbl64_r << endl;
}
static map<string, int> SPRName2Num = {
2020-05-12 18:55:45 +00:00
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR}, {"DEC", SPR::DEC}, {"PVR", SPR::PVR}};
2020-05-12 18:55:45 +00:00
uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
string reg_name_u, reg_num_str;
unsigned reg_num;
map<string, int>::iterator spr;
if (reg_name.length() < 2)
goto bail_out;
reg_name_u = reg_name;
/* convert reg_name string to uppercase */
2020-05-12 18:55:45 +00:00
std::for_each(reg_name_u.begin(), reg_name_u.end(), [](char& c) { c = ::toupper(c); });
try {
if (reg_name_u == "PC") {
if (is_write)
2020-03-05 14:48:10 +00:00
ppc_state.pc = val;
return ppc_state.pc;
}
if (reg_name_u == "MSR") {
if (is_write)
ppc_state.msr = val;
return ppc_state.msr;
}
if (reg_name_u == "CR") {
if (is_write)
ppc_state.cr = val;
return ppc_state.cr;
}
if (reg_name_u == "FPSCR") {
if (is_write)
ppc_state.fpscr = val;
return ppc_state.fpscr;
}
if (reg_name_u.substr(0, 1) == "R") {
reg_num_str = reg_name_u.substr(1);
2020-05-12 18:55:45 +00:00
reg_num = stoul(reg_num_str, NULL, 0);
if (reg_num < 32) {
if (is_write)
ppc_state.gpr[reg_num] = val;
return ppc_state.gpr[reg_num];
}
}
if (reg_name_u.substr(0, 1) == "FR") {
reg_num_str = reg_name_u.substr(2);
2020-05-12 18:55:45 +00:00
reg_num = stoul(reg_num_str, NULL, 0);
if (reg_num < 32) {
if (is_write)
ppc_state.fpr[reg_num].int64_r = val;
return ppc_state.fpr[reg_num].int64_r;
}
}
if (reg_name_u.substr(0, 3) == "SPR") {
reg_num_str = reg_name_u.substr(3);
2020-05-12 18:55:45 +00:00
reg_num = stoul(reg_num_str, NULL, 0);
if (reg_num < 1024) {
if (is_write)
ppc_state.spr[reg_num] = val;
return ppc_state.spr[reg_num];
}
}
if (reg_name_u.substr(0, 2) == "SR") {
reg_num_str = reg_name_u.substr(2);
2020-05-12 18:55:45 +00:00
reg_num = stoul(reg_num_str, NULL, 0);
if (reg_num < 16) {
if (is_write)
ppc_state.sr[reg_num] = val;
return ppc_state.sr[reg_num];
}
}
spr = SPRName2Num.find(reg_name_u);
if (spr != SPRName2Num.end()) {
if (is_write)
ppc_state.spr[spr->second] = val;
return ppc_state.spr[spr->second];
}
2020-05-12 18:55:45 +00:00
} catch (...) {
}
bail_out:
throw std::invalid_argument(string("Unknown register ") + reg_name);
}
2020-05-12 18:55:45 +00:00
uint64_t get_reg(string& reg_name) {
return reg_op(reg_name, 0, false);
}
2020-05-12 18:55:45 +00:00
void set_reg(string& reg_name, uint64_t val) {
reg_op(reg_name, val, true);
}