trunk/src/emu/cpu/powerpc/ppcdrc.c
| r31142 | r31143 | |
| 16 | 16 | |
| 17 | 17 | #include "emu.h" |
| 18 | 18 | #include "debugger.h" |
| 19 | #include "ppc.h" |
| 19 | 20 | #include "ppccom.h" |
| 20 | 21 | #include "ppcfe.h" |
| 21 | 22 | #include "cpu/drcfe.h" |
| r31142 | r31143 | |
| 29 | 30 | |
| 30 | 31 | |
| 31 | 32 | /*************************************************************************** |
| 32 | | DEBUGGING |
| 33 | | ***************************************************************************/ |
| 34 | | |
| 35 | | #define LOG_UML (0) |
| 36 | | #define LOG_NATIVE (0) |
| 37 | | |
| 38 | | #define DISABLE_FLAG_OPTIMIZATIONS (0) |
| 39 | | #define DISABLE_FAST_REGISTERS (0) |
| 40 | | #define SINGLE_INSTRUCTION_MODE (0) |
| 41 | | |
| 42 | | #define PRINTF_EXCEPTIONS (0) |
| 43 | | #define PRINTF_MMU (0) |
| 44 | | |
| 45 | | #define PROBE_ADDRESS ~0 |
| 46 | | |
| 47 | | |
| 48 | | |
| 49 | | /*************************************************************************** |
| 50 | 33 | CONSTANTS |
| 51 | 34 | ***************************************************************************/ |
| 52 | 35 | |
| r31142 | r31143 | |
| 61 | 44 | #define MODE_PROTECTION 0x02 /* 4XX */ |
| 62 | 45 | #define MODE_USER 0x04 |
| 63 | 46 | |
| 64 | | /* size of the execution code cache */ |
| 65 | | #define CACHE_SIZE (32 * 1024 * 1024) |
| 66 | | |
| 67 | | /* compilation boundaries -- how far back/forward does the analysis extend? */ |
| 68 | | #define COMPILE_BACKWARDS_BYTES 128 |
| 69 | | #define COMPILE_FORWARDS_BYTES 512 |
| 70 | | #define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) |
| 71 | | #define COMPILE_MAX_SEQUENCE 64 |
| 72 | | |
| 73 | 47 | /* exit codes */ |
| 74 | 48 | #define EXECUTE_OUT_OF_CYCLES 0 |
| 75 | 49 | #define EXECUTE_MISSING_CODE 1 |
| r31142 | r31143 | |
| 82 | 56 | MACROS |
| 83 | 57 | ***************************************************************************/ |
| 84 | 58 | |
| 85 | | #define R32(reg) ppc->impstate->regmap[reg] |
| 86 | | #define R32Z(reg) (((reg) == 0) ? parameter(0) : ppc->impstate->regmap[reg]) |
| 87 | | #define F64(reg) ppc->impstate->fdregmap[reg] |
| 88 | | #define CR32(reg) mem(&ppc->cr[reg]) |
| 89 | | #define FPSCR32 mem(&ppc->fpscr) |
| 90 | | #define MSR32 mem(&ppc->msr) |
| 91 | | #define XERSO32 mem(&ppc->xerso) |
| 92 | | #define SR32(reg) mem(&ppc->sr[reg]) |
| 93 | | #define SPR32(reg) mem(&ppc->spr[reg]) |
| 59 | #define R32(reg) m_regmap[reg] |
| 60 | #define R32Z(reg) (((reg) == 0) ? parameter(0) : m_regmap[reg]) |
| 61 | #define F64(reg) m_fdregmap[reg] |
| 62 | #define CR32(reg) mem(&m_core->cr[reg]) |
| 63 | #define FPSCR32 mem(&m_core->fpscr) |
| 64 | #define MSR32 mem(&m_core->msr) |
| 65 | #define XERSO32 mem(&m_core->xerso) |
| 66 | #define SR32(reg) mem(&m_core->sr[reg]) |
| 67 | #define SPR32(reg) mem(&m_core->spr[reg]) |
| 94 | 68 | |
| 95 | 69 | #define CRMASK(reg) (0xf0000000 >> ((reg) * 4)) |
| 96 | 70 | |
| r31142 | r31143 | |
| 122 | 96 | |
| 123 | 97 | |
| 124 | 98 | /*************************************************************************** |
| 125 | | STRUCTURES & TYPEDEFS |
| 126 | | ***************************************************************************/ |
| 127 | | |
| 128 | | /* fast RAM info */ |
| 129 | | struct fast_ram_info |
| 130 | | { |
| 131 | | offs_t start; /* start of the RAM block */ |
| 132 | | offs_t end; /* end of the RAM block */ |
| 133 | | UINT8 readonly; /* TRUE if read-only */ |
| 134 | | void * base; /* base in memory where the RAM lives */ |
| 135 | | }; |
| 136 | | |
| 137 | | |
| 138 | | /* hotspot info */ |
| 139 | | struct hotspot_info |
| 140 | | { |
| 141 | | offs_t pc; /* PC to consider */ |
| 142 | | UINT32 opcode; /* required opcode at that PC */ |
| 143 | | UINT32 cycles; /* number of cycles to eat when hit */ |
| 144 | | }; |
| 145 | | |
| 146 | | |
| 147 | | /* internal compiler state */ |
| 148 | | struct compiler_state |
| 149 | | { |
| 150 | | UINT32 cycles; /* accumulated cycles */ |
| 151 | | UINT8 checkints; /* need to check interrupts before next instruction */ |
| 152 | | UINT8 checksoftints; /* need to check software interrupts before next instruction */ |
| 153 | | code_label labelnum; /* index for local labels */ |
| 154 | | }; |
| 155 | | |
| 156 | | |
| 157 | | /* PowerPC implementation state */ |
| 158 | | struct ppcimp_state |
| 159 | | { |
| 160 | | /* core state */ |
| 161 | | drc_cache * cache; /* pointer to the DRC code cache */ |
| 162 | | drcuml_state * drcuml; /* DRC UML generator state */ |
| 163 | | ppc_frontend * drcfe; /* pointer to the DRC front-end state */ |
| 164 | | UINT32 drcoptions; /* configurable DRC options */ |
| 165 | | |
| 166 | | /* parameters for subroutines */ |
| 167 | | UINT32 mode; /* current global mode */ |
| 168 | | const char * format; /* format string for printing */ |
| 169 | | UINT32 arg0; /* print_debug argument 1 */ |
| 170 | | UINT32 arg1; /* print_debug argument 2 */ |
| 171 | | UINT32 updateaddr; /* update address storage */ |
| 172 | | UINT32 swcount; /* counter for sw instructions */ |
| 173 | | UINT32 tempaddr; /* temporary address storage */ |
| 174 | | drcuml_ireg tempdata; /* temporary data storage */ |
| 175 | | double fp0; /* floating point 0 */ |
| 176 | | |
| 177 | | /* tables */ |
| 178 | | UINT8 fpmode[4]; /* FPU mode table */ |
| 179 | | UINT8 sz_cr_table[32]; /* SZ CR table */ |
| 180 | | UINT8 cmp_cr_table[32]; /* CMP CR table */ |
| 181 | | UINT8 cmpl_cr_table[32]; /* CMPL CR table */ |
| 182 | | UINT8 fcmp_cr_table[32]; /* FCMP CR table */ |
| 183 | | |
| 184 | | /* internal stuff */ |
| 185 | | UINT8 cache_dirty; /* true if we need to flush the cache */ |
| 186 | | |
| 187 | | /* register mappings */ |
| 188 | | parameter regmap[32]; /* parameter to register mappings for all 32 integer registers */ |
| 189 | | parameter fdregmap[32]; /* parameter to register mappings for all 32 floating point registers */ |
| 190 | | |
| 191 | | /* subroutines */ |
| 192 | | code_handle * entry; /* entry point */ |
| 193 | | code_handle * nocode; /* nocode exception handler */ |
| 194 | | code_handle * out_of_cycles; /* out of cycles exception handler */ |
| 195 | | code_handle * tlb_mismatch; /* tlb mismatch handler */ |
| 196 | | code_handle * swap_tgpr; /* swap TGPR handler */ |
| 197 | | code_handle * lsw[8][32]; /* lsw entries */ |
| 198 | | code_handle * stsw[8][32]; /* stsw entries */ |
| 199 | | code_handle * read8[8]; /* read byte */ |
| 200 | | code_handle * write8[8]; /* write byte */ |
| 201 | | code_handle * read16[8]; /* read half */ |
| 202 | | code_handle * read16mask[8]; /* read half */ |
| 203 | | code_handle * write16[8]; /* write half */ |
| 204 | | code_handle * write16mask[8]; /* write half */ |
| 205 | | code_handle * read32[8]; /* read word */ |
| 206 | | code_handle * read32align[8]; /* read word aligned */ |
| 207 | | code_handle * read32mask[8]; /* read word */ |
| 208 | | code_handle * write32[8]; /* write word */ |
| 209 | | code_handle * write32align[8]; /* write word aligned */ |
| 210 | | code_handle * write32mask[8]; /* write word */ |
| 211 | | code_handle * read64[8]; /* read double */ |
| 212 | | code_handle * read64mask[8]; /* read double */ |
| 213 | | code_handle * write64[8]; /* write double */ |
| 214 | | code_handle * write64mask[8]; /* write double */ |
| 215 | | code_handle * exception[EXCEPTION_COUNT]; /* array of exception handlers */ |
| 216 | | code_handle * exception_norecover[EXCEPTION_COUNT]; /* array of exception handlers */ |
| 217 | | |
| 218 | | /* fast RAM */ |
| 219 | | UINT32 fastram_select; |
| 220 | | fast_ram_info fastram[PPC_MAX_FASTRAM]; |
| 221 | | |
| 222 | | /* hotspots */ |
| 223 | | UINT32 hotspot_select; |
| 224 | | hotspot_info hotspot[PPC_MAX_HOTSPOTS]; |
| 225 | | }; |
| 226 | | |
| 227 | | |
| 228 | | |
| 229 | | /*************************************************************************** |
| 230 | | FUNCTION PROTOTYPES |
| 231 | | ***************************************************************************/ |
| 232 | | |
| 233 | | static void code_flush_cache(powerpc_state *ppc); |
| 234 | | static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc); |
| 235 | | |
| 236 | | static void cfunc_printf_exception(void *param); |
| 237 | | static void cfunc_printf_probe(void *param); |
| 238 | | |
| 239 | | static void static_generate_entry_point(powerpc_state *ppc); |
| 240 | | static void static_generate_nocode_handler(powerpc_state *ppc); |
| 241 | | static void static_generate_out_of_cycles(powerpc_state *ppc); |
| 242 | | static void static_generate_tlb_mismatch(powerpc_state *ppc); |
| 243 | | static void static_generate_exception(powerpc_state *ppc, UINT8 exception, int recover, const char *name); |
| 244 | | static void static_generate_memory_accessor(powerpc_state *ppc, int mode, int size, int iswrite, int ismasked, const char *name, code_handle *&handleptr, code_handle *masked); |
| 245 | | static void static_generate_swap_tgpr(powerpc_state *ppc); |
| 246 | | static void static_generate_lsw_entries(powerpc_state *ppc, int mode); |
| 247 | | static void static_generate_stsw_entries(powerpc_state *ppc, int mode); |
| 248 | | |
| 249 | | static void generate_update_mode(powerpc_state *ppc, drcuml_block *block); |
| 250 | | static void generate_update_cycles(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, parameter, int allow_exception); |
| 251 | | static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); |
| 252 | | static void generate_sequence_instruction(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 253 | | static int generate_opcode(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 254 | | static int generate_instruction_13(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 255 | | static int generate_instruction_1f(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 256 | | static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 257 | | static int generate_instruction_3f(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 258 | | |
| 259 | | static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op); |
| 260 | | static const char *log_desc_flags_to_string(UINT32 flags); |
| 261 | | static void log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist); |
| 262 | | static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent); |
| 263 | | |
| 264 | | |
| 265 | | |
| 266 | | /*************************************************************************** |
| 267 | | PRIVATE GLOBAL VARIABLES |
| 268 | | ***************************************************************************/ |
| 269 | | |
| 270 | | /* lookup table for FP modes */ |
| 271 | | static const UINT8 fpmode_source[4] = |
| 272 | | { |
| 273 | | ROUND_ROUND, |
| 274 | | ROUND_TRUNC, |
| 275 | | ROUND_CEIL, |
| 276 | | ROUND_FLOOR |
| 277 | | }; |
| 278 | | |
| 279 | | /* flag lookup table for SZ */ |
| 280 | | static const UINT8 sz_cr_table_source[32] = |
| 281 | | { |
| 282 | | /* ..... */ 0x4, |
| 283 | | /* ....C */ 0x4, |
| 284 | | /* ...V. */ 0x4, |
| 285 | | /* ...VC */ 0x4, |
| 286 | | /* ..Z.. */ 0x2, |
| 287 | | /* ..Z.C */ 0x2, |
| 288 | | /* ..ZV. */ 0x2, |
| 289 | | /* ..ZVC */ 0x2, |
| 290 | | /* .S... */ 0x8, |
| 291 | | /* .S..C */ 0x8, |
| 292 | | /* .S.V. */ 0x8, |
| 293 | | /* .S.VC */ 0x8, |
| 294 | | /* .SZ.. */ 0x2, |
| 295 | | /* .SZ.C */ 0x2, |
| 296 | | /* .SZV. */ 0x2, |
| 297 | | /* .SZVC */ 0x2, |
| 298 | | /* U.... */ 0x4, |
| 299 | | /* U...C */ 0x4, |
| 300 | | /* U..V. */ 0x4, |
| 301 | | /* U..VC */ 0x4, |
| 302 | | /* U.Z.. */ 0x2, |
| 303 | | /* U.Z.C */ 0x2, |
| 304 | | /* U.ZV. */ 0x2, |
| 305 | | /* U.ZVC */ 0x2, |
| 306 | | /* US... */ 0x8, |
| 307 | | /* US..C */ 0x8, |
| 308 | | /* US.V. */ 0x8, |
| 309 | | /* US.VC */ 0x8, |
| 310 | | /* USZ.. */ 0x2, |
| 311 | | /* USZ.C */ 0x2, |
| 312 | | /* USZV. */ 0x2, |
| 313 | | /* USZVC */ 0x2 |
| 314 | | }; |
| 315 | | |
| 316 | | /* flag lookup table for CMP */ |
| 317 | | static const UINT8 cmp_cr_table_source[32] = |
| 318 | | { |
| 319 | | /* ..... */ 0x4, |
| 320 | | /* ....C */ 0x4, |
| 321 | | /* ...V. */ 0x8, |
| 322 | | /* ...VC */ 0x8, |
| 323 | | /* ..Z.. */ 0x2, |
| 324 | | /* ..Z.C */ 0x2, |
| 325 | | /* ..ZV. */ 0x2, |
| 326 | | /* ..ZVC */ 0x2, |
| 327 | | /* .S... */ 0x8, |
| 328 | | /* .S..C */ 0x8, |
| 329 | | /* .S.V. */ 0x4, |
| 330 | | /* .S.VC */ 0x4, |
| 331 | | /* .SZ.. */ 0x2, |
| 332 | | /* .SZ.C */ 0x2, |
| 333 | | /* .SZV. */ 0x2, |
| 334 | | /* .SZVC */ 0x2, |
| 335 | | /* U.... */ 0x4, |
| 336 | | /* U...C */ 0x4, |
| 337 | | /* U..V. */ 0x8, |
| 338 | | /* U..VC */ 0x8, |
| 339 | | /* U.Z.. */ 0x2, |
| 340 | | /* U.Z.C */ 0x2, |
| 341 | | /* U.ZV. */ 0x2, |
| 342 | | /* U.ZVC */ 0x2, |
| 343 | | /* US... */ 0x8, |
| 344 | | /* US..C */ 0x8, |
| 345 | | /* US.V. */ 0x4, |
| 346 | | /* US.VC */ 0x4, |
| 347 | | /* USZ.. */ 0x2, |
| 348 | | /* USZ.C */ 0x2, |
| 349 | | /* USZV. */ 0x2, |
| 350 | | /* USZVC */ 0x2 |
| 351 | | }; |
| 352 | | |
| 353 | | /* flag lookup table for CMPL */ |
| 354 | | static const UINT8 cmpl_cr_table_source[32] = |
| 355 | | { |
| 356 | | /* ..... */ 0x4, |
| 357 | | /* ....C */ 0x8, |
| 358 | | /* ...V. */ 0x4, |
| 359 | | /* ...VC */ 0x8, |
| 360 | | /* ..Z.. */ 0x2, |
| 361 | | /* ..Z.C */ 0x2, |
| 362 | | /* ..ZV. */ 0x2, |
| 363 | | /* ..ZVC */ 0x2, |
| 364 | | /* .S... */ 0x4, |
| 365 | | /* .S..C */ 0x8, |
| 366 | | /* .S.V. */ 0x4, |
| 367 | | /* .S.VC */ 0x8, |
| 368 | | /* .SZ.. */ 0x2, |
| 369 | | /* .SZ.C */ 0x2, |
| 370 | | /* .SZV. */ 0x2, |
| 371 | | /* .SZVC */ 0x2, |
| 372 | | /* U.... */ 0x4, |
| 373 | | /* U...C */ 0x8, |
| 374 | | /* U..V. */ 0x4, |
| 375 | | /* U..VC */ 0x8, |
| 376 | | /* U.Z.. */ 0x2, |
| 377 | | /* U.Z.C */ 0x2, |
| 378 | | /* U.ZV. */ 0x2, |
| 379 | | /* U.ZVC */ 0x2, |
| 380 | | /* US... */ 0x4, |
| 381 | | /* US..C */ 0x8, |
| 382 | | /* US.V. */ 0x4, |
| 383 | | /* US.VC */ 0x8, |
| 384 | | /* USZ.. */ 0x2, |
| 385 | | /* USZ.C */ 0x2, |
| 386 | | /* USZV. */ 0x2, |
| 387 | | /* USZVC */ 0x2 |
| 388 | | }; |
| 389 | | |
| 390 | | /* flag lookup table for FCMP */ |
| 391 | | static const UINT8 fcmp_cr_table_source[32] = |
| 392 | | { |
| 393 | | /* ..... */ 0x4, |
| 394 | | /* ....C */ 0x8, |
| 395 | | /* ...V. */ 0x4, |
| 396 | | /* ...VC */ 0x8, |
| 397 | | /* ..Z.. */ 0x2, |
| 398 | | /* ..Z.C */ 0xa, |
| 399 | | /* ..ZV. */ 0x2, |
| 400 | | /* ..ZVC */ 0xa, |
| 401 | | /* .S... */ 0x4, |
| 402 | | /* .S..C */ 0x8, |
| 403 | | /* .S.V. */ 0x4, |
| 404 | | /* .S.VC */ 0x8, |
| 405 | | /* .SZ.. */ 0x2, |
| 406 | | /* .SZ.C */ 0xa, |
| 407 | | /* .SZV. */ 0x2, |
| 408 | | /* .SZVC */ 0xa, |
| 409 | | /* U.... */ 0x5, |
| 410 | | /* U...C */ 0x9, |
| 411 | | /* U..V. */ 0x5, |
| 412 | | /* U..VC */ 0x9, |
| 413 | | /* U.Z.. */ 0x3, |
| 414 | | /* U.Z.C */ 0xb, |
| 415 | | /* U.ZV. */ 0x3, |
| 416 | | /* U.ZVC */ 0xb, |
| 417 | | /* US... */ 0x5, |
| 418 | | /* US..C */ 0x9, |
| 419 | | /* US.V. */ 0x5, |
| 420 | | /* US.VC */ 0x9, |
| 421 | | /* USZ.. */ 0x3, |
| 422 | | /* USZ.C */ 0xb, |
| 423 | | /* USZV. */ 0x3, |
| 424 | | /* USZVC */ 0xb |
| 425 | | }; |
| 426 | | |
| 427 | | |
| 428 | | |
| 429 | | /*************************************************************************** |
| 430 | 99 | INLINE FUNCTIONS |
| 431 | 100 | ***************************************************************************/ |
| 432 | 101 | |
| 433 | | INLINE powerpc_state *get_safe_token(device_t *device) |
| 434 | | { |
| 435 | | assert(device != NULL); |
| 436 | | assert(device->type() == PPC403GA || |
| 437 | | device->type() == PPC403GCX || |
| 438 | | device->type() == PPC405GP || |
| 439 | | device->type() == PPC601 || |
| 440 | | device->type() == PPC602 || |
| 441 | | device->type() == PPC603 || |
| 442 | | device->type() == PPC603E || |
| 443 | | device->type() == PPC603R || |
| 444 | | device->type() == PPC604 || |
| 445 | | device->type() == MPC8240); |
| 446 | | return *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 447 | | } |
| 448 | | |
| 449 | 102 | /*------------------------------------------------- |
| 450 | 103 | alloc_handle - allocate a handle if not |
| 451 | 104 | already allocated |
| 452 | 105 | -------------------------------------------------*/ |
| 453 | 106 | |
| 454 | | INLINE void alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) |
| 107 | inline void ppc_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) |
| 455 | 108 | { |
| 456 | 109 | if (*handleptr == NULL) |
| 457 | 110 | *handleptr = drcuml->handle_alloc(name); |
| r31142 | r31143 | |
| 463 | 116 | registers |
| 464 | 117 | -------------------------------------------------*/ |
| 465 | 118 | |
| 466 | | INLINE void load_fast_iregs(powerpc_state *ppc, drcuml_block *block) |
| 119 | inline void ppc_device::load_fast_iregs(drcuml_block *block) |
| 467 | 120 | { |
| 468 | 121 | int regnum; |
| 469 | 122 | |
| 470 | | for (regnum = 0; regnum < ARRAY_LENGTH(ppc->impstate->regmap); regnum++) |
| 471 | | if (ppc->impstate->regmap[regnum].is_int_register()) |
| 472 | | UML_MOV(block, ireg(ppc->impstate->regmap[regnum].ireg() - REG_I0), mem(&ppc->r[regnum])); |
| 123 | for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) |
| 124 | { |
| 125 | if (m_regmap[regnum].is_int_register()) |
| 126 | { |
| 127 | UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum])); |
| 128 | } |
| 129 | } |
| 473 | 130 | } |
| 474 | 131 | |
| 475 | 132 | |
| r31142 | r31143 | |
| 478 | 135 | registers |
| 479 | 136 | -------------------------------------------------*/ |
| 480 | 137 | |
| 481 | | INLINE void save_fast_iregs(powerpc_state *ppc, drcuml_block *block) |
| 138 | void ppc_device::save_fast_iregs(drcuml_block *block) |
| 482 | 139 | { |
| 483 | 140 | int regnum; |
| 484 | 141 | |
| 485 | | for (regnum = 0; regnum < ARRAY_LENGTH(ppc->impstate->regmap); regnum++) |
| 486 | | if (ppc->impstate->regmap[regnum].is_int_register()) |
| 487 | | UML_MOV(block, mem(&ppc->r[regnum]), ireg(ppc->impstate->regmap[regnum].ireg() - REG_I0)); |
| 142 | for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) |
| 143 | { |
| 144 | if (m_regmap[regnum].is_int_register()) |
| 145 | { |
| 146 | UML_MOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0)); |
| 147 | } |
| 148 | } |
| 488 | 149 | } |
| 489 | 150 | |
| 490 | 151 | |
| r31142 | r31143 | |
| 493 | 154 | for an rlw* instruction |
| 494 | 155 | -------------------------------------------------*/ |
| 495 | 156 | |
| 496 | | INLINE UINT32 compute_rlw_mask(UINT8 mb, UINT8 me) |
| 157 | inline UINT32 ppc_device::compute_rlw_mask(UINT8 mb, UINT8 me) |
| 497 | 158 | { |
| 498 | 159 | if (mb <= me) |
| 499 | 160 | return (0xffffffff >> mb) & (0xffffffff << (31 - me)); |
| r31142 | r31143 | |
| 507 | 168 | for a mtcrf/mfcrf instruction |
| 508 | 169 | -------------------------------------------------*/ |
| 509 | 170 | |
| 510 | | INLINE UINT32 compute_crf_mask(UINT8 crm) |
| 171 | inline UINT32 ppc_device::compute_crf_mask(UINT8 crm) |
| 511 | 172 | { |
| 512 | 173 | UINT32 mask = 0; |
| 513 | 174 | if (crm & 0x80) mask |= 0xf0000000; |
| r31142 | r31143 | |
| 527 | 188 | SPR field of an opcode |
| 528 | 189 | -------------------------------------------------*/ |
| 529 | 190 | |
| 530 | | INLINE UINT32 compute_spr(UINT32 spr) |
| 191 | inline UINT32 ppc_device::compute_spr(UINT32 spr) |
| 531 | 192 | { |
| 532 | 193 | return ((spr >> 5) | (spr << 5)) & 0x3ff; |
| 533 | 194 | } |
| r31142 | r31143 | |
| 539 | 200 | ***************************************************************************/ |
| 540 | 201 | |
| 541 | 202 | /*------------------------------------------------- |
| 542 | | ppcdrc_init - initialize the processor |
| 543 | | -------------------------------------------------*/ |
| 544 | | |
| 545 | | static void ppcdrc_init(powerpc_flavor flavor, UINT32 cap, int tb_divisor, legacy_cpu_device *device, device_irq_acknowledge_delegate irqcallback) |
| 546 | | { |
| 547 | | powerpc_state *ppc; |
| 548 | | drcbe_info beinfo; |
| 549 | | UINT32 flags = 0; |
| 550 | | drc_cache *cache; |
| 551 | | int regnum; |
| 552 | | |
| 553 | | /* allocate enough space for the cache and the core */ |
| 554 | | cache = auto_alloc(device->machine(), drc_cache(CACHE_SIZE + sizeof(*ppc))); |
| 555 | | |
| 556 | | /* allocate the core from the near cache */ |
| 557 | | *(powerpc_state **)device->token() = ppc = (powerpc_state *)cache->alloc_near(sizeof(*ppc)); |
| 558 | | memset(ppc, 0, sizeof(*ppc)); |
| 559 | | |
| 560 | | /* initialize the core */ |
| 561 | | ppccom_init(ppc, flavor, cap, tb_divisor, device, irqcallback); |
| 562 | | |
| 563 | | /* allocate the implementation-specific state from the full cache */ |
| 564 | | ppc->impstate = (ppcimp_state *)cache->alloc_near(sizeof(*ppc->impstate)); |
| 565 | | memset(ppc->impstate, 0, sizeof(*ppc->impstate)); |
| 566 | | ppc->impstate->cache = cache; |
| 567 | | |
| 568 | | /* initialize the UML generator */ |
| 569 | | if (LOG_UML) |
| 570 | | flags |= DRCUML_OPTION_LOG_UML; |
| 571 | | if (LOG_NATIVE) |
| 572 | | flags |= DRCUML_OPTION_LOG_NATIVE; |
| 573 | | ppc->impstate->drcuml = auto_alloc(device->machine(), drcuml_state(*device, *cache, flags, 8, 32, 2)); |
| 574 | | |
| 575 | | /* add symbols for our stuff */ |
| 576 | | ppc->impstate->drcuml->symbol_add(&ppc->pc, sizeof(ppc->pc), "pc"); |
| 577 | | ppc->impstate->drcuml->symbol_add(&ppc->icount, sizeof(ppc->icount), "icount"); |
| 578 | | for (regnum = 0; regnum < 32; regnum++) |
| 579 | | { |
| 580 | | char buf[10]; |
| 581 | | sprintf(buf, "r%d", regnum); |
| 582 | | ppc->impstate->drcuml->symbol_add(&ppc->r[regnum], sizeof(ppc->r[regnum]), buf); |
| 583 | | sprintf(buf, "fpr%d", regnum); |
| 584 | | ppc->impstate->drcuml->symbol_add(&ppc->f[regnum], sizeof(ppc->r[regnum]), buf); |
| 585 | | } |
| 586 | | for (regnum = 0; regnum < 8; regnum++) |
| 587 | | { |
| 588 | | char buf[10]; |
| 589 | | sprintf(buf, "cr%d", regnum); |
| 590 | | ppc->impstate->drcuml->symbol_add(&ppc->cr[regnum], sizeof(ppc->cr[regnum]), buf); |
| 591 | | } |
| 592 | | ppc->impstate->drcuml->symbol_add(&ppc->xerso, sizeof(ppc->xerso), "xerso"); |
| 593 | | ppc->impstate->drcuml->symbol_add(&ppc->fpscr, sizeof(ppc->fpscr), "fpscr"); |
| 594 | | ppc->impstate->drcuml->symbol_add(&ppc->msr, sizeof(ppc->msr), "msr"); |
| 595 | | ppc->impstate->drcuml->symbol_add(&ppc->sr, sizeof(ppc->sr), "sr"); |
| 596 | | ppc->impstate->drcuml->symbol_add(&ppc->spr[SPR_XER], sizeof(ppc->spr[SPR_XER]), "xer"); |
| 597 | | ppc->impstate->drcuml->symbol_add(&ppc->spr[SPR_LR], sizeof(ppc->spr[SPR_LR]), "lr"); |
| 598 | | ppc->impstate->drcuml->symbol_add(&ppc->spr[SPR_CTR], sizeof(ppc->spr[SPR_CTR]), "ctr"); |
| 599 | | ppc->impstate->drcuml->symbol_add(&ppc->spr, sizeof(ppc->spr), "spr"); |
| 600 | | ppc->impstate->drcuml->symbol_add(&ppc->dcr, sizeof(ppc->dcr), "dcr"); |
| 601 | | ppc->impstate->drcuml->symbol_add(&ppc->param0, sizeof(ppc->param0), "param0"); |
| 602 | | ppc->impstate->drcuml->symbol_add(&ppc->param1, sizeof(ppc->param1), "param1"); |
| 603 | | ppc->impstate->drcuml->symbol_add(&ppc->irq_pending, sizeof(ppc->irq_pending), "irq_pending"); |
| 604 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->mode, sizeof(ppc->impstate->mode), "mode"); |
| 605 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->arg0, sizeof(ppc->impstate->arg0), "arg0"); |
| 606 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->arg1, sizeof(ppc->impstate->arg1), "arg1"); |
| 607 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->updateaddr, sizeof(ppc->impstate->updateaddr), "updateaddr"); |
| 608 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->swcount, sizeof(ppc->impstate->swcount), "swcount"); |
| 609 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->tempaddr, sizeof(ppc->impstate->tempaddr), "tempaddr"); |
| 610 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->tempdata, sizeof(ppc->impstate->tempdata), "tempdata"); |
| 611 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->fp0, sizeof(ppc->impstate->fp0), "fp0"); |
| 612 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->fpmode, sizeof(ppc->impstate->fpmode), "fpmode"); |
| 613 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->sz_cr_table, sizeof(ppc->impstate->sz_cr_table), "sz_cr_table"); |
| 614 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->cmp_cr_table, sizeof(ppc->impstate->cmp_cr_table), "cmp_cr_table"); |
| 615 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->cmpl_cr_table, sizeof(ppc->impstate->cmpl_cr_table), "cmpl_cr_table"); |
| 616 | | ppc->impstate->drcuml->symbol_add(&ppc->impstate->fcmp_cr_table, sizeof(ppc->impstate->fcmp_cr_table), "fcmp_cr_table"); |
| 617 | | |
| 618 | | /* initialize the front-end helper */ |
| 619 | | ppc->impstate->drcfe = auto_alloc(device->machine(), ppc_frontend(*ppc, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); |
| 620 | | |
| 621 | | /* initialize the implementation state tables */ |
| 622 | | memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); |
| 623 | | memcpy(ppc->impstate->sz_cr_table, sz_cr_table_source, sizeof(sz_cr_table_source)); |
| 624 | | memcpy(ppc->impstate->cmp_cr_table, cmp_cr_table_source, sizeof(cmp_cr_table_source)); |
| 625 | | memcpy(ppc->impstate->cmpl_cr_table, cmpl_cr_table_source, sizeof(cmpl_cr_table_source)); |
| 626 | | memcpy(ppc->impstate->fcmp_cr_table, fcmp_cr_table_source, sizeof(fcmp_cr_table_source)); |
| 627 | | |
| 628 | | /* compute the register parameters */ |
| 629 | | for (regnum = 0; regnum < 32; regnum++) |
| 630 | | { |
| 631 | | ppc->impstate->regmap[regnum] = mem(&ppc->r[regnum]); |
| 632 | | ppc->impstate->fdregmap[regnum] = mem(&ppc->f[regnum]); |
| 633 | | } |
| 634 | | |
| 635 | | /* if we have registers to spare, assign r0, r1, r2 to leftovers */ |
| 636 | | if (!DISABLE_FAST_REGISTERS) |
| 637 | | { |
| 638 | | ppc->impstate->drcuml->get_backend_info(beinfo); |
| 639 | | if (beinfo.direct_iregs > 5) |
| 640 | | ppc->impstate->regmap[0] = I5; |
| 641 | | if (beinfo.direct_iregs > 6) |
| 642 | | ppc->impstate->regmap[1] = I6; |
| 643 | | if (beinfo.direct_iregs > 7) |
| 644 | | ppc->impstate->regmap[2] = I7; |
| 645 | | } |
| 646 | | |
| 647 | | /* mark the cache dirty so it is updated on next execute */ |
| 648 | | ppc->impstate->cache_dirty = TRUE; |
| 649 | | } |
| 650 | | |
| 651 | | |
| 652 | | /*------------------------------------------------- |
| 653 | | ppcdrc_reset - reset the processor |
| 654 | | -------------------------------------------------*/ |
| 655 | | |
| 656 | | static CPU_RESET( ppcdrc ) |
| 657 | | { |
| 658 | | powerpc_state *ppc = get_safe_token(device); |
| 659 | | |
| 660 | | /* reset the common code and mark the cache dirty */ |
| 661 | | ppccom_reset(ppc); |
| 662 | | ppc->impstate->mode = 0; |
| 663 | | ppc->impstate->cache_dirty = TRUE; |
| 664 | | } |
| 665 | | |
| 666 | | |
| 667 | | /*------------------------------------------------- |
| 668 | 203 | ppcdrc_execute - execute the CPU for the |
| 669 | 204 | specified number of cycles |
| 670 | 205 | -------------------------------------------------*/ |
| 671 | 206 | |
| 672 | | static CPU_EXECUTE( ppcdrc ) |
| 207 | void ppc_device::execute_run() |
| 673 | 208 | { |
| 674 | | powerpc_state *ppc = get_safe_token(device); |
| 675 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 676 | 209 | int execute_result; |
| 677 | 210 | |
| 678 | 211 | /* reset the cache if dirty */ |
| 679 | | if (ppc->impstate->cache_dirty) |
| 680 | | code_flush_cache(ppc); |
| 681 | | ppc->impstate->cache_dirty = FALSE; |
| 212 | if (m_cache_dirty) |
| 213 | code_flush_cache(); |
| 214 | m_cache_dirty = FALSE; |
| 682 | 215 | |
| 683 | 216 | /* execute */ |
| 684 | 217 | do |
| 685 | 218 | { |
| 686 | 219 | /* run as much as we can */ |
| 687 | | execute_result = drcuml->execute(*ppc->impstate->entry); |
| 220 | execute_result = m_drcuml->execute(*m_entry); |
| 688 | 221 | |
| 689 | 222 | /* if we need to recompile, do it */ |
| 690 | 223 | if (execute_result == EXECUTE_MISSING_CODE) |
| 691 | | code_compile_block(ppc, ppc->impstate->mode, ppc->pc); |
| 224 | code_compile_block(m_core->mode, m_core->pc); |
| 692 | 225 | else if (execute_result == EXECUTE_UNMAPPED_CODE) |
| 693 | | fatalerror("Attempted to execute unmapped code at PC=%08X\n", ppc->pc); |
| 226 | fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->pc); |
| 694 | 227 | else if (execute_result == EXECUTE_RESET_CACHE) |
| 695 | | code_flush_cache(ppc); |
| 228 | code_flush_cache(); |
| 696 | 229 | |
| 697 | 230 | } while (execute_result != EXECUTE_OUT_OF_CYCLES); |
| 698 | 231 | } |
| 699 | 232 | |
| 700 | 233 | |
| 701 | 234 | /*------------------------------------------------- |
| 702 | | ppcdrc_exit - cleanup from execution |
| 703 | | -------------------------------------------------*/ |
| 704 | | |
| 705 | | static CPU_EXIT( ppcdrc ) |
| 706 | | { |
| 707 | | powerpc_state *ppc = get_safe_token(device); |
| 708 | | ppccom_exit(ppc); |
| 709 | | |
| 710 | | /* clean up the DRC */ |
| 711 | | auto_free(device->machine(), ppc->impstate->drcfe); |
| 712 | | auto_free(device->machine(), ppc->impstate->drcuml); |
| 713 | | auto_free(device->machine(), ppc->impstate->cache); |
| 714 | | } |
| 715 | | |
| 716 | | |
| 717 | | /*------------------------------------------------- |
| 718 | | ppcdrc_translate - perform virtual-to-physical |
| 719 | | address translation |
| 720 | | -------------------------------------------------*/ |
| 721 | | |
| 722 | | static CPU_TRANSLATE( ppcdrc ) |
| 723 | | { |
| 724 | | powerpc_state *ppc = get_safe_token(device); |
| 725 | | return ppccom_translate_address(ppc, space, intention, address); |
| 726 | | } |
| 727 | | |
| 728 | | |
| 729 | | /*------------------------------------------------- |
| 730 | | ppcdrc_dasm - disassemble an instruction |
| 731 | | -------------------------------------------------*/ |
| 732 | | |
| 733 | | static CPU_DISASSEMBLE( ppcdrc ) |
| 734 | | { |
| 735 | | powerpc_state *ppc = get_safe_token(device); |
| 736 | | return ppccom_dasm(ppc, buffer, pc, oprom, opram); |
| 737 | | } |
| 738 | | |
| 739 | | |
| 740 | | /*------------------------------------------------- |
| 741 | | ppcdrc_set_info - set information about a given |
| 742 | | CPU instance |
| 743 | | -------------------------------------------------*/ |
| 744 | | |
| 745 | | static CPU_SET_INFO( ppcdrc ) |
| 746 | | { |
| 747 | | powerpc_state *ppc = get_safe_token(device); |
| 748 | | |
| 749 | | /* --- everything is handled generically --- */ |
| 750 | | ppccom_set_info(ppc, state, info); |
| 751 | | } |
| 752 | | |
| 753 | | |
| 754 | | /*------------------------------------------------- |
| 755 | | ppcdrc_get_info - return information about a given |
| 756 | | CPU instance |
| 757 | | -------------------------------------------------*/ |
| 758 | | |
| 759 | | static CPU_GET_INFO( ppcdrc ) |
| 760 | | { |
| 761 | | powerpc_state *ppc = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; |
| 762 | | switch (state) |
| 763 | | { |
| 764 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 765 | | case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(powerpc_state *); break; |
| 766 | | case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; |
| 767 | | |
| 768 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 769 | | case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppcdrc); break; |
| 770 | | case CPUINFO_FCT_INIT: /* provided per-CPU */ break; |
| 771 | | case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppcdrc); break; |
| 772 | | case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppcdrc); break; |
| 773 | | case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppcdrc); break; |
| 774 | | case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(ppcdrc);break; |
| 775 | | case CPUINFO_FCT_TRANSLATE: info->translate = CPU_TRANSLATE_NAME(ppcdrc); break; |
| 776 | | |
| 777 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 778 | | case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 779 | | |
| 780 | | /* --- everything else is handled generically --- */ |
| 781 | | default: ppccom_get_info(ppc, state, info); break; |
| 782 | | } |
| 783 | | } |
| 784 | | |
| 785 | | |
| 786 | | /*------------------------------------------------- |
| 787 | 235 | ppcdrc_set_options - configure DRC options |
| 788 | 236 | -------------------------------------------------*/ |
| 789 | 237 | |
| 790 | | void ppcdrc_set_options(device_t *device, UINT32 options) |
| 238 | void ppc_device::ppcdrc_set_options(UINT32 options) |
| 791 | 239 | { |
| 792 | | powerpc_state *ppc = get_safe_token(device); |
| 793 | | ppc->impstate->drcoptions = options; |
| 240 | m_drcoptions = options; |
| 794 | 241 | } |
| 795 | 242 | |
| 796 | 243 | |
| r31142 | r31143 | |
| 799 | 246 | region |
| 800 | 247 | -------------------------------------------------*/ |
| 801 | 248 | |
| 802 | | void ppcdrc_add_fastram(device_t *device, offs_t start, offs_t end, UINT8 readonly, void *base) |
| 249 | void ppc_device::ppcdrc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base) |
| 803 | 250 | { |
| 804 | | powerpc_state *ppc = get_safe_token(device); |
| 805 | | if (ppc->impstate->fastram_select < ARRAY_LENGTH(ppc->impstate->fastram)) |
| 251 | if (m_fastram_select < ARRAY_LENGTH(m_fastram)) |
| 806 | 252 | { |
| 807 | | ppc->impstate->fastram[ppc->impstate->fastram_select].start = start; |
| 808 | | ppc->impstate->fastram[ppc->impstate->fastram_select].end = end; |
| 809 | | ppc->impstate->fastram[ppc->impstate->fastram_select].readonly = readonly; |
| 810 | | ppc->impstate->fastram[ppc->impstate->fastram_select].base = base; |
| 811 | | ppc->impstate->fastram_select++; |
| 253 | m_fastram[m_fastram_select].start = start; |
| 254 | m_fastram[m_fastram_select].end = end; |
| 255 | m_fastram[m_fastram_select].readonly = readonly; |
| 256 | m_fastram[m_fastram_select].base = base; |
| 257 | m_fastram_select++; |
| 812 | 258 | } |
| 813 | 259 | } |
| 814 | 260 | |
| r31142 | r31143 | |
| 817 | 263 | ppcdrc_add_hotspot - add a new hotspot |
| 818 | 264 | -------------------------------------------------*/ |
| 819 | 265 | |
| 820 | | void ppcdrc_add_hotspot(device_t *device, offs_t pc, UINT32 opcode, UINT32 cycles) |
| 266 | void ppc_device::ppcdrc_add_hotspot(offs_t pc, UINT32 opcode, UINT32 cycles) |
| 821 | 267 | { |
| 822 | | powerpc_state *ppc = get_safe_token(device); |
| 823 | | if (ppc->impstate->hotspot_select < ARRAY_LENGTH(ppc->impstate->hotspot)) |
| 268 | if (m_hotspot_select < ARRAY_LENGTH(m_hotspot)) |
| 824 | 269 | { |
| 825 | | ppc->impstate->hotspot[ppc->impstate->hotspot_select].pc = pc; |
| 826 | | ppc->impstate->hotspot[ppc->impstate->hotspot_select].opcode = opcode; |
| 827 | | ppc->impstate->hotspot[ppc->impstate->hotspot_select].cycles = cycles; |
| 828 | | ppc->impstate->hotspot_select++; |
| 270 | m_hotspot[m_hotspot_select].pc = pc; |
| 271 | m_hotspot[m_hotspot_select].opcode = opcode; |
| 272 | m_hotspot[m_hotspot_select].cycles = cycles; |
| 273 | m_hotspot_select++; |
| 829 | 274 | } |
| 830 | 275 | } |
| 831 | 276 | |
| r31142 | r31143 | |
| 840 | 285 | regenerate static code |
| 841 | 286 | -------------------------------------------------*/ |
| 842 | 287 | |
| 843 | | static void code_flush_cache(powerpc_state *ppc) |
| 288 | void ppc_device::code_flush_cache() |
| 844 | 289 | { |
| 845 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 846 | | int mode; |
| 847 | | |
| 848 | 290 | /* empty the transient cache contents */ |
| 849 | | drcuml->reset(); |
| 291 | m_drcuml->reset(); |
| 850 | 292 | |
| 851 | 293 | try |
| 852 | 294 | { |
| 853 | 295 | /* generate the entry point and out-of-cycles handlers */ |
| 854 | | static_generate_entry_point(ppc); |
| 855 | | static_generate_nocode_handler(ppc); |
| 856 | | static_generate_out_of_cycles(ppc); |
| 857 | | static_generate_tlb_mismatch(ppc); |
| 858 | | if (ppc->cap & PPCCAP_603_MMU) |
| 859 | | static_generate_swap_tgpr(ppc); |
| 296 | static_generate_entry_point(); |
| 297 | static_generate_nocode_handler(); |
| 298 | static_generate_out_of_cycles(); |
| 299 | static_generate_tlb_mismatch(); |
| 300 | if (m_cap & PPCCAP_603_MMU) |
| 301 | static_generate_swap_tgpr(); |
| 860 | 302 | |
| 861 | 303 | /* append exception handlers for various types */ |
| 862 | | static_generate_exception(ppc, EXCEPTION_RESET, TRUE, "exception_reset"); |
| 863 | | static_generate_exception(ppc, EXCEPTION_MACHCHECK, TRUE, "exception_machine_check"); |
| 864 | | static_generate_exception(ppc, EXCEPTION_DSI, TRUE, "exception_dsi"); |
| 865 | | static_generate_exception(ppc, EXCEPTION_ISI, TRUE, "exception_isi"); |
| 866 | | static_generate_exception(ppc, EXCEPTION_EI, TRUE, "exception_ei"); |
| 867 | | static_generate_exception(ppc, EXCEPTION_EI, FALSE, "exception_ei_norecover"); |
| 868 | | static_generate_exception(ppc, EXCEPTION_ALIGN, TRUE, "exception_align"); |
| 869 | | static_generate_exception(ppc, EXCEPTION_PROGRAM, TRUE, "exception_program"); |
| 870 | | static_generate_exception(ppc, EXCEPTION_NOFPU, TRUE, "exception_fpu_unavailable"); |
| 871 | | static_generate_exception(ppc, EXCEPTION_DECREMENT, TRUE, "exception_decrementer"); |
| 872 | | static_generate_exception(ppc, EXCEPTION_SYSCALL, TRUE, "exception_syscall"); |
| 873 | | static_generate_exception(ppc, EXCEPTION_TRACE, TRUE, "exception_trace"); |
| 874 | | static_generate_exception(ppc, EXCEPTION_FPASSIST, TRUE, "exception_floating_point_assist"); |
| 875 | | if (ppc->cap & PPCCAP_603_MMU) |
| 304 | static_generate_exception(EXCEPTION_RESET, TRUE, "exception_reset"); |
| 305 | static_generate_exception(EXCEPTION_MACHCHECK, TRUE, "exception_machine_check"); |
| 306 | static_generate_exception(EXCEPTION_DSI, TRUE, "exception_dsi"); |
| 307 | static_generate_exception(EXCEPTION_ISI, TRUE, "exception_isi"); |
| 308 | static_generate_exception(EXCEPTION_EI, TRUE, "exception_ei"); |
| 309 | static_generate_exception(EXCEPTION_EI, FALSE, "exception_ei_norecover"); |
| 310 | static_generate_exception(EXCEPTION_ALIGN, TRUE, "exception_align"); |
| 311 | static_generate_exception(EXCEPTION_PROGRAM, TRUE, "exception_program"); |
| 312 | static_generate_exception(EXCEPTION_NOFPU, TRUE, "exception_fpu_unavailable"); |
| 313 | static_generate_exception(EXCEPTION_DECREMENT, TRUE, "exception_decrementer"); |
| 314 | static_generate_exception(EXCEPTION_SYSCALL, TRUE, "exception_syscall"); |
| 315 | static_generate_exception(EXCEPTION_TRACE, TRUE, "exception_trace"); |
| 316 | static_generate_exception(EXCEPTION_FPASSIST, TRUE, "exception_floating_point_assist"); |
| 317 | if (m_cap & PPCCAP_603_MMU) |
| 876 | 318 | { |
| 877 | | static_generate_exception(ppc, EXCEPTION_ITLBMISS, TRUE, "exception_itlb_miss"); |
| 878 | | static_generate_exception(ppc, EXCEPTION_DTLBMISSL, TRUE, "exception_dtlb_miss_load"); |
| 879 | | static_generate_exception(ppc, EXCEPTION_DTLBMISSS, TRUE, "exception_dtlb_miss_store"); |
| 319 | static_generate_exception(EXCEPTION_ITLBMISS, TRUE, "exception_itlb_miss"); |
| 320 | static_generate_exception(EXCEPTION_DTLBMISSL, TRUE, "exception_dtlb_miss_load"); |
| 321 | static_generate_exception(EXCEPTION_DTLBMISSS, TRUE, "exception_dtlb_miss_store"); |
| 880 | 322 | } |
| 881 | 323 | |
| 882 | 324 | /* add subroutines for memory accesses */ |
| 883 | | for (mode = 0; mode < 8; mode++) |
| 325 | for (int mode = 0; mode < 8; mode++) |
| 884 | 326 | { |
| 885 | | static_generate_memory_accessor(ppc, mode, 1, FALSE, FALSE, "read8", ppc->impstate->read8[mode], NULL); |
| 886 | | static_generate_memory_accessor(ppc, mode, 1, TRUE, FALSE, "write8", ppc->impstate->write8[mode], NULL); |
| 887 | | static_generate_memory_accessor(ppc, mode, 2, FALSE, TRUE, "read16mask", ppc->impstate->read16mask[mode], NULL); |
| 888 | | static_generate_memory_accessor(ppc, mode, 2, FALSE, FALSE, "read16", ppc->impstate->read16[mode], ppc->impstate->read16mask[mode]); |
| 889 | | static_generate_memory_accessor(ppc, mode, 2, TRUE, TRUE, "write16mask", ppc->impstate->write16mask[mode], NULL); |
| 890 | | static_generate_memory_accessor(ppc, mode, 2, TRUE, FALSE, "write16", ppc->impstate->write16[mode], ppc->impstate->write16mask[mode]); |
| 891 | | static_generate_memory_accessor(ppc, mode, 4, FALSE, TRUE, "read32mask", ppc->impstate->read32mask[mode], NULL); |
| 892 | | static_generate_memory_accessor(ppc, mode, 4, FALSE, FALSE, "read32align", ppc->impstate->read32align[mode], NULL); |
| 893 | | static_generate_memory_accessor(ppc, mode, 4, FALSE, FALSE, "read32", ppc->impstate->read32[mode], ppc->impstate->read32mask[mode]); |
| 894 | | static_generate_memory_accessor(ppc, mode, 4, TRUE, TRUE, "write32mask", ppc->impstate->write32mask[mode], NULL); |
| 895 | | static_generate_memory_accessor(ppc, mode, 4, TRUE, FALSE, "write32align",ppc->impstate->write32align[mode],NULL); |
| 896 | | static_generate_memory_accessor(ppc, mode, 4, TRUE, FALSE, "write32", ppc->impstate->write32[mode], ppc->impstate->write32mask[mode]); |
| 897 | | static_generate_memory_accessor(ppc, mode, 8, FALSE, TRUE, "read64mask", ppc->impstate->read64mask[mode], NULL); |
| 898 | | static_generate_memory_accessor(ppc, mode, 8, FALSE, FALSE, "read64", ppc->impstate->read64[mode], ppc->impstate->read64mask[mode]); |
| 899 | | static_generate_memory_accessor(ppc, mode, 8, TRUE, TRUE, "write64mask", ppc->impstate->write64mask[mode], NULL); |
| 900 | | static_generate_memory_accessor(ppc, mode, 8, TRUE, FALSE, "write64", ppc->impstate->write64[mode], ppc->impstate->write64mask[mode]); |
| 901 | | static_generate_lsw_entries(ppc, mode); |
| 902 | | static_generate_stsw_entries(ppc, mode); |
| 327 | static_generate_memory_accessor(mode, 1, FALSE, FALSE, "read8", m_read8[mode], NULL); |
| 328 | static_generate_memory_accessor(mode, 1, TRUE, FALSE, "write8", m_write8[mode], NULL); |
| 329 | static_generate_memory_accessor(mode, 2, FALSE, TRUE, "read16mask", m_read16mask[mode], NULL); |
| 330 | static_generate_memory_accessor(mode, 2, FALSE, FALSE, "read16", m_read16[mode], m_read16mask[mode]); |
| 331 | static_generate_memory_accessor(mode, 2, TRUE, TRUE, "write16mask", m_write16mask[mode], NULL); |
| 332 | static_generate_memory_accessor(mode, 2, TRUE, FALSE, "write16", m_write16[mode], m_write16mask[mode]); |
| 333 | static_generate_memory_accessor(mode, 4, FALSE, TRUE, "read32mask", m_read32mask[mode], NULL); |
| 334 | static_generate_memory_accessor(mode, 4, FALSE, FALSE, "read32align", m_read32align[mode], NULL); |
| 335 | static_generate_memory_accessor(mode, 4, FALSE, FALSE, "read32", m_read32[mode], m_read32mask[mode]); |
| 336 | static_generate_memory_accessor(mode, 4, TRUE, TRUE, "write32mask", m_write32mask[mode], NULL); |
| 337 | static_generate_memory_accessor(mode, 4, TRUE, FALSE, "write32align",m_write32align[mode],NULL); |
| 338 | static_generate_memory_accessor(mode, 4, TRUE, FALSE, "write32", m_write32[mode], m_write32mask[mode]); |
| 339 | static_generate_memory_accessor(mode, 8, FALSE, TRUE, "read64mask", m_read64mask[mode], NULL); |
| 340 | static_generate_memory_accessor(mode, 8, FALSE, FALSE, "read64", m_read64[mode], m_read64mask[mode]); |
| 341 | static_generate_memory_accessor(mode, 8, TRUE, TRUE, "write64mask", m_write64mask[mode], NULL); |
| 342 | static_generate_memory_accessor(mode, 8, TRUE, FALSE, "write64", m_write64[mode], m_write64mask[mode]); |
| 343 | static_generate_lsw_entries(mode); |
| 344 | static_generate_stsw_entries(mode); |
| 903 | 345 | } |
| 904 | 346 | } |
| 905 | 347 | catch (drcuml_block::abort_compilation &) |
| r31142 | r31143 | |
| 914 | 356 | given mode at the specified pc |
| 915 | 357 | -------------------------------------------------*/ |
| 916 | 358 | |
| 917 | | static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc) |
| 359 | void ppc_device::code_compile_block(UINT8 mode, offs_t pc) |
| 918 | 360 | { |
| 919 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 920 | 361 | compiler_state compiler = { 0 }; |
| 921 | 362 | const opcode_desc *seqhead, *seqlast; |
| 922 | 363 | const opcode_desc *desclist; |
| r31142 | r31143 | |
| 926 | 367 | g_profiler.start(PROFILER_DRC_COMPILE); |
| 927 | 368 | |
| 928 | 369 | /* get a description of this sequence */ |
| 929 | | desclist = ppc->impstate->drcfe->describe_code(pc); |
| 370 | desclist = m_drcfe->describe_code(pc); |
| 930 | 371 | if (LOG_UML || LOG_NATIVE) |
| 931 | | log_opcode_desc(drcuml, desclist, 0); |
| 372 | log_opcode_desc(m_drcuml, desclist, 0); |
| 932 | 373 | |
| 933 | 374 | bool succeeded = false; |
| 934 | 375 | while (!succeeded) |
| r31142 | r31143 | |
| 936 | 377 | try |
| 937 | 378 | { |
| 938 | 379 | /* start the block */ |
| 939 | | block = drcuml->begin_block(4096); |
| 380 | block = m_drcuml->begin_block(4096); |
| 940 | 381 | |
| 941 | 382 | /* loop until we get through all instruction sequences */ |
| 942 | 383 | for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) |
| r31142 | r31143 | |
| 955 | 396 | assert(seqlast != NULL); |
| 956 | 397 | |
| 957 | 398 | /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ |
| 958 | | if (override || !drcuml->hash_exists(mode, seqhead->pc)) |
| 399 | if (override || !m_drcuml->hash_exists(mode, seqhead->pc)) |
| 959 | 400 | UML_HASH(block, mode, seqhead->pc); // hash mode,pc |
| 960 | 401 | |
| 961 | 402 | /* if we already have a hash, and this is the first sequence, assume that we */ |
| r31142 | r31143 | |
| 970 | 411 | else |
| 971 | 412 | { |
| 972 | 413 | UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 |
| 973 | | UML_HASHJMP(block, ppc->impstate->mode, seqhead->pc, *ppc->impstate->nocode); |
| 414 | UML_HASHJMP(block, m_core->mode, seqhead->pc, *m_nocode); |
| 974 | 415 | // hashjmp <mode>,seqhead->pc,nocode |
| 975 | 416 | continue; |
| 976 | 417 | } |
| 977 | 418 | |
| 978 | 419 | /* validate this code block if we're not pointing into ROM */ |
| 979 | | if (ppc->program->get_write_ptr(seqhead->physpc) != NULL) |
| 980 | | generate_checksum_block(ppc, block, &compiler, seqhead, seqlast); // <checksum> |
| 420 | if (m_program->get_write_ptr(seqhead->physpc) != NULL) |
| 421 | generate_checksum_block(block, &compiler, seqhead, seqlast); // <checksum> |
| 981 | 422 | |
| 982 | 423 | /* label this instruction, if it may be jumped to locally */ |
| 983 | 424 | if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) |
| r31142 | r31143 | |
| 985 | 426 | |
| 986 | 427 | /* iterate over instructions in the sequence and compile them */ |
| 987 | 428 | for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) |
| 988 | | generate_sequence_instruction(ppc, block, &compiler, curdesc); // <instruction> |
| 429 | generate_sequence_instruction(block, &compiler, curdesc); // <instruction> |
| 989 | 430 | |
| 990 | 431 | /* if we need to return to the start, do it */ |
| 991 | 432 | if (seqlast->flags & OPFLAG_RETURN_TO_START) |
| r31142 | r31143 | |
| 996 | 437 | nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; |
| 997 | 438 | |
| 998 | 439 | /* count off cycles and go there */ |
| 999 | | generate_update_cycles(ppc, block, &compiler, nextpc, TRUE); // <subtract cycles> |
| 440 | generate_update_cycles(block, &compiler, nextpc, TRUE); // <subtract cycles> |
| 1000 | 441 | |
| 1001 | 442 | /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ |
| 1002 | 443 | if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) |
| 1003 | | UML_HASHJMP(block, mem(&ppc->impstate->mode), nextpc, *ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode |
| 444 | UML_HASHJMP(block, mem(&m_core->mode), nextpc, *m_nocode);// hashjmp <mode>,nextpc,nocode |
| 1004 | 445 | else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) |
| 1005 | | UML_HASHJMP(block, ppc->impstate->mode, nextpc, *ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode |
| 446 | UML_HASHJMP(block, m_core->mode, nextpc, *m_nocode);// hashjmp <mode>,nextpc,nocode |
| 1006 | 447 | } |
| 1007 | 448 | |
| 1008 | 449 | /* end the sequence */ |
| r31142 | r31143 | |
| 1013 | 454 | catch (drcuml_block::abort_compilation &) |
| 1014 | 455 | { |
| 1015 | 456 | // flush the cache and try again |
| 1016 | | code_flush_cache(ppc); |
| 457 | code_flush_cache(); |
| 1017 | 458 | } |
| 1018 | 459 | } |
| 1019 | 460 | } |
| r31142 | r31143 | |
| 1031 | 472 | |
| 1032 | 473 | static void cfunc_printf_exception(void *param) |
| 1033 | 474 | { |
| 1034 | | powerpc_state *ppc = (powerpc_state *)param; |
| 1035 | | printf("Exception: type=%2d EPC=%08X MSR=%08X\n", ppc->param0, ppc->spr[SPROEA_SRR0], ppc->spr[SPROEA_SRR1]); |
| 1036 | | cfunc_printf_probe(ppc); |
| 475 | ppc_device *ppc = (ppc_device *)param; |
| 476 | ppc->ppc_cfunc_printf_exception(); |
| 1037 | 477 | } |
| 1038 | 478 | |
| 479 | void ppc_device::ppc_cfunc_printf_exception() |
| 480 | { |
| 481 | printf("Exception: type=%2d EPC=%08X MSR=%08X\n", m_core->param0, m_core->spr[SPROEA_SRR0], m_core->spr[SPROEA_SRR1]); |
| 482 | ppc_cfunc_printf_probe(); |
| 483 | } |
| 1039 | 484 | |
| 485 | |
| 1040 | 486 | /*------------------------------------------------- |
| 1041 | 487 | cfunc_printf_debug - generic printf for |
| 1042 | 488 | debugging |
| r31142 | r31143 | |
| 1044 | 490 | |
| 1045 | 491 | static void cfunc_printf_debug(void *param) |
| 1046 | 492 | { |
| 1047 | | powerpc_state *ppc = (powerpc_state *)param; |
| 1048 | | printf(ppc->impstate->format, ppc->impstate->arg0, ppc->impstate->arg1); |
| 493 | ppc_device *ppc = (ppc_device *)param; |
| 494 | ppc->ppc_cfunc_printf_debug(); |
| 1049 | 495 | } |
| 1050 | 496 | |
| 497 | void ppc_device::ppc_cfunc_printf_debug() |
| 498 | { |
| 499 | printf(m_core->format, m_core->arg0, m_arg1); |
| 500 | } |
| 1051 | 501 | |
| 502 | |
| 1052 | 503 | /*------------------------------------------------- |
| 1053 | 504 | cfunc_printf_probe - print the current CPU |
| 1054 | 505 | state and return |
| r31142 | r31143 | |
| 1056 | 507 | |
| 1057 | 508 | static void cfunc_printf_probe(void *param) |
| 1058 | 509 | { |
| 1059 | | powerpc_state *ppc = (powerpc_state *)param; |
| 1060 | | UINT32 pc = (UINT32)(FPTR)param; |
| 510 | ppc_device *ppc = (ppc_device *)param; |
| 511 | ppc->ppc_cfunc_printf_probe(); |
| 512 | } |
| 1061 | 513 | |
| 1062 | | printf(" PC=%08X\n", pc); |
| 514 | void ppc_device::ppc_cfunc_printf_probe() |
| 515 | { |
| 516 | printf(" PC=%08X\n", m_core->pc); |
| 1063 | 517 | printf(" r0=%08X r1=%08X r2=%08X r3=%08X\n", |
| 1064 | | ppc->r[0], ppc->r[1], ppc->r[2], ppc->r[3]); |
| 518 | m_core->r[0], m_core->r[1], m_core->r[2], m_core->r[3]); |
| 1065 | 519 | printf(" r4=%08X r5=%08X r6=%08X r7=%08X\n", |
| 1066 | | ppc->r[4], ppc->r[5], ppc->r[6], ppc->r[7]); |
| 520 | m_core->r[4], m_core->r[5], m_core->r[6], m_core->r[7]); |
| 1067 | 521 | printf(" r8=%08X r9=%08X r10=%08X r11=%08X\n", |
| 1068 | | ppc->r[8], ppc->r[9], ppc->r[10], ppc->r[11]); |
| 522 | m_core->r[8], m_core->r[9], m_core->r[10], m_core->r[11]); |
| 1069 | 523 | printf("r12=%08X r13=%08X r14=%08X r15=%08X\n", |
| 1070 | | ppc->r[12], ppc->r[13], ppc->r[14], ppc->r[15]); |
| 524 | m_core->r[12], m_core->r[13], m_core->r[14], m_core->r[15]); |
| 1071 | 525 | printf("r16=%08X r17=%08X r18=%08X r19=%08X\n", |
| 1072 | | ppc->r[16], ppc->r[17], ppc->r[18], ppc->r[19]); |
| 526 | m_core->r[16], m_core->r[17], m_core->r[18], m_core->r[19]); |
| 1073 | 527 | printf("r20=%08X r21=%08X r22=%08X r23=%08X\n", |
| 1074 | | ppc->r[20], ppc->r[21], ppc->r[22], ppc->r[23]); |
| 528 | m_core->r[20], m_core->r[21], m_core->r[22], m_core->r[23]); |
| 1075 | 529 | printf("r24=%08X r25=%08X r26=%08X r27=%08X\n", |
| 1076 | | ppc->r[24], ppc->r[25], ppc->r[26], ppc->r[27]); |
| 530 | m_core->r[24], m_core->r[25], m_core->r[26], m_core->r[27]); |
| 1077 | 531 | printf("r28=%08X r29=%08X r30=%08X r31=%08X\n", |
| 1078 | | ppc->r[28], ppc->r[29], ppc->r[30], ppc->r[31]); |
| 532 | m_core->r[28], m_core->r[29], m_core->r[30], m_core->r[31]); |
| 1079 | 533 | } |
| 1080 | 534 | |
| 1081 | 535 | |
| r31142 | r31143 | |
| 1086 | 540 | |
| 1087 | 541 | static void cfunc_unimplemented(void *param) |
| 1088 | 542 | { |
| 1089 | | powerpc_state *ppc = (powerpc_state *)param; |
| 1090 | | UINT32 opcode = ppc->impstate->arg0; |
| 1091 | | fatalerror("PC=%08X: Unimplemented op %08X\n", ppc->pc, opcode); |
| 543 | ppc_device *ppc = (ppc_device *)param; |
| 544 | ppc->ppc_cfunc_unimplemented(); |
| 1092 | 545 | } |
| 1093 | 546 | |
| 547 | void ppc_device::ppc_cfunc_unimplemented() |
| 548 | { |
| 549 | UINT32 opcode = m_core->arg0; |
| 550 | fatalerror("PC=%08X: Unimplemented op %08X\n", m_core->pc, opcode); |
| 551 | } |
| 1094 | 552 | |
| 553 | static void cfunc_ppccom_tlb_fill(void *param) |
| 554 | { |
| 555 | ppc_device *ppc = (ppc_device *)param; |
| 556 | ppc->ppccom_tlb_fill(); |
| 557 | } |
| 1095 | 558 | |
| 559 | static void cfunc_ppccom_update_fprf(void *param) |
| 560 | { |
| 561 | ppc_device *ppc = (ppc_device *)param; |
| 562 | ppc->ppccom_update_fprf(); |
| 563 | } |
| 564 | |
| 565 | static void cfunc_ppccom_dcstore_callback(void *param) |
| 566 | { |
| 567 | ppc_device *ppc = (ppc_device *)param; |
| 568 | ppc->ppccom_dcstore_callback(); |
| 569 | } |
| 570 | |
| 571 | static void cfunc_ppccom_execute_tlbie(void *param) |
| 572 | { |
| 573 | ppc_device *ppc = (ppc_device *)param; |
| 574 | ppc->ppccom_execute_tlbie(); |
| 575 | } |
| 576 | |
| 577 | static void cfunc_ppccom_execute_tlbia(void *param) |
| 578 | { |
| 579 | ppc_device *ppc = (ppc_device *)param; |
| 580 | ppc->ppccom_execute_tlbia(); |
| 581 | } |
| 582 | |
| 583 | static void cfunc_ppccom_execute_tlbl(void *param) |
| 584 | { |
| 585 | ppc_device *ppc = (ppc_device *)param; |
| 586 | ppc->ppccom_execute_tlbl(); |
| 587 | } |
| 588 | |
| 589 | static void cfunc_ppccom_execute_mfspr(void *param) |
| 590 | { |
| 591 | ppc_device *ppc = (ppc_device *)param; |
| 592 | ppc->ppccom_execute_mfspr(); |
| 593 | } |
| 594 | |
| 595 | static void cfunc_ppccom_execute_mftb(void *param) |
| 596 | { |
| 597 | ppc_device *ppc = (ppc_device *)param; |
| 598 | ppc->ppccom_execute_mftb(); |
| 599 | } |
| 600 | |
| 601 | static void cfunc_ppccom_execute_mtspr(void *param) |
| 602 | { |
| 603 | ppc_device *ppc = (ppc_device *)param; |
| 604 | ppc->ppccom_execute_mtspr(); |
| 605 | } |
| 606 | |
| 607 | static void cfunc_ppccom_tlb_flush(void *param) |
| 608 | { |
| 609 | ppc_device *ppc = (ppc_device *)param; |
| 610 | ppc->ppccom_tlb_flush(); |
| 611 | } |
| 612 | |
| 613 | static void cfunc_ppccom_execute_mfdcr(void *param) |
| 614 | { |
| 615 | ppc_device *ppc = (ppc_device *)param; |
| 616 | ppc->ppccom_execute_mfdcr(); |
| 617 | } |
| 618 | |
| 619 | static void cfunc_ppccom_execute_mtdcr(void *param) |
| 620 | { |
| 621 | ppc_device *ppc = (ppc_device *)param; |
| 622 | ppc->ppccom_execute_mtdcr(); |
| 623 | } |
| 624 | |
| 625 | |
| 1096 | 626 | /*************************************************************************** |
| 1097 | 627 | STATIC CODEGEN |
| 1098 | 628 | ***************************************************************************/ |
| r31142 | r31143 | |
| 1102 | 632 | static entry point |
| 1103 | 633 | -------------------------------------------------*/ |
| 1104 | 634 | |
| 1105 | | static void static_generate_entry_point(powerpc_state *ppc) |
| 635 | void ppc_device::static_generate_entry_point() |
| 1106 | 636 | { |
| 1107 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1108 | 637 | code_label skip = 1; |
| 1109 | 638 | drcuml_block *block; |
| 1110 | 639 | |
| 1111 | 640 | /* begin generating */ |
| 1112 | | block = drcuml->begin_block(20); |
| 641 | block = m_drcuml->begin_block(20); |
| 1113 | 642 | |
| 1114 | 643 | /* forward references */ |
| 1115 | | alloc_handle(drcuml, &ppc->impstate->nocode, "nocode"); |
| 1116 | | alloc_handle(drcuml, &ppc->impstate->exception_norecover[EXCEPTION_EI], "exception_ei_norecover"); |
| 644 | alloc_handle(m_drcuml, &m_nocode, "nocode"); |
| 645 | alloc_handle(m_drcuml, &m_exception_norecover[EXCEPTION_EI], "exception_ei_norecover"); |
| 1117 | 646 | |
| 1118 | | alloc_handle(drcuml, &ppc->impstate->entry, "entry"); |
| 1119 | | UML_HANDLE(block, *ppc->impstate->entry); // handle entry |
| 647 | alloc_handle(m_drcuml, &m_entry, "entry"); |
| 648 | UML_HANDLE(block, *m_entry); // handle entry |
| 1120 | 649 | |
| 1121 | 650 | /* reset the FPU mode */ |
| 1122 | 651 | UML_AND(block, I0, FPSCR32, 3); // and i0,fpscr,3 |
| 1123 | | UML_LOAD(block, I0, &ppc->impstate->fpmode[0], I0, SIZE_BYTE, SCALE_x1); // load i0,fpmode,i0,byte |
| 652 | UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1); // load i0,fpmode,i0,byte |
| 1124 | 653 | UML_SETFMOD(block, I0); // setfmod i0 |
| 1125 | 654 | |
| 1126 | 655 | /* load fast integer registers */ |
| 1127 | | load_fast_iregs(ppc, block); // <load fastregs> |
| 656 | load_fast_iregs(block); // <load fastregs> |
| 1128 | 657 | |
| 1129 | 658 | /* check for interrupts */ |
| 1130 | | UML_TEST(block, mem(&ppc->irq_pending), ~0); // test [irq_pending],0 |
| 659 | UML_TEST(block, mem(&m_core->irq_pending), ~0); // test [irq_pending],0 |
| 1131 | 660 | UML_JMPc(block, COND_Z, skip); // jmp skip,Z |
| 1132 | 661 | UML_TEST(block, MSR32, MSR_EE); // test msr,MSR_EE |
| 1133 | 662 | UML_JMPc(block, COND_Z, skip); // jmp skip,Z |
| 1134 | | UML_MOV(block, I0, mem(&ppc->pc)); // mov i0,pc |
| 663 | UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc |
| 1135 | 664 | UML_MOV(block, I1, 0); // mov i1,0 |
| 1136 | | UML_CALLH(block, *ppc->impstate->exception_norecover[EXCEPTION_EI]); // callh exception_norecover |
| 665 | UML_CALLH(block, *m_exception_norecover[EXCEPTION_EI]); // callh exception_norecover |
| 1137 | 666 | UML_LABEL(block, skip); // skip: |
| 1138 | 667 | |
| 1139 | 668 | /* generate a hash jump via the current mode and PC */ |
| 1140 | | UML_HASHJMP(block, mem(&ppc->impstate->mode), mem(&ppc->pc), *ppc->impstate->nocode); // hashjmp <mode>,<pc>,nocode |
| 669 | UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode |
| 1141 | 670 | |
| 1142 | 671 | block->end(); |
| 1143 | 672 | } |
| r31142 | r31143 | |
| 1148 | 677 | exception handler for "out of code" |
| 1149 | 678 | -------------------------------------------------*/ |
| 1150 | 679 | |
| 1151 | | static void static_generate_nocode_handler(powerpc_state *ppc) |
| 680 | void ppc_device::static_generate_nocode_handler() |
| 1152 | 681 | { |
| 1153 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1154 | 682 | drcuml_block *block; |
| 1155 | 683 | |
| 1156 | 684 | /* begin generating */ |
| 1157 | | block = drcuml->begin_block(10); |
| 685 | block = m_drcuml->begin_block(10); |
| 1158 | 686 | |
| 1159 | 687 | /* generate a hash jump via the current mode and PC */ |
| 1160 | | alloc_handle(drcuml, &ppc->impstate->nocode, "nocode"); |
| 1161 | | UML_HANDLE(block, *ppc->impstate->nocode); // handle nocode |
| 688 | alloc_handle(m_drcuml, &m_nocode, "nocode"); |
| 689 | UML_HANDLE(block, *m_nocode); // handle nocode |
| 1162 | 690 | UML_GETEXP(block, I0); // getexp i0 |
| 1163 | | UML_MOV(block, mem(&ppc->pc), I0); // mov [pc],i0 |
| 1164 | | save_fast_iregs(ppc, block); // <save fastregs> |
| 691 | UML_MOV(block, mem(&m_core->pc), I0); // mov [pc],i0 |
| 692 | save_fast_iregs(block); // <save fastregs> |
| 1165 | 693 | UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE |
| 1166 | 694 | |
| 1167 | 695 | block->end(); |
| r31142 | r31143 | |
| 1173 | 701 | out of cycles exception handler |
| 1174 | 702 | -------------------------------------------------*/ |
| 1175 | 703 | |
| 1176 | | static void static_generate_out_of_cycles(powerpc_state *ppc) |
| 704 | void ppc_device::static_generate_out_of_cycles() |
| 1177 | 705 | { |
| 1178 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1179 | 706 | drcuml_block *block; |
| 1180 | 707 | |
| 1181 | 708 | /* begin generating */ |
| 1182 | | block = drcuml->begin_block(10); |
| 709 | block = m_drcuml->begin_block(10); |
| 1183 | 710 | |
| 1184 | 711 | /* generate a hash jump via the current mode and PC */ |
| 1185 | | alloc_handle(drcuml, &ppc->impstate->out_of_cycles, "out_of_cycles"); |
| 1186 | | UML_HANDLE(block, *ppc->impstate->out_of_cycles); // handle out_of_cycles |
| 712 | alloc_handle(m_drcuml, &m_out_of_cycles, "out_of_cycles"); |
| 713 | UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles |
| 1187 | 714 | UML_GETEXP(block, I0); // getexp i0 |
| 1188 | | UML_MOV(block, mem(&ppc->pc), I0); // mov <pc>,i0 |
| 1189 | | save_fast_iregs(ppc, block); // <save fastregs> |
| 715 | UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0 |
| 716 | save_fast_iregs(block); // <save fastregs> |
| 1190 | 717 | UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES |
| 1191 | 718 | |
| 1192 | 719 | block->end(); |
| r31142 | r31143 | |
| 1198 | 725 | TLB mismatch handler |
| 1199 | 726 | -------------------------------------------------*/ |
| 1200 | 727 | |
| 1201 | | static void static_generate_tlb_mismatch(powerpc_state *ppc) |
| 728 | void ppc_device::static_generate_tlb_mismatch() |
| 1202 | 729 | { |
| 1203 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1204 | 730 | drcuml_block *block; |
| 1205 | 731 | int isi, exit, label = 1; |
| 1206 | 732 | |
| 1207 | 733 | /* forward references */ |
| 1208 | | alloc_handle(drcuml, &ppc->impstate->exception[EXCEPTION_ISI], "exception_isi"); |
| 1209 | | if (ppc->cap & PPCCAP_603_MMU) |
| 1210 | | alloc_handle(drcuml, &ppc->impstate->exception[EXCEPTION_ITLBMISS], "exception_itlb_miss"); |
| 734 | alloc_handle(m_drcuml, &m_exception[EXCEPTION_ISI], "exception_isi"); |
| 735 | if (m_cap & PPCCAP_603_MMU) |
| 736 | alloc_handle(m_drcuml, &m_exception[EXCEPTION_ITLBMISS], "exception_itlb_miss"); |
| 1211 | 737 | |
| 1212 | 738 | /* begin generating */ |
| 1213 | | block = drcuml->begin_block(20); |
| 739 | block = m_drcuml->begin_block(20); |
| 1214 | 740 | |
| 1215 | 741 | /* generate a hash jump via the current mode and PC */ |
| 1216 | | alloc_handle(drcuml, &ppc->impstate->tlb_mismatch, "tlb_mismatch"); |
| 1217 | | UML_HANDLE(block, *ppc->impstate->tlb_mismatch); // handle tlb_mismatch |
| 742 | alloc_handle(m_drcuml, &m_tlb_mismatch, "tlb_mismatch"); |
| 743 | UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch |
| 1218 | 744 | UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC |
| 1219 | 745 | UML_SHR(block, I1, I0, 12); // shr i1,i0,12 |
| 1220 | | UML_LOAD(block, I2, (void *)vtlb_table(ppc->vtlb), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword |
| 1221 | | UML_MOV(block, mem(&ppc->param0), I0); // mov [param0],i0 |
| 1222 | | UML_MOV(block, mem(&ppc->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH |
| 1223 | | UML_CALLC(block, (c_function)ppccom_tlb_fill, ppc); // callc tlbfill,ppc |
| 1224 | | UML_LOAD(block, I1, (void *)vtlb_table(ppc->vtlb), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword |
| 746 | UML_LOAD(block, I2, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword |
| 747 | UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 |
| 748 | UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH |
| 749 | UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc |
| 750 | UML_LOAD(block, I1, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword |
| 1225 | 751 | UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED |
| 1226 | 752 | UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z |
| 1227 | 753 | UML_CMP(block, I2, 0); // cmp i2,0 |
| 1228 | 754 | UML_JMPc(block, COND_NZ, exit = label++); // jmp exit,nz |
| 1229 | | UML_HASHJMP(block, mem(&ppc->impstate->mode), I0, *ppc->impstate->nocode); // hashjmp <mode>,i0,nocode |
| 755 | UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp <mode>,i0,nocode |
| 1230 | 756 | UML_LABEL(block, exit); // exit: |
| 1231 | | UML_MOV(block, mem(&ppc->pc), I0); // mov <pc>,i0 |
| 1232 | | save_fast_iregs(ppc, block); // <save fastregs> |
| 757 | UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0 |
| 758 | save_fast_iregs(block); // <save fastregs> |
| 1233 | 759 | UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE |
| 1234 | 760 | UML_LABEL(block, isi); // isi: |
| 1235 | | if (!(ppc->cap & PPCCAP_603_MMU)) |
| 761 | if (!(m_cap & PPCCAP_603_MMU)) |
| 1236 | 762 | { |
| 1237 | | UML_MOV(block, SPR32(SPROEA_DSISR), mem(&ppc->param0)); // mov [dsisr],[param0] |
| 1238 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_ISI], I0); // exh isi,i0 |
| 763 | UML_MOV(block, SPR32(SPROEA_DSISR), mem(&m_core->param0)); // mov [dsisr],[param0] |
| 764 | UML_EXH(block, *m_exception[EXCEPTION_ISI], I0); // exh isi,i0 |
| 1239 | 765 | } |
| 1240 | 766 | else |
| 1241 | 767 | { |
| 1242 | 768 | UML_MOV(block, SPR32(SPR603_IMISS), I0); // mov [imiss],i0 |
| 1243 | | UML_MOV(block, SPR32(SPR603_ICMP), mem(&ppc->mmu603_cmp)); // mov [icmp],[mmu603_cmp] |
| 1244 | | UML_MOV(block, SPR32(SPR603_HASH1), mem(&ppc->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] |
| 1245 | | UML_MOV(block, SPR32(SPR603_HASH2), mem(&ppc->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] |
| 1246 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_ITLBMISS], I0); // exh itlbmiss,i0 |
| 769 | UML_MOV(block, SPR32(SPR603_ICMP), mem(&m_core->mmu603_cmp)); // mov [icmp],[mmu603_cmp] |
| 770 | UML_MOV(block, SPR32(SPR603_HASH1), mem(&m_core->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] |
| 771 | UML_MOV(block, SPR32(SPR603_HASH2), mem(&m_core->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] |
| 772 | UML_EXH(block, *m_exception[EXCEPTION_ITLBMISS], I0); // exh itlbmiss,i0 |
| 1247 | 773 | } |
| 1248 | 774 | |
| 1249 | 775 | block->end(); |
| r31142 | r31143 | |
| 1255 | 781 | exception handler |
| 1256 | 782 | -------------------------------------------------*/ |
| 1257 | 783 | |
| 1258 | | static void static_generate_exception(powerpc_state *ppc, UINT8 exception, int recover, const char *name) |
| 784 | void ppc_device::static_generate_exception(UINT8 exception, int recover, const char *name) |
| 1259 | 785 | { |
| 1260 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1261 | | code_handle *&exception_handle = recover ? ppc->impstate->exception[exception] : ppc->impstate->exception_norecover[exception]; |
| 786 | code_handle *&exception_handle = recover ? m_exception[exception] : m_exception_norecover[exception]; |
| 1262 | 787 | UINT32 vector = exception << 8; |
| 1263 | 788 | code_label label = 1; |
| 1264 | 789 | drcuml_block *block; |
| 1265 | 790 | |
| 1266 | 791 | /* begin generating */ |
| 1267 | | block = drcuml->begin_block(1024); |
| 792 | block = m_drcuml->begin_block(1024); |
| 1268 | 793 | |
| 1269 | 794 | /* add a global entry for this */ |
| 1270 | | alloc_handle(drcuml, &exception_handle, name); |
| 795 | alloc_handle(m_drcuml, &exception_handle, name); |
| 1271 | 796 | UML_HANDLE(block, *exception_handle); // handle name |
| 1272 | 797 | |
| 1273 | 798 | /* exception parameter is expected to be the fault address in this case */ |
| r31142 | r31143 | |
| 1285 | 810 | } |
| 1286 | 811 | |
| 1287 | 812 | /* OEA handling of SRR exceptions */ |
| 1288 | | if (ppc->cap & PPCCAP_OEA) |
| 813 | if (m_cap & PPCCAP_OEA) |
| 1289 | 814 | { |
| 1290 | 815 | UINT32 msrandmask = MSROEA_POW | MSR_EE | MSR_PR | MSROEA_FP | MSROEA_FE0 | MSROEA_SE | MSROEA_BE | MSROEA_FE1 | MSROEA_IR | MSROEA_DR | MSROEA_RI | MSR_LE; |
| 1291 | 816 | UINT32 msrormask = 0; |
| r31142 | r31143 | |
| 1296 | 821 | { |
| 1297 | 822 | code_label not_decrementer; |
| 1298 | 823 | |
| 1299 | | UML_TEST(block, mem(&ppc->irq_pending), 0x01); // test [irq_pending],0x01 |
| 824 | UML_TEST(block, mem(&m_core->irq_pending), 0x01); // test [irq_pending],0x01 |
| 1300 | 825 | UML_JMPc(block, COND_NZ, not_decrementer = label++); // jmp not_decrementer,nz |
| 1301 | 826 | UML_MOV(block, I3, EXCEPTION_DECREMENT << 8); // mov i3,EXCEPTION_DECREMENT << 8 |
| 1302 | | UML_AND(block, mem(&ppc->irq_pending), mem(&ppc->irq_pending), ~0x02); // and [irq_pending],[irq_pending],~0x02 |
| 827 | UML_AND(block, mem(&m_core->irq_pending), mem(&m_core->irq_pending), ~0x02); // and [irq_pending],[irq_pending],~0x02 |
| 1303 | 828 | UML_LABEL(block, not_decrementer); // not_decrementer: |
| 1304 | 829 | } |
| 1305 | 830 | |
| r31142 | r31143 | |
| 1313 | 838 | UML_GETEXP(block, I1); // getexp i1 |
| 1314 | 839 | UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), I1); // or [srr1],[srr1],i1 |
| 1315 | 840 | } |
| 1316 | | if (ppc->cap & PPCCAP_603_MMU) |
| 841 | if (m_cap & PPCCAP_603_MMU) |
| 1317 | 842 | { |
| 1318 | 843 | if (exception == EXCEPTION_ITLBMISS) |
| 1319 | 844 | UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), 0x00040000); // or [srr1],0x00040000 |
| r31142 | r31143 | |
| 1324 | 849 | } |
| 1325 | 850 | |
| 1326 | 851 | /* update MSR */ |
| 1327 | | if (ppc->cap & PPCCAP_603_MMU) |
| 852 | if (m_cap & PPCCAP_603_MMU) |
| 1328 | 853 | { |
| 1329 | 854 | if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) |
| 1330 | 855 | msrormask |= MSR603_TGPR; |
| r31142 | r31143 | |
| 1336 | 861 | UML_OR(block, I2, I2, msrormask); // or i2,i2,ormask |
| 1337 | 862 | UML_ROLINS(block, I2, I2, 16, MSR_LE); // rolins i2,u2,16,MSR_LE |
| 1338 | 863 | UML_MOV(block, MSR32, I2); // mov [msr],i2 |
| 1339 | | if (ppc->cap & PPCCAP_603_MMU) |
| 864 | if (m_cap & PPCCAP_603_MMU) |
| 1340 | 865 | { |
| 1341 | 866 | UML_XOR(block, I0, I0, I2); // xor i0,i0,i2 |
| 1342 | 867 | UML_TEST(block, I0, MSR603_TGPR); // test i0,tgpr |
| 1343 | | UML_CALLHc(block, COND_NZ, *ppc->impstate->swap_tgpr); // callh swap_tgpr,nz |
| 868 | UML_CALLHc(block, COND_NZ, *m_swap_tgpr); // callh swap_tgpr,nz |
| 1344 | 869 | } |
| 1345 | | generate_update_mode(ppc, block); // <update mode> |
| 870 | generate_update_mode(block); // <update mode> |
| 1346 | 871 | |
| 1347 | 872 | /* determine our target PC */ |
| 1348 | | if (ppc->flavor == PPC_MODEL_602) |
| 873 | if (m_flavor == PPC_MODEL_602) |
| 1349 | 874 | UML_MOV(block, I0, SPR32(SPR602_IBR)); // mov i0,[ibr] |
| 1350 | 875 | else |
| 1351 | 876 | UML_MOV(block, I0, 0x00000000); // mov i0,0x00000000 |
| r31142 | r31143 | |
| 1355 | 880 | } |
| 1356 | 881 | |
| 1357 | 882 | /* 4XX handling of exceptions */ |
| 1358 | | if (ppc->cap & PPCCAP_4XX) |
| 883 | if (m_cap & PPCCAP_4XX) |
| 1359 | 884 | { |
| 1360 | 885 | /* check registers to see the real source of our exception (EI exceptions only) */ |
| 1361 | 886 | UML_MOV(block, I3, vector); // mov i3,vector |
| r31142 | r31143 | |
| 1397 | 922 | /* finish updating MSR */ |
| 1398 | 923 | UML_ROLINS(block, I2, I2, 16, MSR_LE); // rolins i2,u2,16,MSR_LE |
| 1399 | 924 | UML_MOV(block, MSR32, I2); // mov [msr],i2 |
| 1400 | | generate_update_mode(ppc, block); // <update mode> |
| 925 | generate_update_mode(block); // <update mode> |
| 1401 | 926 | |
| 1402 | 927 | /* program exception flags go to ESR */ |
| 1403 | 928 | if (exception == EXCEPTION_PROGRAM) |
| r31142 | r31143 | |
| 1415 | 940 | if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_EI && exception != EXCEPTION_SYSCALL) || |
| 1416 | 941 | (PRINTF_MMU && (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI))) |
| 1417 | 942 | { |
| 1418 | | UML_MOV(block, mem(&ppc->param0), exception); // mov [param0],exception |
| 1419 | | UML_CALLC(block, cfunc_printf_exception, ppc); // callc cfunc_printf_exception,ppc |
| 943 | UML_MOV(block, mem(&m_core->param0), exception); // mov [param0],exception |
| 944 | UML_CALLC(block, cfunc_printf_exception, this); // callc cfunc_printf_exception,ppc |
| 1420 | 945 | } |
| 1421 | 946 | |
| 1422 | 947 | /* adjust cycles */ |
| 1423 | | UML_SUB(block, mem(&ppc->icount), mem(&ppc->icount), I1); // sub icount,icount,cycles |
| 1424 | | UML_EXHc(block, COND_S, *ppc->impstate->out_of_cycles, I0); // exh out_of_cycles,i0 |
| 1425 | | UML_HASHJMP(block, mem(&ppc->impstate->mode), I0, *ppc->impstate->nocode); // hashjmp <mode>,i0,nocode |
| 948 | UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I1); // sub icount,icount,cycles |
| 949 | UML_EXHc(block, COND_S, *m_out_of_cycles, I0); // exh out_of_cycles,i0 |
| 950 | UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp <mode>,i0,nocode |
| 1426 | 951 | |
| 1427 | 952 | block->end(); |
| 1428 | 953 | } |
| r31142 | r31143 | |
| 1432 | 957 | static_generate_memory_accessor |
| 1433 | 958 | ------------------------------------------------------------------*/ |
| 1434 | 959 | |
| 1435 | | static void static_generate_memory_accessor(powerpc_state *ppc, int mode, int size, int iswrite, int ismasked, const char *name, code_handle *&handleptr, code_handle *masked) |
| 960 | void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, code_handle *&handleptr, code_handle *masked) |
| 1436 | 961 | { |
| 1437 | 962 | /* on entry, address is in I0; data for writes is in I1; masks are in I2 */ |
| 1438 | 963 | /* on exit, read result is in I0 */ |
| 1439 | 964 | /* routine trashes I0-I3 */ |
| 1440 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1441 | | int fastxor = BYTE8_XOR_BE(0) >> (int)(ppc->device->space_config(AS_PROGRAM)->m_databus_width < 64); |
| 965 | int fastxor = BYTE8_XOR_BE(0) >> (int)(space_config(AS_PROGRAM)->m_databus_width < 64); |
| 1442 | 966 | drcuml_block *block; |
| 1443 | 967 | int translate_type; |
| 1444 | 968 | int tlbreturn = 0; |
| r31142 | r31143 | |
| 1454 | 978 | translate_type = iswrite ? TRANSLATE_WRITE : TRANSLATE_READ; |
| 1455 | 979 | |
| 1456 | 980 | /* begin generating */ |
| 1457 | | block = drcuml->begin_block(1024); |
| 981 | block = m_drcuml->begin_block(1024); |
| 1458 | 982 | |
| 1459 | 983 | /* add a global entry for this */ |
| 1460 | | alloc_handle(drcuml, &handleptr, name); |
| 984 | alloc_handle(m_drcuml, &handleptr, name); |
| 1461 | 985 | UML_HANDLE(block, *handleptr); // handle *handleptr |
| 1462 | 986 | |
| 1463 | 987 | /* check for unaligned accesses and break into two */ |
| 1464 | 988 | if (!ismasked && size != 1) |
| 1465 | 989 | { |
| 1466 | 990 | /* in little-endian mode, anything misaligned generates an exception */ |
| 1467 | | if ((mode & MODE_LITTLE_ENDIAN) || masked == NULL || !(ppc->cap & PPCCAP_MISALIGNED)) |
| 991 | if ((mode & MODE_LITTLE_ENDIAN) || masked == NULL || !(m_cap & PPCCAP_MISALIGNED)) |
| 1468 | 992 | { |
| 1469 | 993 | UML_TEST(block, I0, size - 1); // test i0,size-1 |
| 1470 | 994 | UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz |
| r31142 | r31143 | |
| 1494 | 1018 | } |
| 1495 | 1019 | |
| 1496 | 1020 | /* general case: assume paging and perform a translation */ |
| 1497 | | if (((ppc->cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) || (iswrite && (ppc->cap & PPCCAP_4XX) && (mode & MODE_PROTECTION))) |
| 1021 | if (((m_cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) || (iswrite && (m_cap & PPCCAP_4XX) && (mode & MODE_PROTECTION))) |
| 1498 | 1022 | { |
| 1499 | 1023 | UML_SHR(block, I3, I0, 12); // shr i3,i0,12 |
| 1500 | | UML_LOAD(block, I3, (void *)vtlb_table(ppc->vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword |
| 1024 | UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword |
| 1501 | 1025 | UML_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type |
| 1502 | 1026 | UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z |
| 1503 | 1027 | UML_LABEL(block, tlbreturn = label++); // tlbreturn: |
| 1504 | 1028 | UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000 |
| 1505 | 1029 | } |
| 1506 | | else if (ppc->cap & PPCCAP_4XX) |
| 1030 | else if (m_cap & PPCCAP_4XX) |
| 1507 | 1031 | UML_AND(block, I0, I0, 0x7fffffff); // and i0,i0,0x7fffffff |
| 1508 | 1032 | UML_XOR(block, I0, I0, (mode & MODE_LITTLE_ENDIAN) ? (8 - size) : 0); // xor i0,i0,8-size |
| 1509 | 1033 | |
| 1510 | | if ((ppc->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 1034 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 1511 | 1035 | for (ramnum = 0; ramnum < PPC_MAX_FASTRAM; ramnum++) |
| 1512 | | if (ppc->impstate->fastram[ramnum].base != NULL && (!iswrite || !ppc->impstate->fastram[ramnum].readonly)) |
| 1036 | if (m_fastram[ramnum].base != NULL && (!iswrite || !m_fastram[ramnum].readonly)) |
| 1513 | 1037 | { |
| 1514 | | void *fastbase = (UINT8 *)ppc->impstate->fastram[ramnum].base - ppc->impstate->fastram[ramnum].start; |
| 1038 | void *fastbase = (UINT8 *)m_fastram[ramnum].base - m_fastram[ramnum].start; |
| 1515 | 1039 | UINT32 skip = label++; |
| 1516 | 1040 | |
| 1517 | | if (ppc->impstate->fastram[ramnum].end != 0xffffffff) |
| 1041 | if (m_fastram[ramnum].end != 0xffffffff) |
| 1518 | 1042 | { |
| 1519 | | UML_CMP(block, I0, ppc->impstate->fastram[ramnum].end); // cmp i0,end |
| 1043 | UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end |
| 1520 | 1044 | UML_JMPc(block, COND_A, skip); // ja skip |
| 1521 | 1045 | } |
| 1522 | | if (ppc->impstate->fastram[ramnum].start != 0x00000000) |
| 1046 | if (m_fastram[ramnum].start != 0x00000000) |
| 1523 | 1047 | { |
| 1524 | | UML_CMP(block, I0, ppc->impstate->fastram[ramnum].start); // cmp i0,fastram_start |
| 1048 | UML_CMP(block, I0, m_fastram[ramnum].start); // cmp i0,fastram_start |
| 1525 | 1049 | UML_JMPc(block, COND_B, skip); // jb skip |
| 1526 | 1050 | } |
| 1527 | 1051 | |
| r31142 | r31143 | |
| 1661 | 1185 | { |
| 1662 | 1186 | if (iswrite) |
| 1663 | 1187 | { |
| 1664 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), I0); // mov [tempaddr],i0 |
| 1665 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), I1); // mov [tempdata],i1 |
| 1188 | UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 |
| 1189 | UML_MOV(block, mem(&m_core->tempdata.w.l), I1); // mov [tempdata],i1 |
| 1666 | 1190 | UML_SUB(block, I0, I0, 1); // sub i0,i0,1 |
| 1667 | 1191 | UML_SHR(block, I1, I1, 8); // shr i1,i1,8 |
| 1668 | 1192 | UML_MOV(block, I2, 0x00ff); // mov i2,0x00ff |
| 1669 | 1193 | UML_CALLH(block, *masked); // callh masked |
| 1670 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 1); // add i0,[tempaddr],1 |
| 1671 | | UML_SHL(block, I1, mem(&ppc->impstate->tempdata.w.l), 8); // shl i1,[tempdata],8 |
| 1194 | UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 |
| 1195 | UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 8); // shl i1,[tempdata],8 |
| 1672 | 1196 | UML_MOV(block, I2, 0xff00); // mov i2,0xff00 |
| 1673 | 1197 | UML_CALLH(block, *masked); // callh masked |
| 1674 | 1198 | } |
| 1675 | 1199 | else |
| 1676 | 1200 | { |
| 1677 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), I0); // mov [tempaddr],i0 |
| 1201 | UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 |
| 1678 | 1202 | UML_SUB(block, I0, I0, 1); // sub i0,i0,1 |
| 1679 | 1203 | UML_MOV(block, I2, 0x00ff); // mov i2,0x00ff |
| 1680 | 1204 | UML_CALLH(block, *masked); // callh masked |
| 1681 | | UML_SHL(block, mem(&ppc->impstate->tempdata.w.l), I0, 8); // shl [tempdata],i0,8 |
| 1682 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 1); // add i0,[tempaddr],1 |
| 1205 | UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 8); // shl [tempdata],i0,8 |
| 1206 | UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 |
| 1683 | 1207 | UML_MOV(block, I2, 0xff00); // mov i2,0xff00 |
| 1684 | 1208 | UML_CALLH(block, *masked); // callh masked |
| 1685 | 1209 | UML_SHR(block, I0, I0, 8); // shr i0,i0,8 |
| 1686 | | UML_OR(block, I0, I0, mem(&ppc->impstate->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1210 | UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1687 | 1211 | } |
| 1688 | 1212 | } |
| 1689 | 1213 | else if (size == 4) |
| r31142 | r31143 | |
| 1691 | 1215 | int offs2, offs3; |
| 1692 | 1216 | if (iswrite) |
| 1693 | 1217 | { |
| 1694 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), I0); // mov [tempaddr],i0 |
| 1695 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), I1); // mov [tempdata],i1 |
| 1218 | UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 |
| 1219 | UML_MOV(block, mem(&m_core->tempdata.w.l), I1); // mov [tempdata],i1 |
| 1696 | 1220 | UML_TEST(block, I0, 2); // test i0,i0,2 |
| 1697 | 1221 | UML_JMPc(block, COND_NZ, offs2 = label++); // jnz offs2 |
| 1698 | 1222 | UML_SUB(block, I0, I0, 1); // sub i0,i0,1 |
| 1699 | 1223 | UML_SHR(block, I1, I1, 8); // shr i1,i1,8 |
| 1700 | 1224 | UML_MOV(block, I2, 0x00ffffff); // mov i2,0x00ffffff |
| 1701 | 1225 | UML_CALLH(block, *masked); // callh masked |
| 1702 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 3); // add i0,[tempaddr],3 |
| 1703 | | UML_SHL(block, I1, mem(&ppc->impstate->tempdata.w.l), 24); // shl i1,[tempdata],24 |
| 1226 | UML_ADD(block, I0, mem(&m_core->tempaddr), 3); // add i0,[tempaddr],3 |
| 1227 | UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 24); // shl i1,[tempdata],24 |
| 1704 | 1228 | UML_MOV(block, I2, 0xff000000); // mov i2,0xff000000 |
| 1705 | 1229 | UML_CALLH(block, *masked); // callh masked |
| 1706 | 1230 | UML_RET(block); // ret |
| r31142 | r31143 | |
| 1711 | 1235 | UML_SHR(block, I1, I1, 16); // shr i1,i1,16 |
| 1712 | 1236 | UML_MOV(block, I2, 0x0000ffff); // mov i2,0x0000ffff |
| 1713 | 1237 | UML_CALLH(block, *masked); // callh masked |
| 1714 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 2); // add i0,[tempaddr],2 |
| 1715 | | UML_SHL(block, I1, mem(&ppc->impstate->tempdata.w.l), 16); // shl i1,[tempdata],16 |
| 1238 | UML_ADD(block, I0, mem(&m_core->tempaddr), 2); // add i0,[tempaddr],2 |
| 1239 | UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 16); // shl i1,[tempdata],16 |
| 1716 | 1240 | UML_MOV(block, I2, 0xffff0000); // mov i2,0xffff0000 |
| 1717 | 1241 | UML_CALLH(block, *masked); // callh masked |
| 1718 | 1242 | UML_RET(block); // ret |
| r31142 | r31143 | |
| 1721 | 1245 | UML_SHR(block, I1, I1, 24); // shr i1,i1,24 |
| 1722 | 1246 | UML_MOV(block, I2, 0x000000ff); // mov i2,0x000000ff |
| 1723 | 1247 | UML_CALLH(block, *masked); // callh masked |
| 1724 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 1); // add i0,[tempaddr],1 |
| 1725 | | UML_SHL(block, I1, mem(&ppc->impstate->tempdata.w.l), 8); // shl i1,[tempdata],8 |
| 1248 | UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 |
| 1249 | UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 8); // shl i1,[tempdata],8 |
| 1726 | 1250 | UML_MOV(block, I2, 0xffffff00); // mov i2,0xffffff00 |
| 1727 | 1251 | UML_CALLH(block, *masked); // callh masked |
| 1728 | 1252 | } |
| 1729 | 1253 | else |
| 1730 | 1254 | { |
| 1731 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), I0); // mov [tempaddr],i0 |
| 1255 | UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 |
| 1732 | 1256 | UML_TEST(block, I0, 2); // test i0,i0,2 |
| 1733 | 1257 | UML_JMPc(block, COND_NZ, offs2 = label++); // jnz offs2 |
| 1734 | 1258 | UML_SUB(block, I0, I0, 1); // sub i0,i0,1 |
| 1735 | 1259 | UML_MOV(block, I2, 0x00ffffff); // mov i2,0x00ffffff |
| 1736 | 1260 | UML_CALLH(block, *masked); // callh masked |
| 1737 | | UML_SHL(block, mem(&ppc->impstate->tempdata.w.l), I0, 8); // shl [tempdata],i0,8 |
| 1738 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 3); // add i0,[tempaddr],3 |
| 1261 | UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 8); // shl [tempdata],i0,8 |
| 1262 | UML_ADD(block, I0, mem(&m_core->tempaddr), 3); // add i0,[tempaddr],3 |
| 1739 | 1263 | UML_MOV(block, I2, 0xff000000); // mov i2,0xff000000 |
| 1740 | 1264 | UML_CALLH(block, *masked); // callh masked |
| 1741 | 1265 | UML_SHR(block, I0, I0, 24); // shr i0,i0,24 |
| 1742 | | UML_OR(block, I0, I0, mem(&ppc->impstate->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1266 | UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1743 | 1267 | UML_RET(block); // ret |
| 1744 | 1268 | UML_LABEL(block, offs2); // offs2: |
| 1745 | 1269 | UML_TEST(block, I0, 1); // test i0,i0,1 |
| r31142 | r31143 | |
| 1747 | 1271 | UML_SUB(block, I0, I0, 2); // sub i0,i0,2 |
| 1748 | 1272 | UML_MOV(block, I2, 0x0000ffff); // mov i2,0x0000ffff |
| 1749 | 1273 | UML_CALLH(block, *masked); // callh masked |
| 1750 | | UML_SHL(block, mem(&ppc->impstate->tempdata.w.l), I0, 16); // shl [tempdata],i0,16 |
| 1751 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 2); // add i0,[tempaddr],2 |
| 1274 | UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 16); // shl [tempdata],i0,16 |
| 1275 | UML_ADD(block, I0, mem(&m_core->tempaddr), 2); // add i0,[tempaddr],2 |
| 1752 | 1276 | UML_MOV(block, I2, 0xffff0000); // mov i2,0xffff0000 |
| 1753 | 1277 | UML_CALLH(block, *masked); // callh masked |
| 1754 | 1278 | UML_SHR(block, I0, I0, 16); // shr i0,i0,16 |
| 1755 | | UML_OR(block, I0, I0, mem(&ppc->impstate->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1279 | UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1756 | 1280 | UML_RET(block); // ret |
| 1757 | 1281 | UML_LABEL(block, offs3); // offs3: |
| 1758 | 1282 | UML_SUB(block, I0, I0, 3); // sub i0,i0,3 |
| 1759 | 1283 | UML_MOV(block, I2, 0x000000ff); // mov i2,0x000000ff |
| 1760 | 1284 | UML_CALLH(block, *masked); // callh masked |
| 1761 | | UML_SHL(block, mem(&ppc->impstate->tempdata.w.l), I0, 24); // shl [tempdata],i0,24 |
| 1762 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 1); // add i0,[tempaddr],1 |
| 1285 | UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 24); // shl [tempdata],i0,24 |
| 1286 | UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 |
| 1763 | 1287 | UML_MOV(block, I2, 0xffffff00); // mov i2,0xffffff00 |
| 1764 | 1288 | UML_CALLH(block, *masked); // callh masked |
| 1765 | 1289 | UML_SHR(block, I0, I0, 8); // shr i0,i0,8 |
| 1766 | | UML_OR(block, I0, I0, mem(&ppc->impstate->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1290 | UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] |
| 1767 | 1291 | } |
| 1768 | 1292 | } |
| 1769 | 1293 | else if (size == 8) |
| 1770 | 1294 | { |
| 1771 | 1295 | if (iswrite) |
| 1772 | 1296 | { |
| 1773 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), I0); // mov [tempaddr],i0 |
| 1774 | | UML_DMOV(block, mem(&ppc->impstate->tempdata.d), I1); // dmov [tempdata],i1 |
| 1297 | UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 |
| 1298 | UML_DMOV(block, mem(&m_core->tempdata.d), I1); // dmov [tempdata],i1 |
| 1775 | 1299 | UML_DSHR(block, I1, I1, 32); // dshr i1,i1,32 |
| 1776 | 1300 | UML_DMOV(block, I2, U64(0x00000000ffffffff)); // dmov i2,0x00000000ffffffff |
| 1777 | 1301 | UML_CALLH(block, *masked); // callh masked |
| 1778 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 4); // add i0,[tempaddr],4 |
| 1779 | | UML_DSHL(block, I1, mem(&ppc->impstate->tempdata.d), 32); // dshl i1,[tempdata],32 |
| 1302 | UML_ADD(block, I0, mem(&m_core->tempaddr), 4); // add i0,[tempaddr],4 |
| 1303 | UML_DSHL(block, I1, mem(&m_core->tempdata.d), 32); // dshl i1,[tempdata],32 |
| 1780 | 1304 | UML_DMOV(block, I2, U64(0xffffffff00000000)); // dmov i2,0xffffffff00000000 |
| 1781 | 1305 | UML_CALLH(block, *masked); // callh masked |
| 1782 | 1306 | } |
| 1783 | 1307 | else |
| 1784 | 1308 | { |
| 1785 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), I0); // mov [tempaddr],i0 |
| 1309 | UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 |
| 1786 | 1310 | UML_DMOV(block, I2, U64(0x00000000ffffffff)); // mov i2,0x00000000ffffffff |
| 1787 | 1311 | UML_CALLH(block, *masked); // callh masked |
| 1788 | | UML_DSHL(block, mem(&ppc->impstate->tempdata.d), I0, 32); // dshl [tempdata],i0,32 |
| 1789 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 4); // add i0,[tempaddr],4 |
| 1312 | UML_DSHL(block, mem(&m_core->tempdata.d), I0, 32); // dshl [tempdata],i0,32 |
| 1313 | UML_ADD(block, I0, mem(&m_core->tempaddr), 4); // add i0,[tempaddr],4 |
| 1790 | 1314 | UML_DMOV(block, I2, U64(0xffffffff00000000)); // dmov i2,0xffffffff00000000 |
| 1791 | 1315 | UML_CALLH(block, *masked); // callh masked |
| 1792 | 1316 | UML_DSHR(block, I0, I0, 32); // dshr i0,i0,32 |
| 1793 | | UML_DOR(block, I0, I0, mem(&ppc->impstate->tempdata.d)); // dor i0,i0,[tempdata] |
| 1317 | UML_DOR(block, I0, I0, mem(&m_core->tempdata.d)); // dor i0,i0,[tempdata] |
| 1794 | 1318 | } |
| 1795 | 1319 | } |
| 1796 | 1320 | UML_RET(block); // ret |
| r31142 | r31143 | |
| 1801 | 1325 | { |
| 1802 | 1326 | UML_LABEL(block, alignex); // alignex: |
| 1803 | 1327 | UML_RECOVER(block, SPR32(SPROEA_DSISR), MAPVAR_DSISR); // recover [dsisr],DSISR |
| 1804 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_ALIGN], I0); // exh align,i0 |
| 1328 | UML_EXH(block, *m_exception[EXCEPTION_ALIGN], I0); // exh align,i0 |
| 1805 | 1329 | } |
| 1806 | 1330 | |
| 1807 | 1331 | /* handle a TLB miss */ |
| 1808 | 1332 | if (tlbmiss != 0) |
| 1809 | 1333 | { |
| 1810 | 1334 | UML_LABEL(block, tlbmiss); // tlbmiss: |
| 1811 | | UML_MOV(block, mem(&ppc->param0), I0); // mov [param0],i0 |
| 1812 | | UML_MOV(block, mem(&ppc->param1), translate_type); // mov [param1],translate_type |
| 1813 | | UML_CALLC(block, (c_function)ppccom_tlb_fill, ppc); // callc tlbfill,ppc |
| 1335 | UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 |
| 1336 | UML_MOV(block, mem(&m_core->param1), translate_type); // mov [param1],translate_type |
| 1337 | UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc |
| 1814 | 1338 | UML_SHR(block, I3, I0, 12); // shr i3,i0,12 |
| 1815 | | UML_LOAD(block, I3, (void *)vtlb_table(ppc->vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword |
| 1339 | UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword |
| 1816 | 1340 | UML_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type |
| 1817 | 1341 | UML_JMPc(block, COND_NZ, tlbreturn); // jmp tlbreturn,nz |
| 1818 | 1342 | |
| 1819 | 1343 | /* 4XX case: protection exception */ |
| 1820 | | if (ppc->cap & PPCCAP_4XX) |
| 1344 | if (m_cap & PPCCAP_4XX) |
| 1821 | 1345 | { |
| 1822 | 1346 | UML_MOV(block, SPR32(SPR4XX_DEAR), I0); // mov [dear],i0 |
| 1823 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_DSI], I0); // exh dsi,i0 |
| 1347 | UML_EXH(block, *m_exception[EXCEPTION_DSI], I0); // exh dsi,i0 |
| 1824 | 1348 | } |
| 1825 | 1349 | |
| 1826 | 1350 | /* 603 case: TLBMISS exception */ |
| 1827 | | else if (ppc->cap & PPCCAP_603_MMU) |
| 1351 | else if (m_cap & PPCCAP_603_MMU) |
| 1828 | 1352 | { |
| 1829 | 1353 | UML_MOV(block, SPR32(SPR603_DMISS), I0); // mov [dmiss],i0 |
| 1830 | | UML_MOV(block, SPR32(SPR603_DCMP), mem(&ppc->mmu603_cmp)); // mov [dcmp],[mmu603_cmp] |
| 1831 | | UML_MOV(block, SPR32(SPR603_HASH1), mem(&ppc->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] |
| 1832 | | UML_MOV(block, SPR32(SPR603_HASH2), mem(&ppc->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] |
| 1354 | UML_MOV(block, SPR32(SPR603_DCMP), mem(&m_core->mmu603_cmp)); // mov [dcmp],[mmu603_cmp] |
| 1355 | UML_MOV(block, SPR32(SPR603_HASH1), mem(&m_core->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] |
| 1356 | UML_MOV(block, SPR32(SPR603_HASH2), mem(&m_core->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] |
| 1833 | 1357 | if (iswrite) |
| 1834 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_DTLBMISSS], I0); // exh dtlbmisss,i0 |
| 1358 | UML_EXH(block, *m_exception[EXCEPTION_DTLBMISSS], I0); // exh dtlbmisss,i0 |
| 1835 | 1359 | else |
| 1836 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_DTLBMISSL], I0); // exh dtlbmissl,i0 |
| 1360 | UML_EXH(block, *m_exception[EXCEPTION_DTLBMISSL], I0); // exh dtlbmissl,i0 |
| 1837 | 1361 | } |
| 1838 | 1362 | |
| 1839 | 1363 | /* general case: DSI exception */ |
| 1840 | 1364 | else |
| 1841 | 1365 | { |
| 1842 | | UML_MOV(block, SPR32(SPROEA_DSISR), mem(&ppc->param0)); // mov [dsisr],[param0] |
| 1843 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_DSI], I0); // exh dsi,i0 |
| 1366 | UML_MOV(block, SPR32(SPROEA_DSISR), mem(&m_core->param0)); // mov [dsisr],[param0] |
| 1367 | UML_EXH(block, *m_exception[EXCEPTION_DSI], I0); // exh dsi,i0 |
| 1844 | 1368 | } |
| 1845 | 1369 | } |
| 1846 | 1370 | |
| r31142 | r31143 | |
| 1853 | 1377 | subroutine to swap GPR0-3 with TGPR0-3 |
| 1854 | 1378 | -------------------------------------------------*/ |
| 1855 | 1379 | |
| 1856 | | static void static_generate_swap_tgpr(powerpc_state *ppc) |
| 1380 | void ppc_device::static_generate_swap_tgpr() |
| 1857 | 1381 | { |
| 1858 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1859 | 1382 | drcuml_block *block; |
| 1860 | 1383 | int regnum; |
| 1861 | 1384 | |
| 1862 | 1385 | /* begin generating */ |
| 1863 | | block = drcuml->begin_block(30); |
| 1386 | block = m_drcuml->begin_block(30); |
| 1864 | 1387 | |
| 1865 | 1388 | /* generate a hash jump via the current mode and PC */ |
| 1866 | | alloc_handle(drcuml, &ppc->impstate->swap_tgpr, "swap_tgpr"); |
| 1867 | | UML_HANDLE(block, *ppc->impstate->swap_tgpr); // handle swap_tgpr |
| 1389 | alloc_handle(m_drcuml, &m_swap_tgpr, "swap_tgpr"); |
| 1390 | UML_HANDLE(block, *m_swap_tgpr); // handle swap_tgpr |
| 1868 | 1391 | for (regnum = 0; regnum < 4; regnum++) |
| 1869 | 1392 | { |
| 1870 | 1393 | UML_MOV(block, I1, R32(regnum)); // mov i1,r[regnum] |
| 1871 | | UML_MOV(block, R32(regnum), mem(&ppc->mmu603_r[regnum])); // mov r[regnum],mmu603_r[regnum] |
| 1872 | | UML_MOV(block, mem(&ppc->mmu603_r[regnum]), I1); // mov mmu603_r[regnum],i1 |
| 1394 | UML_MOV(block, R32(regnum), mem(&m_core->mmu603_r[regnum])); // mov r[regnum],mmu603_r[regnum] |
| 1395 | UML_MOV(block, mem(&m_core->mmu603_r[regnum]), I1); // mov mmu603_r[regnum],i1 |
| 1873 | 1396 | } |
| 1874 | 1397 | UML_RET(block); // ret |
| 1875 | 1398 | |
| r31142 | r31143 | |
| 1883 | 1406 | for each possible register |
| 1884 | 1407 | -------------------------------------------------*/ |
| 1885 | 1408 | |
| 1886 | | static void static_generate_lsw_entries(powerpc_state *ppc, int mode) |
| 1409 | void ppc_device::static_generate_lsw_entries(int mode) |
| 1887 | 1410 | { |
| 1888 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1889 | 1411 | drcuml_block *block; |
| 1890 | 1412 | int regnum; |
| 1891 | 1413 | |
| 1892 | 1414 | /* begin generating */ |
| 1893 | | block = drcuml->begin_block(32 * 30); |
| 1415 | block = m_drcuml->begin_block(32 * 30); |
| 1894 | 1416 | |
| 1895 | 1417 | /* iterate over all possible registers */ |
| 1896 | 1418 | for (regnum = 0; regnum < 32; regnum++) |
| r31142 | r31143 | |
| 1899 | 1421 | |
| 1900 | 1422 | /* allocate a handle */ |
| 1901 | 1423 | sprintf(temp, "lsw%d", regnum); |
| 1902 | | alloc_handle(drcuml, &ppc->impstate->lsw[mode][regnum], temp); |
| 1903 | | UML_HANDLE(block, *ppc->impstate->lsw[mode][regnum]); // handle lsw<regnum> |
| 1424 | alloc_handle(m_drcuml, &m_lsw[mode][regnum], temp); |
| 1425 | UML_HANDLE(block, *m_lsw[mode][regnum]); // handle lsw<regnum> |
| 1904 | 1426 | UML_LABEL(block, regnum); // regnum: |
| 1905 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 0); // add i0,[updateaddr],0 |
| 1906 | | UML_CALLH(block, *ppc->impstate->read8[mode]); // callh read8 |
| 1427 | UML_ADD(block, I0, mem(&m_core->updateaddr), 0); // add i0,[updateaddr],0 |
| 1428 | UML_CALLH(block, *m_read8[mode]); // callh read8 |
| 1907 | 1429 | UML_ROLAND(block, R32(regnum), I0, 24, 0xff000000); // roland reg,i0,24,0xff000000 |
| 1908 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1430 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1909 | 1431 | UML_RETc(block, COND_Z); // ret z |
| 1910 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 1); // add i0,[updateaddr],1 |
| 1911 | | UML_CALLH(block, *ppc->impstate->read8[mode]); // callh read8 |
| 1432 | UML_ADD(block, I0, mem(&m_core->updateaddr), 1); // add i0,[updateaddr],1 |
| 1433 | UML_CALLH(block, *m_read8[mode]); // callh read8 |
| 1912 | 1434 | UML_ROLAND(block, I0, I0, 16, 0x00ff0000); // roland i0,i0,16,0x00ff0000 |
| 1913 | 1435 | UML_OR(block, R32(regnum), R32(regnum), I0); // or reg,i0 |
| 1914 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1436 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1915 | 1437 | UML_RETc(block, COND_Z); // ret z |
| 1916 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 2); // add i0,[updateaddr],2 |
| 1917 | | UML_CALLH(block, *ppc->impstate->read8[mode]); // callh read8 |
| 1438 | UML_ADD(block, I0, mem(&m_core->updateaddr), 2); // add i0,[updateaddr],2 |
| 1439 | UML_CALLH(block, *m_read8[mode]); // callh read8 |
| 1918 | 1440 | UML_ROLAND(block, I0, I0, 8, 0x0000ff00); // roland i0,i0,8,0x0000ff00 |
| 1919 | 1441 | UML_OR(block, R32(regnum), R32(regnum), I0); // or reg,i0 |
| 1920 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1442 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1921 | 1443 | UML_RETc(block, COND_Z); // ret z |
| 1922 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 3); // add i0,[updateaddr],3 |
| 1923 | | UML_ADD(block, mem(&ppc->impstate->updateaddr), I0, 1); // add [updateaddr],i0,1 |
| 1924 | | UML_CALLH(block, *ppc->impstate->read8[mode]); // callh read8 |
| 1444 | UML_ADD(block, I0, mem(&m_core->updateaddr), 3); // add i0,[updateaddr],3 |
| 1445 | UML_ADD(block, mem(&m_core->updateaddr), I0, 1); // add [updateaddr],i0,1 |
| 1446 | UML_CALLH(block, *m_read8[mode]); // callh read8 |
| 1925 | 1447 | UML_ROLAND(block, I0, I0, 0, 0x000000ff); // roland i0,i0,0,0x000000ff |
| 1926 | 1448 | UML_OR(block, R32(regnum), R32(regnum), I0); // or reg,i0 |
| 1927 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1449 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1928 | 1450 | UML_RETc(block, COND_Z); // ret z |
| 1929 | 1451 | UML_JMP(block, (regnum + 1) % 32); // jmp nextreg |
| 1930 | 1452 | } |
| r31142 | r31143 | |
| 1939 | 1461 | for each possible register |
| 1940 | 1462 | -------------------------------------------------*/ |
| 1941 | 1463 | |
| 1942 | | static void static_generate_stsw_entries(powerpc_state *ppc, int mode) |
| 1464 | void ppc_device::static_generate_stsw_entries(int mode) |
| 1943 | 1465 | { |
| 1944 | | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 1945 | 1466 | drcuml_block *block; |
| 1946 | | int regnum; |
| 1947 | 1467 | |
| 1948 | 1468 | /* begin generating */ |
| 1949 | | block = drcuml->begin_block(32 * 30); |
| 1469 | block = m_drcuml->begin_block(32 * 30); |
| 1950 | 1470 | |
| 1951 | 1471 | /* iterate over all possible registers */ |
| 1952 | | for (regnum = 0; regnum < 32; regnum++) |
| 1472 | for (int regnum = 0; regnum < 32; regnum++) |
| 1953 | 1473 | { |
| 1954 | 1474 | char temp[20]; |
| 1955 | 1475 | |
| 1956 | 1476 | /* allocate a handle */ |
| 1957 | 1477 | sprintf(temp, "stsw%d", regnum); |
| 1958 | | alloc_handle(drcuml, &ppc->impstate->stsw[mode][regnum], temp); |
| 1959 | | UML_HANDLE(block, *ppc->impstate->stsw[mode][regnum]); // handle stsw<regnum> |
| 1478 | alloc_handle(m_drcuml, &m_stsw[mode][regnum], temp); |
| 1479 | UML_HANDLE(block, *m_stsw[mode][regnum]); // handle stsw<regnum> |
| 1960 | 1480 | UML_LABEL(block, regnum); // regnum: |
| 1961 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 0); // add i0,[updateaddr],0 |
| 1481 | UML_ADD(block, I0, mem(&m_core->updateaddr), 0); // add i0,[updateaddr],0 |
| 1962 | 1482 | UML_ROLAND(block, I1, R32(regnum), 8, 0xff); // roland i1,regnum,8,0xff |
| 1963 | | UML_CALLH(block, *ppc->impstate->write8[mode]); // callh write8 |
| 1964 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1483 | UML_CALLH(block, *m_write8[mode]); // callh write8 |
| 1484 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1965 | 1485 | UML_RETc(block, COND_Z); // ret z |
| 1966 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 1); // add i0,[updateaddr],1 |
| 1486 | UML_ADD(block, I0, mem(&m_core->updateaddr), 1); // add i0,[updateaddr],1 |
| 1967 | 1487 | UML_ROLAND(block, I1, R32(regnum), 16, 0xff); // roland i1,regnum,16,0xff |
| 1968 | | UML_CALLH(block, *ppc->impstate->write8[mode]); // callh write8 |
| 1969 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1488 | UML_CALLH(block, *m_write8[mode]); // callh write8 |
| 1489 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1970 | 1490 | UML_RETc(block, COND_Z); // ret z |
| 1971 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 2); // add i0,[updateaddr],2 |
| 1491 | UML_ADD(block, I0, mem(&m_core->updateaddr), 2); // add i0,[updateaddr],2 |
| 1972 | 1492 | UML_ROLAND(block, I1, R32(regnum), 24, 0xff); // roland i1,regnum,24,0xff |
| 1973 | | UML_CALLH(block, *ppc->impstate->write8[mode]); // callh write8 |
| 1974 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1493 | UML_CALLH(block, *m_write8[mode]); // callh write8 |
| 1494 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1975 | 1495 | UML_RETc(block, COND_Z); // ret z |
| 1976 | | UML_ADD(block, I0, mem(&ppc->impstate->updateaddr), 3); // add i0,[updateaddr],3 |
| 1977 | | UML_ADD(block, mem(&ppc->impstate->updateaddr), I0, 1); // add [updateaddr],i0,1 |
| 1496 | UML_ADD(block, I0, mem(&m_core->updateaddr), 3); // add i0,[updateaddr],3 |
| 1497 | UML_ADD(block, mem(&m_core->updateaddr), I0, 1); // add [updateaddr],i0,1 |
| 1978 | 1498 | UML_ROLAND(block, I1, R32(regnum), 0, 0xff); // roland i1,regnum,0,0xff |
| 1979 | | UML_CALLH(block, *ppc->impstate->write8[mode]); // callh write8 |
| 1980 | | UML_SUB(block, mem(&ppc->impstate->swcount), mem(&ppc->impstate->swcount), 1); // sub [swcount],[swcount],1 |
| 1499 | UML_CALLH(block, *m_write8[mode]); // callh write8 |
| 1500 | UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 |
| 1981 | 1501 | UML_RETc(block, COND_Z); // ret z |
| 1982 | 1502 | UML_JMP(block, (regnum + 1) % 32); // jmp nextreg |
| 1983 | 1503 | } |
| r31142 | r31143 | |
| 1996 | 1516 | on the MSR |
| 1997 | 1517 | -------------------------------------------------*/ |
| 1998 | 1518 | |
| 1999 | | static void generate_update_mode(powerpc_state *ppc, drcuml_block *block) |
| 1519 | void ppc_device::generate_update_mode(drcuml_block *block) |
| 2000 | 1520 | { |
| 2001 | 1521 | /* LE in bit 0 of mode */ |
| 2002 | 1522 | UML_AND(block, I0, MSR32, MSR_LE); // and i0,msr,MSR_LE |
| 2003 | 1523 | |
| 2004 | 1524 | /* DR (OEA and 403GCX) in bit 1 of mode */ |
| 2005 | | if ((ppc->cap & PPCCAP_OEA) || ppc->flavor == PPC_MODEL_403GCX) |
| 1525 | if ((m_cap & PPCCAP_OEA) || m_flavor == PPC_MODEL_403GCX) |
| 2006 | 1526 | { |
| 2007 | 1527 | UML_ROLAND(block, I1, MSR32, 29, 0x02); // roland i1,[msr],29,0x02 |
| 2008 | 1528 | UML_OR(block, I0, I0, I1); // or i0,i0,i1 |
| 2009 | 1529 | } |
| 2010 | 1530 | |
| 2011 | 1531 | /* (4XX) in bit 1 of mode */ |
| 2012 | | if (ppc->cap & PPCCAP_4XX) |
| 1532 | if (m_cap & PPCCAP_4XX) |
| 2013 | 1533 | { |
| 2014 | 1534 | UML_ROLAND(block, I1, MSR32, 30, 0x02); // roland i1,[msr],30,0x02 |
| 2015 | 1535 | UML_OR(block, I0, I0, I1); // or i0,i0,i1 |
| r31142 | r31143 | |
| 2017 | 1537 | |
| 2018 | 1538 | /* PR in bit 2 of mode */ |
| 2019 | 1539 | UML_ROLAND(block, I1, MSR32, 20, 0x04); // roland i1,[msr],20,0x04 |
| 2020 | | UML_OR(block, mem(&ppc->impstate->mode), I0, I1); // or [mode],i0,i1 |
| 1540 | UML_OR(block, mem(&m_core->mode), I0, I1); // or [mode],i0,i1 |
| 2021 | 1541 | } |
| 2022 | 1542 | |
| 2023 | 1543 | |
| r31142 | r31143 | |
| 2027 | 1547 | an exception if out |
| 2028 | 1548 | -------------------------------------------------*/ |
| 2029 | 1549 | |
| 2030 | | static void generate_update_cycles(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, parameter param, int allow_exception) |
| 1550 | void ppc_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, parameter param, int allow_exception) |
| 2031 | 1551 | { |
| 2032 | 1552 | /* check full interrupts if pending */ |
| 2033 | 1553 | if (compiler->checkints) |
| r31142 | r31143 | |
| 2035 | 1555 | code_label skip; |
| 2036 | 1556 | |
| 2037 | 1557 | compiler->checkints = FALSE; |
| 2038 | | UML_TEST(block, mem(&ppc->irq_pending), ~0); // test [irq_pending],0 |
| 1558 | UML_TEST(block, mem(&m_core->irq_pending), ~0); // test [irq_pending],0 |
| 2039 | 1559 | UML_JMPc(block, COND_Z, skip = compiler->labelnum++); // jmp skip,Z |
| 2040 | 1560 | UML_TEST(block, MSR32, MSR_EE); // test [msr],MSR_EE |
| 2041 | 1561 | UML_JMPc(block, COND_Z, skip); // jmp skip,Z |
| 2042 | 1562 | UML_MOV(block, I0, param); // mov i0,nextpc |
| 2043 | 1563 | UML_MOV(block, I1, compiler->cycles); // mov i1,cycles |
| 2044 | | UML_CALLH(block, *ppc->impstate->exception_norecover[EXCEPTION_EI]); // callh interrupt_norecover |
| 1564 | UML_CALLH(block, *m_exception_norecover[EXCEPTION_EI]); // callh interrupt_norecover |
| 2045 | 1565 | UML_LABEL(block, skip); // skip: |
| 2046 | 1566 | } |
| 2047 | 1567 | |
| 2048 | 1568 | /* account for cycles */ |
| 2049 | 1569 | if (compiler->cycles > 0) |
| 2050 | 1570 | { |
| 2051 | | UML_SUB(block, mem(&ppc->icount), mem(&ppc->icount), MAPVAR_CYCLES); // sub icount,icount,cycles |
| 1571 | UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES); // sub icount,icount,cycles |
| 2052 | 1572 | UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 |
| 2053 | 1573 | if (allow_exception) |
| 2054 | | UML_EXHc(block, COND_S, *ppc->impstate->out_of_cycles, param); // exh out_of_cycles,nextpc |
| 1574 | UML_EXHc(block, COND_S, *m_out_of_cycles, param); // exh out_of_cycles,nextpc |
| 2055 | 1575 | } |
| 2056 | 1576 | compiler->cycles = 0; |
| 2057 | 1577 | } |
| r31142 | r31143 | |
| 2062 | 1582 | validate a sequence of opcodes |
| 2063 | 1583 | -------------------------------------------------*/ |
| 2064 | 1584 | |
| 2065 | | static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) |
| 1585 | void ppc_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) |
| 2066 | 1586 | { |
| 2067 | 1587 | const opcode_desc *curdesc; |
| 2068 | 1588 | if (LOG_UML) |
| 2069 | 1589 | block->append_comment("[Validation for %08X]", seqhead->pc); // comment |
| 2070 | 1590 | |
| 2071 | 1591 | /* loose verify or single instruction: just compare and fail */ |
| 2072 | | if (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next() == NULL) |
| 1592 | if (!(m_drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next() == NULL) |
| 2073 | 1593 | { |
| 2074 | 1594 | if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) |
| 2075 | 1595 | { |
| 2076 | | void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor); |
| 1596 | void *base = m_direct->read_decrypted_ptr(seqhead->physpc, m_codexor); |
| 2077 | 1597 | UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,dword |
| 2078 | 1598 | UML_CMP(block, I0, seqhead->opptr.l[0]); // cmp i0,*opptr |
| 2079 | | UML_EXHc(block, COND_NE, *ppc->impstate->nocode, seqhead->pc); // exne nocode,seqhead->pc |
| 1599 | UML_EXHc(block, COND_NE, *m_nocode, seqhead->pc); // exne nocode,seqhead->pc |
| 2080 | 1600 | } |
| 2081 | 1601 | } |
| 2082 | 1602 | |
| r31142 | r31143 | |
| 2087 | 1607 | for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) |
| 2088 | 1608 | if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 2089 | 1609 | { |
| 2090 | | void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor); |
| 1610 | void *base = m_direct->read_decrypted_ptr(seqhead->physpc, m_codexor); |
| 2091 | 1611 | UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,dword |
| 2092 | 1612 | UML_CMP(block, I0, curdesc->opptr.l[0]); // cmp i0,*opptr |
| 2093 | | UML_EXHc(block, COND_NE, *ppc->impstate->nocode, seqhead->pc); // exne nocode,seqhead->pc |
| 1613 | UML_EXHc(block, COND_NE, *m_nocode, seqhead->pc); // exne nocode,seqhead->pc |
| 2094 | 1614 | } |
| 2095 | 1615 | #else |
| 2096 | 1616 | UINT32 sum = 0; |
| 2097 | | void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor); |
| 1617 | void *base = m_direct->read_decrypted_ptr(seqhead->physpc, m_codexor); |
| 2098 | 1618 | UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,dword |
| 2099 | 1619 | sum += seqhead->opptr.l[0]; |
| 2100 | 1620 | for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) |
| 2101 | 1621 | if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 2102 | 1622 | { |
| 2103 | | base = ppc->direct->read_decrypted_ptr(curdesc->physpc, ppc->codexor); |
| 1623 | base = m_direct->read_decrypted_ptr(curdesc->physpc, m_codexor); |
| 2104 | 1624 | UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword |
| 2105 | 1625 | UML_ADD(block, I0, I0, I1); // add i0,i0,i1 |
| 2106 | 1626 | sum += curdesc->opptr.l[0]; |
| 2107 | 1627 | } |
| 2108 | 1628 | UML_CMP(block, I0, sum); // cmp i0,sum |
| 2109 | | UML_EXHc(block, COND_NE, *ppc->impstate->nocode, seqhead->pc); // exne nocode,seqhead->pc |
| 1629 | UML_EXHc(block, COND_NE, *m_nocode, seqhead->pc); // exne nocode,seqhead->pc |
| 2110 | 1630 | #endif |
| 2111 | 1631 | } |
| 2112 | 1632 | } |
| r31142 | r31143 | |
| 2117 | 1637 | for a single instruction in a sequence |
| 2118 | 1638 | -------------------------------------------------*/ |
| 2119 | 1639 | |
| 2120 | | static void generate_sequence_instruction(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 1640 | void ppc_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2121 | 1641 | { |
| 2122 | 1642 | int hotnum; |
| 2123 | 1643 | |
| r31142 | r31143 | |
| 2133 | 1653 | |
| 2134 | 1654 | /* is this a hotspot? */ |
| 2135 | 1655 | for (hotnum = 0; hotnum < PPC_MAX_HOTSPOTS; hotnum++) |
| 2136 | | if (ppc->impstate->hotspot[hotnum].pc != 0 && desc->pc == ppc->impstate->hotspot[hotnum].pc && desc->opptr.l[0] == ppc->impstate->hotspot[hotnum].opcode) |
| 1656 | if (m_hotspot[hotnum].pc != 0 && desc->pc == m_hotspot[hotnum].pc && desc->opptr.l[0] == m_hotspot[hotnum].opcode) |
| 2137 | 1657 | { |
| 2138 | | compiler->cycles += ppc->impstate->hotspot[hotnum].cycles; |
| 1658 | compiler->cycles += m_hotspot[hotnum].cycles; |
| 2139 | 1659 | break; |
| 2140 | 1660 | } |
| 2141 | 1661 | |
| r31142 | r31143 | |
| 2145 | 1665 | /* if we want a probe, add it here */ |
| 2146 | 1666 | if (desc->pc == PROBE_ADDRESS) |
| 2147 | 1667 | { |
| 2148 | | UML_MOV(block, mem(&ppc->pc), desc->pc); // mov [pc],desc->pc |
| 1668 | UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc |
| 2149 | 1669 | UML_CALLC(block, cfunc_printf_probe, (void *)(FPTR)desc->pc); // callc cfunc_printf_probe,desc->pc |
| 2150 | 1670 | } |
| 2151 | 1671 | |
| 2152 | 1672 | /* if we are debugging, call the debugger */ |
| 2153 | | if ((ppc->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 1673 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 2154 | 1674 | { |
| 2155 | | UML_MOV(block, mem(&ppc->pc), desc->pc); // mov [pc],desc->pc |
| 2156 | | save_fast_iregs(ppc, block); // <save fastregs> |
| 1675 | UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc |
| 1676 | save_fast_iregs(block); // <save fastregs> |
| 2157 | 1677 | UML_DEBUG(block, desc->pc); // debug desc->pc |
| 2158 | 1678 | } |
| 2159 | 1679 | |
| 2160 | 1680 | /* if we hit an unmapped address, fatal error */ |
| 2161 | 1681 | if (desc->flags & OPFLAG_COMPILER_UNMAPPED) |
| 2162 | 1682 | { |
| 2163 | | UML_MOV(block, mem(&ppc->pc), desc->pc); // mov [pc],desc->pc |
| 2164 | | save_fast_iregs(ppc, block); // <save fastregs> |
| 1683 | UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc |
| 1684 | save_fast_iregs(block); // <save fastregs> |
| 2165 | 1685 | UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE |
| 2166 | 1686 | } |
| 2167 | 1687 | |
| r31142 | r31143 | |
| 2171 | 1691 | if (PRINTF_MMU) |
| 2172 | 1692 | { |
| 2173 | 1693 | const char *text = "Compiler page fault @ %08X\n"; |
| 2174 | | UML_MOV(block, mem(&ppc->impstate->format), (FPTR)text); // mov [format],text |
| 2175 | | UML_MOV(block, mem(&ppc->impstate->arg0), desc->pc); // mov [arg0],desc->pc |
| 2176 | | UML_CALLC(block, cfunc_printf_debug, ppc); // callc printf_debug |
| 1694 | UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text |
| 1695 | UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc |
| 1696 | UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug |
| 2177 | 1697 | } |
| 2178 | | UML_EXH(block, *ppc->impstate->tlb_mismatch, 0); // exh tlb_mismatch,0 |
| 1698 | UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 |
| 2179 | 1699 | } |
| 2180 | 1700 | |
| 2181 | 1701 | /* validate our TLB entry at this PC; if we fail, we need to handle it */ |
| 2182 | | if ((desc->flags & OPFLAG_VALIDATE_TLB) && (ppc->impstate->mode & MODE_DATA_TRANSLATION)) |
| 1702 | if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION)) |
| 2183 | 1703 | { |
| 2184 | | const vtlb_entry *tlbtable = vtlb_table(ppc->vtlb); |
| 1704 | const vtlb_entry *tlbtable = vtlb_table(m_vtlb); |
| 2185 | 1705 | |
| 2186 | 1706 | /* if we currently have a valid TLB read entry, we just verify */ |
| 2187 | 1707 | if (tlbtable[desc->pc >> 12] != 0) |
| r31142 | r31143 | |
| 2189 | 1709 | if (PRINTF_MMU) |
| 2190 | 1710 | { |
| 2191 | 1711 | const char *text = "Checking TLB at @ %08X\n"; |
| 2192 | | UML_MOV(block, mem(&ppc->impstate->format), (FPTR)text); // mov [format],text |
| 2193 | | UML_MOV(block, mem(&ppc->impstate->arg0), desc->pc); // mov [arg0],desc->pc |
| 2194 | | UML_CALLC(block, cfunc_printf_debug, ppc); // callc printf_debug |
| 1712 | UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text |
| 1713 | UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc |
| 1714 | UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug |
| 2195 | 1715 | } |
| 2196 | 1716 | UML_LOAD(block, I0, &tlbtable[desc->pc >> 12], 0, SIZE_DWORD, SCALE_x4);// load i0,tlbtable[desc->pc >> 12],dword |
| 2197 | 1717 | UML_CMP(block, I0, tlbtable[desc->pc >> 12]); // cmp i0,*tlbentry |
| 2198 | | UML_EXHc(block, COND_NE, *ppc->impstate->tlb_mismatch, 0); // exh tlb_mismatch,0,NE |
| 1718 | UML_EXHc(block, COND_NE, *m_tlb_mismatch, 0); // exh tlb_mismatch,0,NE |
| 2199 | 1719 | } |
| 2200 | 1720 | |
| 2201 | 1721 | /* otherwise, we generate an unconditional exception */ |
| r31142 | r31143 | |
| 2204 | 1724 | if (PRINTF_MMU) |
| 2205 | 1725 | { |
| 2206 | 1726 | const char *text = "No valid TLB @ %08X\n"; |
| 2207 | | UML_MOV(block, mem(&ppc->impstate->format), (FPTR)text); // mov [format],text |
| 2208 | | UML_MOV(block, mem(&ppc->impstate->arg0), desc->pc); // mov [arg0],desc->pc |
| 2209 | | UML_CALLC(block, cfunc_printf_debug, ppc); // callc printf_debug |
| 1727 | UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text |
| 1728 | UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc |
| 1729 | UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug |
| 2210 | 1730 | } |
| 2211 | | UML_EXH(block, *ppc->impstate->tlb_mismatch, 0); // exh tlb_mismatch,0 |
| 1731 | UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 |
| 2212 | 1732 | } |
| 2213 | 1733 | } |
| 2214 | 1734 | |
| 2215 | 1735 | /* if this is an invalid opcode, generate the exception now */ |
| 2216 | 1736 | if (desc->flags & OPFLAG_INVALID_OPCODE) |
| 2217 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000 |
| 1737 | UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000 |
| 2218 | 1738 | |
| 2219 | 1739 | /* if this is a privileged opcode in user mode, generate the exception */ |
| 2220 | | else if ((desc->flags & OPFLAG_PRIVILEGED) && (ppc->impstate->mode & MODE_USER)) |
| 2221 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x40000); // exh exception_program,0x40000 |
| 1740 | else if ((desc->flags & OPFLAG_PRIVILEGED) && (m_core->mode & MODE_USER)) |
| 1741 | UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x40000); // exh exception_program,0x40000 |
| 2222 | 1742 | |
| 2223 | 1743 | /* otherwise, unless this is a virtual no-op, it's a regular instruction */ |
| 2224 | 1744 | else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 2225 | 1745 | { |
| 2226 | 1746 | /* compile the instruction */ |
| 2227 | | if (!generate_opcode(ppc, block, compiler, desc)) |
| 1747 | if (!generate_opcode(block, compiler, desc)) |
| 2228 | 1748 | { |
| 2229 | | UML_MOV(block, mem(&ppc->pc), desc->pc); // mov [pc],desc->pc |
| 2230 | | UML_MOV(block, mem(&ppc->impstate->arg0), desc->opptr.l[0]); // mov [arg0],*desc->opptr.l |
| 2231 | | UML_CALLC(block, cfunc_unimplemented, ppc); // callc cfunc_unimplemented,ppc |
| 1749 | UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc |
| 1750 | UML_MOV(block, mem(&m_core->arg0), desc->opptr.l[0]); // mov [arg0],*desc->opptr.l |
| 1751 | UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented,ppc |
| 2232 | 1752 | } |
| 2233 | 1753 | } |
| 2234 | 1754 | } |
| r31142 | r31143 | |
| 2238 | 1758 | generate_compute_flags - compute CR0 and/or XER flags |
| 2239 | 1759 | ------------------------------------------------------------------*/ |
| 2240 | 1760 | |
| 2241 | | static void generate_compute_flags(powerpc_state *ppc, drcuml_block *block, const opcode_desc *desc, int updatecr, UINT32 xermask, int invertcarry) |
| 1761 | void ppc_device::generate_compute_flags(drcuml_block *block, const opcode_desc *desc, int updatecr, UINT32 xermask, int invertcarry) |
| 2242 | 1762 | { |
| 2243 | 1763 | UINT32 xerflags; |
| 2244 | 1764 | |
| r31142 | r31143 | |
| 2260 | 1780 | if (xermask == 0) |
| 2261 | 1781 | { |
| 2262 | 1782 | UML_GETFLGS(block, I0, FLAG_S | FLAG_Z); // getflgs i0,sz |
| 2263 | | UML_LOAD(block, I0, ppc->impstate->sz_cr_table, I0, SIZE_BYTE, SCALE_x1); // load i0,sz_cr_table,i0,byte |
| 1783 | UML_LOAD(block, I0, m_sz_cr_table, I0, SIZE_BYTE, SCALE_x1); // load i0,sz_cr_table,i0,byte |
| 2264 | 1784 | UML_OR(block, CR32(0), I0, XERSO32); // or [cr0],i0,[xerso] |
| 2265 | 1785 | return; |
| 2266 | 1786 | } |
| r31142 | r31143 | |
| 2287 | 1807 | |
| 2288 | 1808 | /* tricky case: both */ |
| 2289 | 1809 | UML_GETFLGS(block, I0, FLAG_S | FLAG_Z | xerflags); // getflgs i0,SZ | xerflags |
| 2290 | | UML_LOAD(block, I1, ppc->impstate->sz_cr_table, I0, SIZE_BYTE, SCALE_x1); // load i1,sz_cr_table,i0,byte |
| 1810 | UML_LOAD(block, I1, m_sz_cr_table, I0, SIZE_BYTE, SCALE_x1); // load i1,sz_cr_table,i0,byte |
| 2291 | 1811 | if (invertcarry && (xermask & XER_CA)) |
| 2292 | 1812 | UML_XOR(block, I0, I0, FLAG_C); // xor i0,i0,FLAG_C |
| 2293 | 1813 | UML_ROLINS(block, SPR32(SPR_XER), I0, 29, xermask); // rolins [xer],i0,29,xermask |
| r31142 | r31143 | |
| 2309 | 1829 | generate_shift_flags - compute S/Z flags for shifts |
| 2310 | 1830 | -------------------------------------------------------*/ |
| 2311 | 1831 | |
| 2312 | | static void generate_shift_flags(powerpc_state *ppc, drcuml_block *block, const opcode_desc *desc, UINT32 op) |
| 1832 | void ppc_device::generate_shift_flags(drcuml_block *block, const opcode_desc *desc, UINT32 op) |
| 2313 | 1833 | { |
| 2314 | 1834 | UML_CMP(block, R32(G_RA(op)), 0); // cmp ra, #0 |
| 2315 | 1835 | UML_SETc(block, COND_Z, I1); // set Z, i1 |
| r31142 | r31143 | |
| 2318 | 1838 | UML_SHR(block, I2, R32(G_RA(op)), 28); // shr i2, ra, #28 |
| 2319 | 1839 | UML_AND(block, I2, I2, FLAG_S); // and i2, i2, FLAG_S (i2 now = FLAG_S) |
| 2320 | 1840 | UML_OR(block, I1, I1, I2); // or i1, i1, i2 |
| 2321 | | UML_LOAD(block, I0, ppc->impstate->sz_cr_table, I1, SIZE_BYTE, SCALE_x1); // load i0,sz_cr_table,i0,byte |
| 1841 | UML_LOAD(block, I0, m_sz_cr_table, I1, SIZE_BYTE, SCALE_x1); // load i0,sz_cr_table,i0,byte |
| 2322 | 1842 | UML_OR(block, CR32(0), I0, XERSO32); // or [cr0],i0,[xerso] |
| 2323 | 1843 | } |
| 2324 | 1844 | |
| r31142 | r31143 | |
| 2327 | 1847 | point status flags |
| 2328 | 1848 | -------------------------------------------------*/ |
| 2329 | 1849 | |
| 2330 | | static void generate_fp_flags(powerpc_state *ppc, drcuml_block *block, const opcode_desc *desc, int updatefprf) |
| 1850 | void ppc_device::generate_fp_flags(drcuml_block *block, const opcode_desc *desc, int updatefprf) |
| 2331 | 1851 | { |
| 2332 | 1852 | /* for now, only handle the FPRF field */ |
| 2333 | 1853 | if (updatefprf) |
| 2334 | 1854 | { |
| 2335 | | UML_MOV(block, mem(&ppc->param0), G_RD(desc->opptr.l[0])); |
| 2336 | | UML_CALLC(block, (c_function)ppccom_update_fprf, ppc); |
| 1855 | UML_MOV(block, mem(&m_core->param0), G_RD(desc->opptr.l[0])); |
| 1856 | UML_CALLC(block, (c_function)cfunc_ppccom_update_fprf, this); |
| 2337 | 1857 | } |
| 2338 | 1858 | } |
| 2339 | 1859 | |
| r31142 | r31143 | |
| 2342 | 1862 | branch |
| 2343 | 1863 | -------------------------------------------------*/ |
| 2344 | 1864 | |
| 2345 | | static void generate_branch(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int source, UINT8 link) |
| 1865 | void ppc_device::generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int source, UINT8 link) |
| 2346 | 1866 | { |
| 2347 | 1867 | compiler_state compiler_temp = *compiler; |
| 2348 | | UINT32 *srcptr = &ppc->spr[source]; |
| 1868 | UINT32 *srcptr = &m_core->spr[source]; |
| 2349 | 1869 | |
| 2350 | 1870 | /* set the link if needed */ |
| 2351 | 1871 | if (link) |
| 2352 | 1872 | { |
| 2353 | 1873 | if (desc->targetpc == BRANCH_TARGET_DYNAMIC && source == SPR_LR) |
| 2354 | 1874 | { |
| 2355 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), mem(srcptr)); // mov [tempaddr],[lr] |
| 2356 | | srcptr = &ppc->impstate->tempaddr; |
| 1875 | UML_MOV(block, mem(&m_core->tempaddr), mem(srcptr)); // mov [tempaddr],[lr] |
| 1876 | srcptr = &m_core->tempaddr; |
| 2357 | 1877 | } |
| 2358 | 1878 | UML_MOV(block, SPR32(SPR_LR), desc->pc + 4); // mov [lr],desc->pc + 4 |
| 2359 | 1879 | } |
| r31142 | r31143 | |
| 2361 | 1881 | /* update the cycles and jump through the hash table to the target */ |
| 2362 | 1882 | if (desc->targetpc != BRANCH_TARGET_DYNAMIC) |
| 2363 | 1883 | { |
| 2364 | | generate_update_cycles(ppc, block, &compiler_temp, desc->targetpc, TRUE); // <subtract cycles> |
| 1884 | generate_update_cycles(block, &compiler_temp, desc->targetpc, TRUE); // <subtract cycles> |
| 2365 | 1885 | if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) |
| 2366 | 1886 | UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000 |
| 2367 | 1887 | else |
| 2368 | | UML_HASHJMP(block, ppc->impstate->mode, desc->targetpc, *ppc->impstate->nocode); |
| 1888 | UML_HASHJMP(block, m_core->mode, desc->targetpc, *m_nocode); |
| 2369 | 1889 | // hashjmp <mode>,desc->targetpc,nocode |
| 2370 | 1890 | } |
| 2371 | 1891 | else |
| 2372 | 1892 | { |
| 2373 | | generate_update_cycles(ppc, block, &compiler_temp, mem(srcptr), TRUE); // <subtract cycles> |
| 2374 | | UML_HASHJMP(block, ppc->impstate->mode, mem(srcptr), *ppc->impstate->nocode); // hashjmp <mode>,<rsreg>,nocode |
| 1893 | generate_update_cycles(block, &compiler_temp, mem(srcptr), TRUE); // <subtract cycles> |
| 1894 | UML_HASHJMP(block, m_core->mode, mem(srcptr), *m_nocode); // hashjmp <mode>,<rsreg>,nocode |
| 2375 | 1895 | } |
| 2376 | 1896 | |
| 2377 | 1897 | /* update the label */ |
| r31142 | r31143 | |
| 2387 | 1907 | branch based on the BO and BI fields |
| 2388 | 1908 | -------------------------------------------------*/ |
| 2389 | 1909 | |
| 2390 | | static void generate_branch_bo(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 bo, UINT32 bi, int source, int link) |
| 1910 | void ppc_device::generate_branch_bo(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 bo, UINT32 bi, int source, int link) |
| 2391 | 1911 | { |
| 2392 | 1912 | int skip = compiler->labelnum++; |
| 2393 | 1913 | |
| r31142 | r31143 | |
| 2401 | 1921 | UML_TEST(block, CR32(bi / 4), 8 >> (bi % 4)); // test cr32(bi/4),8 >> (bi % 4) |
| 2402 | 1922 | UML_JMPc(block, (bo & 0x08) ? COND_Z : COND_NZ, skip); // jmp skip,z/nz |
| 2403 | 1923 | } |
| 2404 | | generate_branch(ppc, block, compiler, desc, source, link); // <branch> |
| 1924 | generate_branch(block, compiler, desc, source, link); // <branch> |
| 2405 | 1925 | UML_LABEL(block, skip); // skip: |
| 2406 | 1926 | } |
| 2407 | 1927 | |
| r31142 | r31143 | |
| 2411 | 1931 | opcode |
| 2412 | 1932 | -------------------------------------------------*/ |
| 2413 | 1933 | |
| 2414 | | static int generate_opcode(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 1934 | int ppc_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2415 | 1935 | { |
| 2416 | 1936 | UINT32 op = desc->opptr.l[0]; |
| 2417 | 1937 | UINT32 opswitch = op >> 26; |
| 2418 | | int regnum; |
| 2419 | 1938 | |
| 2420 | 1939 | switch (opswitch) |
| 2421 | 1940 | { |
| r31142 | r31143 | |
| 2428 | 1947 | case 0x03: /* TWI */ |
| 2429 | 1948 | UML_CMP(block, R32(G_RA(op)), (INT16)G_SIMM(op)); // cmp ra,simm |
| 2430 | 1949 | if (G_TO(op) & 0x10) |
| 2431 | | UML_EXHc(block, COND_L, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,l |
| 1950 | UML_EXHc(block, COND_L, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,l |
| 2432 | 1951 | if (G_TO(op) & 0x08) |
| 2433 | | UML_EXHc(block, COND_G, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,g |
| 1952 | UML_EXHc(block, COND_G, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,g |
| 2434 | 1953 | if (G_TO(op) & 0x04) |
| 2435 | | UML_EXHc(block, COND_E, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,e |
| 1954 | UML_EXHc(block, COND_E, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,e |
| 2436 | 1955 | if (G_TO(op) & 0x02) |
| 2437 | | UML_EXHc(block, COND_B, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,b |
| 1956 | UML_EXHc(block, COND_B, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,b |
| 2438 | 1957 | if (G_TO(op) & 0x01) |
| 2439 | | UML_EXHc(block, COND_A, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,a |
| 1958 | UML_EXHc(block, COND_A, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,a |
| 2440 | 1959 | return TRUE; |
| 2441 | 1960 | |
| 2442 | 1961 | case 0x07: /* MULLI */ |
| r31142 | r31143 | |
| 2455 | 1974 | case 0x0a: /* CMPLI */ |
| 2456 | 1975 | UML_CMP(block, R32(G_RA(op)), G_UIMM(op)); // cmp ra,uimm |
| 2457 | 1976 | UML_GETFLGS(block, I0, FLAG_Z | FLAG_C); // getflgs i0,zc |
| 2458 | | UML_LOAD(block, I0, ppc->impstate->cmpl_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmpl_cr_table,i0,byte |
| 1977 | UML_LOAD(block, I0, m_cmpl_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmpl_cr_table,i0,byte |
| 2459 | 1978 | UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 2460 | 1979 | return TRUE; |
| 2461 | 1980 | |
| 2462 | 1981 | case 0x0b: /* CMPI */ |
| 2463 | 1982 | UML_CMP(block, R32(G_RA(op)), (INT16)G_SIMM(op)); // cmp ra,uimm |
| 2464 | 1983 | UML_GETFLGS(block, I0, FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs |
| 2465 | | UML_LOAD(block, I0, ppc->impstate->cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte |
| 1984 | UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte |
| 2466 | 1985 | UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 2467 | 1986 | return TRUE; |
| 2468 | 1987 | |
| 2469 | 1988 | case 0x08: /* SUBFIC */ |
| 2470 | 1989 | UML_SUB(block, R32(G_RD(op)), (INT16)G_SIMM(op), R32(G_RA(op))); // sub rd,simm,ra |
| 2471 | | generate_compute_flags(ppc, block, desc, FALSE, XER_CA, TRUE); // <update flags> |
| 1990 | generate_compute_flags(block, desc, FALSE, XER_CA, TRUE); // <update flags> |
| 2472 | 1991 | return TRUE; |
| 2473 | 1992 | |
| 2474 | 1993 | case 0x0c: /* ADDIC */ |
| 2475 | 1994 | UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), (INT16)G_SIMM(op)); // add rd,ra,simm |
| 2476 | | generate_compute_flags(ppc, block, desc, FALSE, XER_CA, FALSE); // <update flags> |
| 1995 | generate_compute_flags(block, desc, FALSE, XER_CA, FALSE); // <update flags> |
| 2477 | 1996 | return TRUE; |
| 2478 | 1997 | |
| 2479 | 1998 | case 0x0d: /* ADDIC. */ |
| 2480 | 1999 | UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), (INT16)G_SIMM(op)); // add rd,ra,simm |
| 2481 | | generate_compute_flags(ppc, block, desc, TRUE, XER_CA, FALSE); // <update flags> |
| 2000 | generate_compute_flags(block, desc, TRUE, XER_CA, FALSE); // <update flags> |
| 2482 | 2001 | return TRUE; |
| 2483 | 2002 | |
| 2484 | 2003 | case 0x10: /* BCx */ |
| 2485 | | generate_branch_bo(ppc, block, compiler, desc, G_BO(op), G_BI(op), 0, op & M_LK);// <branch conditional> |
| 2004 | generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), 0, op & M_LK);// <branch conditional> |
| 2486 | 2005 | return TRUE; |
| 2487 | 2006 | |
| 2488 | 2007 | case 0x11: /* SC */ |
| 2489 | 2008 | UML_MAPVAR(block, MAPVAR_PC, desc->pc + 4); // mapvar PC,desc->pc+4 |
| 2490 | | UML_EXH(block, *ppc->impstate->exception[EXCEPTION_SYSCALL], 0); // exh syscall,0 |
| 2009 | UML_EXH(block, *m_exception[EXCEPTION_SYSCALL], 0); // exh syscall,0 |
| 2491 | 2010 | return TRUE; |
| 2492 | 2011 | |
| 2493 | 2012 | case 0x12: /* Bx */ |
| 2494 | | generate_branch(ppc, block, compiler, desc, 0, op & M_LK); // <branch> |
| 2013 | generate_branch(block, compiler, desc, 0, op & M_LK); // <branch> |
| 2495 | 2014 | return TRUE; |
| 2496 | 2015 | |
| 2497 | 2016 | case 0x13: /* 0x13 group */ |
| 2498 | | return generate_instruction_13(ppc, block, compiler, desc); // <group13> |
| 2017 | return generate_instruction_13(block, compiler, desc); // <group13> |
| 2499 | 2018 | |
| 2500 | 2019 | case 0x14: /* RLWIMIx */ |
| 2501 | 2020 | UML_ROLINS(block, R32(G_RA(op)), R32(G_RS(op)), G_SH(op), compute_rlw_mask(G_MB(op), G_ME(op))); |
| 2502 | 2021 | // rolins ra,rs,sh,mask |
| 2503 | 2022 | if (op & M_RC) |
| 2504 | | generate_compute_flags(ppc, block, desc, TRUE, 0, FALSE); // <update flags> |
| 2023 | generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags> |
| 2505 | 2024 | return TRUE; |
| 2506 | 2025 | |
| 2507 | 2026 | case 0x15: /* RLWINMx */ |
| 2508 | 2027 | UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), G_SH(op), compute_rlw_mask(G_MB(op), G_ME(op))); |
| 2509 | 2028 | // roland ra,rs,sh,mask |
| 2510 | 2029 | if (op & M_RC) |
| 2511 | | generate_compute_flags(ppc, block, desc, TRUE, 0, FALSE); // <update flags> |
| 2030 | generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags> |
| 2512 | 2031 | return TRUE; |
| 2513 | 2032 | |
| 2514 | 2033 | case 0x17: /* RLWNMx */ |
| 2515 | 2034 | UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), compute_rlw_mask(G_MB(op), G_ME(op))); |
| 2516 | 2035 | // roland ra,rs,rb,mask |
| 2517 | 2036 | if (op & M_RC) |
| 2518 | | generate_compute_flags(ppc, block, desc, TRUE, 0, FALSE); // <update flags> |
| 2037 | generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags> |
| 2519 | 2038 | return TRUE; |
| 2520 | 2039 | |
| 2521 | 2040 | case 0x18: /* ORI */ |
| r31142 | r31143 | |
| 2536 | 2055 | |
| 2537 | 2056 | case 0x1c: /* ANDI. */ |
| 2538 | 2057 | UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op)); // and ra,rs,uimm |
| 2539 | | generate_compute_flags(ppc, block, desc, TRUE, 0, FALSE); // <update flags> |
| 2058 | generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags> |
| 2540 | 2059 | return TRUE; |
| 2541 | 2060 | |
| 2542 | 2061 | case 0x1d: /* ANDIS. */ |
| 2543 | 2062 | UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op) << 16); // and ra,rs,uimm << 16 |
| 2544 | | generate_compute_flags(ppc, block, desc, TRUE, 0, FALSE); // <update flags> |
| 2063 | generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags> |
| 2545 | 2064 | return TRUE; |
| 2546 | 2065 | |
| 2547 | 2066 | case 0x1f: /* 0x1f group */ |
| 2548 | | return generate_instruction_1f(ppc, block, compiler, desc); // <group1f> |
| 2067 | return generate_instruction_1f(block, compiler, desc); // <group1f> |
| 2549 | 2068 | |
| 2550 | 2069 | case 0x22: /* LBZ */ |
| 2551 | 2070 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2552 | 2071 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2553 | | UML_CALLH(block, *ppc->impstate->read8[ppc->impstate->mode]); // callh read8 |
| 2072 | UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 |
| 2554 | 2073 | UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff |
| 2555 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2074 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2556 | 2075 | return TRUE; |
| 2557 | 2076 | |
| 2558 | 2077 | case 0x28: /* LHZ */ |
| 2559 | 2078 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2560 | 2079 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2561 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2080 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 2562 | 2081 | UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff |
| 2563 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2082 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2564 | 2083 | return TRUE; |
| 2565 | 2084 | |
| 2566 | 2085 | case 0x2a: /* LHA */ |
| 2567 | 2086 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2568 | 2087 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2569 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2088 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 2570 | 2089 | UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word |
| 2571 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2090 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2572 | 2091 | return TRUE; |
| 2573 | 2092 | |
| 2574 | 2093 | case 0x20: /* LWZ */ |
| 2575 | 2094 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2576 | 2095 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2577 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 2096 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 2578 | 2097 | UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 |
| 2579 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2098 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2580 | 2099 | return TRUE; |
| 2581 | 2100 | |
| 2582 | 2101 | case 0x23: /* LBZU */ |
| 2583 | 2102 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2584 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2103 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2585 | 2104 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2586 | | UML_CALLH(block, *ppc->impstate->read8[ppc->impstate->mode]); // callh read8 |
| 2105 | UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 |
| 2587 | 2106 | UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff |
| 2588 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2589 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2107 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2108 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2590 | 2109 | return TRUE; |
| 2591 | 2110 | |
| 2592 | 2111 | case 0x29: /* LHZU */ |
| 2593 | 2112 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2594 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2113 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2595 | 2114 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2596 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2115 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 2597 | 2116 | UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff |
| 2598 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2599 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2117 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2118 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2600 | 2119 | return TRUE; |
| 2601 | 2120 | |
| 2602 | 2121 | case 0x2b: /* LHAU */ |
| 2603 | 2122 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2604 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2123 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2605 | 2124 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2606 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2125 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 2607 | 2126 | UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word |
| 2608 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2609 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2127 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2128 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2610 | 2129 | return TRUE; |
| 2611 | 2130 | |
| 2612 | 2131 | case 0x21: /* LWZU */ |
| 2613 | 2132 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2614 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2133 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2615 | 2134 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2616 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 2135 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 2617 | 2136 | UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 |
| 2618 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2619 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2137 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2138 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2620 | 2139 | return TRUE; |
| 2621 | 2140 | |
| 2622 | 2141 | case 0x26: /* STB */ |
| 2623 | 2142 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2624 | 2143 | UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff |
| 2625 | 2144 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2626 | | UML_CALLH(block, *ppc->impstate->write8[ppc->impstate->mode]); // callh write8 |
| 2627 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2145 | UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 |
| 2146 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2628 | 2147 | return TRUE; |
| 2629 | 2148 | |
| 2630 | 2149 | case 0x2c: /* STH */ |
| 2631 | 2150 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2632 | 2151 | UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs,0xffff |
| 2633 | 2152 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2634 | | UML_CALLH(block, *ppc->impstate->write16[ppc->impstate->mode]); // callh write16 |
| 2635 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2153 | UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 |
| 2154 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2636 | 2155 | return TRUE; |
| 2637 | 2156 | |
| 2638 | 2157 | case 0x24: /* STW */ |
| 2639 | 2158 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2640 | 2159 | UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs |
| 2641 | 2160 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2642 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 2643 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2161 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 2162 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2644 | 2163 | return TRUE; |
| 2645 | 2164 | |
| 2646 | 2165 | case 0x27: /* STBU */ |
| 2647 | 2166 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2648 | 2167 | UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff |
| 2649 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2168 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2650 | 2169 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2651 | | UML_CALLH(block, *ppc->impstate->write8[ppc->impstate->mode]); // callh write8 |
| 2652 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2653 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2170 | UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 |
| 2171 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2172 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2654 | 2173 | return TRUE; |
| 2655 | 2174 | |
| 2656 | 2175 | case 0x2d: /* STHU */ |
| 2657 | 2176 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2658 | 2177 | UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs,0xffff |
| 2659 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2178 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2660 | 2179 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2661 | | UML_CALLH(block, *ppc->impstate->write16[ppc->impstate->mode]); // callh write16 |
| 2662 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2663 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2180 | UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 |
| 2181 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2182 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2664 | 2183 | return TRUE; |
| 2665 | 2184 | |
| 2666 | 2185 | case 0x25: /* STWU */ |
| 2667 | 2186 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2668 | 2187 | UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs |
| 2669 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2188 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2670 | 2189 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2671 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 2672 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2673 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2190 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 2191 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2192 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2674 | 2193 | return TRUE; |
| 2675 | 2194 | |
| 2676 | 2195 | case 0x2e: /* LMW */ |
| 2677 | 2196 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2678 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra |
| 2679 | | for (regnum = G_RD(op); regnum < 32; regnum++) |
| 2197 | UML_MOV(block, mem(&m_core->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra |
| 2198 | for (int regnum = G_RD(op); regnum < 32; regnum++) |
| 2680 | 2199 | { |
| 2681 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), (INT16)G_SIMM(op) + 4 * (regnum - G_RD(op))); |
| 2200 | UML_ADD(block, I0, mem(&m_core->tempaddr), (INT16)G_SIMM(op) + 4 * (regnum - G_RD(op))); |
| 2682 | 2201 | // add i0,[tempaddr],simm + 4*(regnum-rd) |
| 2683 | | UML_CALLH(block, *ppc->impstate->read32align[ppc->impstate->mode]); // callh read32align |
| 2202 | UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align |
| 2684 | 2203 | UML_MOV(block, R32(regnum), I0); // mov regnum,i0 |
| 2685 | 2204 | } |
| 2686 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2205 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2687 | 2206 | return TRUE; |
| 2688 | 2207 | |
| 2689 | 2208 | case 0x2f: /* STMW */ |
| 2690 | 2209 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2691 | | UML_MOV(block, mem(&ppc->impstate->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra |
| 2692 | | for (regnum = G_RS(op); regnum < 32; regnum++) |
| 2210 | UML_MOV(block, mem(&m_core->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra |
| 2211 | for (int regnum = G_RS(op); regnum < 32; regnum++) |
| 2693 | 2212 | { |
| 2694 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), (INT16)G_SIMM(op) + 4 * (regnum - G_RS(op))); |
| 2213 | UML_ADD(block, I0, mem(&m_core->tempaddr), (INT16)G_SIMM(op) + 4 * (regnum - G_RS(op))); |
| 2695 | 2214 | // add i0,[tempaddr],simm + 4*(regnum-rs) |
| 2696 | 2215 | UML_MOV(block, I1, R32(regnum)); // mov i1,regnum |
| 2697 | | UML_CALLH(block, *ppc->impstate->write32align[ppc->impstate->mode]); // callh write32align |
| 2216 | UML_CALLH(block, *m_write32align[m_core->mode]); // callh write32align |
| 2698 | 2217 | } |
| 2699 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2218 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2700 | 2219 | return TRUE; |
| 2701 | 2220 | |
| 2702 | 2221 | case 0x30: /* LFS */ |
| 2703 | 2222 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2704 | 2223 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2705 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 2706 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), I0); // mov [tempdata],i0 |
| 2707 | | UML_FDFRFLT(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 2708 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2224 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 2225 | UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 |
| 2226 | UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 2227 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2709 | 2228 | return TRUE; |
| 2710 | 2229 | |
| 2711 | 2230 | case 0x32: /* LFD */ |
| 2712 | 2231 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2713 | 2232 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2714 | | UML_CALLH(block, *ppc->impstate->read64[ppc->impstate->mode]); // callh read64 |
| 2715 | | UML_DMOV(block, mem(&ppc->impstate->tempdata.d), I0); // dmov [tempdata],i0 |
| 2716 | | UML_FDMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata] |
| 2717 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2233 | UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 |
| 2234 | UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 |
| 2235 | UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] |
| 2236 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2718 | 2237 | return TRUE; |
| 2719 | 2238 | |
| 2720 | 2239 | case 0x31: /* LFSU */ |
| 2721 | 2240 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2722 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2241 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2723 | 2242 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2724 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 2725 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), I0); // mov [tempdata],i0 |
| 2726 | | UML_FDFRFLT(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 2727 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2728 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2243 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 2244 | UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 |
| 2245 | UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 2246 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2247 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2729 | 2248 | return TRUE; |
| 2730 | 2249 | |
| 2731 | 2250 | case 0x33: /* LFDU */ |
| 2732 | 2251 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2733 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2252 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2734 | 2253 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2735 | | UML_CALLH(block, *ppc->impstate->read64[ppc->impstate->mode]); // callh read64 |
| 2736 | | UML_DMOV(block, mem(&ppc->impstate->tempdata.d), I0); // dmov [tempdata],i0 |
| 2737 | | UML_FDMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata] |
| 2738 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2739 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2254 | UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 |
| 2255 | UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 |
| 2256 | UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] |
| 2257 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2258 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2740 | 2259 | return TRUE; |
| 2741 | 2260 | |
| 2742 | 2261 | case 0x34: /* STFS */ |
| 2743 | 2262 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2744 | | UML_FSFRFLT(block, mem(&ppc->impstate->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 2745 | | UML_MOV(block, I1, mem(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata] |
| 2263 | UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 2264 | UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] |
| 2746 | 2265 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2747 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 2748 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2266 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 2267 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2749 | 2268 | return TRUE; |
| 2750 | 2269 | |
| 2751 | 2270 | case 0x36: /* STFD */ |
| 2752 | 2271 | UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2753 | | UML_FDMOV(block, mem(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 2754 | | UML_DMOV(block, I1, mem(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata] |
| 2272 | UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 2273 | UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] |
| 2755 | 2274 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2756 | | UML_CALLH(block, *ppc->impstate->write64[ppc->impstate->mode]); // callh write64 |
| 2757 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2275 | UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 |
| 2276 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2758 | 2277 | return TRUE; |
| 2759 | 2278 | |
| 2760 | 2279 | case 0x35: /* STFSU */ |
| 2761 | 2280 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2762 | | UML_FSFRFLT(block, mem(&ppc->impstate->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 2763 | | UML_MOV(block, I1, mem(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata] |
| 2764 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2281 | UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 2282 | UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] |
| 2283 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2765 | 2284 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2766 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 2767 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2768 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2285 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 2286 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2287 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2769 | 2288 | return TRUE; |
| 2770 | 2289 | |
| 2771 | 2290 | case 0x37: /* STFDU */ |
| 2772 | 2291 | UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm |
| 2773 | | UML_FDMOV(block, mem(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 2774 | | UML_DMOV(block, I1, mem(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata] |
| 2775 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2292 | UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 2293 | UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] |
| 2294 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 2776 | 2295 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2777 | | UML_CALLH(block, *ppc->impstate->write64[ppc->impstate->mode]); // callh write64 |
| 2778 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2779 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2296 | UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 |
| 2297 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2298 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2780 | 2299 | return TRUE; |
| 2781 | 2300 | |
| 2782 | 2301 | case 0x3b: /* 0x3b group */ |
| 2783 | | return generate_instruction_3b(ppc, block, compiler, desc); // <group3b> |
| 2302 | return generate_instruction_3b(block, compiler, desc); // <group3b> |
| 2784 | 2303 | |
| 2785 | 2304 | case 0x3f: /* 0x3f group */ |
| 2786 | | return generate_instruction_3f(ppc, block, compiler, desc); // <group3f> |
| 2305 | return generate_instruction_3f(block, compiler, desc); // <group3f> |
| 2787 | 2306 | } |
| 2788 | 2307 | |
| 2789 | 2308 | return FALSE; |
| r31142 | r31143 | |
| 2795 | 2314 | the 0x13 group |
| 2796 | 2315 | -------------------------------------------------*/ |
| 2797 | 2316 | |
| 2798 | | static int generate_instruction_13(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2317 | int ppc_device::generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2799 | 2318 | { |
| 2800 | 2319 | UINT32 op = desc->opptr.l[0]; |
| 2801 | 2320 | UINT32 opswitch = (op >> 1) & 0x3ff; |
| r31142 | r31143 | |
| 2803 | 2322 | switch (opswitch) |
| 2804 | 2323 | { |
| 2805 | 2324 | case 0x010: /* BCLRx */ |
| 2806 | | generate_branch_bo(ppc, block, compiler, desc, G_BO(op), G_BI(op), SPR_LR, op & M_LK);// <branch conditional> |
| 2325 | generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_LR, op & M_LK);// <branch conditional> |
| 2807 | 2326 | return TRUE; |
| 2808 | 2327 | |
| 2809 | 2328 | case 0x210: /* BCCTRx */ |
| 2810 | | generate_branch_bo(ppc, block, compiler, desc, G_BO(op), G_BI(op), SPR_CTR, op & M_LK); |
| 2329 | generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_CTR, op & M_LK); |
| 2811 | 2330 | // <branch conditional> |
| 2812 | 2331 | return TRUE; |
| 2813 | 2332 | |
| r31142 | r31143 | |
| 2885 | 2404 | return TRUE; |
| 2886 | 2405 | |
| 2887 | 2406 | case 0x032: /* RFI */ |
| 2888 | | if (ppc->cap & PPCCAP_OEA) |
| 2407 | if (m_cap & PPCCAP_OEA) |
| 2889 | 2408 | { |
| 2890 | | if (!(ppc->cap & PPCCAP_603_MMU)) |
| 2409 | if (!(m_cap & PPCCAP_603_MMU)) |
| 2891 | 2410 | UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), 0, 0x87c0ffff); // rolins [msr],[srr1],0,0x87c0ffff |
| 2892 | 2411 | else |
| 2893 | 2412 | { |
| r31142 | r31143 | |
| 2896 | 2415 | // rolins [msr],[srr1],0,0x87c0ffff | MSR603_TGPR |
| 2897 | 2416 | UML_XOR(block, I0, I0, MSR32); // xor i0,i0,[msr] |
| 2898 | 2417 | UML_TEST(block, I0, MSR603_TGPR); // test i0,tgpr |
| 2899 | | UML_CALLHc(block, COND_NZ, *ppc->impstate->swap_tgpr); // callh swap_tgpr,nz |
| 2418 | UML_CALLHc(block, COND_NZ, *m_swap_tgpr); // callh swap_tgpr,nz |
| 2900 | 2419 | } |
| 2901 | 2420 | } |
| 2902 | | else if (ppc->cap & PPCCAP_4XX) |
| 2421 | else if (m_cap & PPCCAP_4XX) |
| 2903 | 2422 | UML_MOV(block, MSR32, SPR32(SPR4XX_SRR1)); // mov [msr],[srr1] |
| 2904 | | generate_update_mode(ppc, block); // <update mode> |
| 2423 | generate_update_mode(block); // <update mode> |
| 2905 | 2424 | compiler->checkints = TRUE; |
| 2906 | | generate_update_cycles(ppc, block, compiler, SPR32(SPROEA_SRR0), TRUE); // <subtract cycles> |
| 2907 | | UML_HASHJMP(block, mem(&ppc->impstate->mode), SPR32(SPROEA_SRR0), *ppc->impstate->nocode); |
| 2425 | generate_update_cycles(block, compiler, SPR32(SPROEA_SRR0), TRUE); // <subtract cycles> |
| 2426 | UML_HASHJMP(block, mem(&m_core->mode), SPR32(SPROEA_SRR0), *m_nocode); |
| 2908 | 2427 | // hashjmp mode,[srr0],nocode |
| 2909 | 2428 | return TRUE; |
| 2910 | 2429 | |
| 2911 | 2430 | case 0x033: /* RFCI */ |
| 2912 | | assert(ppc->cap & PPCCAP_4XX); |
| 2431 | assert(m_cap & PPCCAP_4XX); |
| 2913 | 2432 | UML_MOV(block, MSR32, SPR32(SPR4XX_SRR3)); // mov [msr],[srr3] |
| 2914 | | generate_update_mode(ppc, block); // <update mode> |
| 2433 | generate_update_mode(block); // <update mode> |
| 2915 | 2434 | compiler->checkints = TRUE; |
| 2916 | | generate_update_cycles(ppc, block, compiler, SPR32(SPR4XX_SRR2), TRUE); // <subtract cycles> |
| 2917 | | UML_HASHJMP(block, mem(&ppc->impstate->mode), SPR32(SPR4XX_SRR2), *ppc->impstate->nocode); |
| 2435 | generate_update_cycles(block, compiler, SPR32(SPR4XX_SRR2), TRUE); // <subtract cycles> |
| 2436 | UML_HASHJMP(block, mem(&m_core->mode), SPR32(SPR4XX_SRR2), *m_nocode); |
| 2918 | 2437 | // hashjmp mode,[srr2],nocode |
| 2919 | 2438 | return TRUE; |
| 2920 | 2439 | |
| r31142 | r31143 | |
| 2932 | 2451 | the 0x1f group |
| 2933 | 2452 | -------------------------------------------------*/ |
| 2934 | 2453 | |
| 2935 | | static int generate_instruction_1f(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2454 | int ppc_device::generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2936 | 2455 | { |
| 2937 | 2456 | UINT32 op = desc->opptr.l[0]; |
| 2938 | 2457 | UINT32 opswitch = (op >> 1) & 0x3ff; |
| r31142 | r31143 | |
| 2971 | 2490 | case 0x004: /* TW */ |
| 2972 | 2491 | UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb |
| 2973 | 2492 | if (G_TO(op) & 0x10) |
| 2974 | | UML_EXHc(block, COND_L, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,l |
| 2493 | UML_EXHc(block, COND_L, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,l |
| 2975 | 2494 | if (G_TO(op) & 0x08) |
| 2976 | | UML_EXHc(block, COND_G, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,g |
| 2495 | UML_EXHc(block, COND_G, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,g |
| 2977 | 2496 | if (G_TO(op) & 0x04) |
| 2978 | | UML_EXHc(block, COND_E, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,e |
| 2497 | UML_EXHc(block, COND_E, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,e |
| 2979 | 2498 | if (G_TO(op) & 0x02) |
| 2980 | | UML_EXHc(block, COND_B, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,b |
| 2499 | UML_EXHc(block, COND_B, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,b |
| 2981 | 2500 | if (G_TO(op) & 0x01) |
| 2982 | | UML_EXHc(block, COND_A, *ppc->impstate->exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,a |
| 2501 | UML_EXHc(block, COND_A, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,a |
| 2983 | 2502 | return TRUE; |
| 2984 | 2503 | |
| 2985 | 2504 | case 0x10a: /* ADDx */ |
| 2986 | 2505 | case 0x30a: /* ADDOx */ |
| 2987 | 2506 | UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // add rd,ra,rb |
| 2988 | | generate_compute_flags(ppc, block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2507 | generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2989 | 2508 | // <update flags> |
| 2990 | 2509 | return TRUE; |
| 2991 | 2510 | |
| 2992 | 2511 | case 0x00a: /* ADDCx */ |
| 2993 | 2512 | case 0x20a: /* ADDCOx */ |
| 2994 | 2513 | UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // add rd,ra,rb |
| 2995 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2514 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2996 | 2515 | // <update flags> |
| 2997 | 2516 | return TRUE; |
| 2998 | 2517 | |
| r31142 | r31143 | |
| 3000 | 2519 | case 0x28a: /* ADDEOx */ |
| 3001 | 2520 | UML_CARRY(block, SPR32(SPR_XER), 29); // carry [xer],XER_CA |
| 3002 | 2521 | UML_ADDC(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // addc rd,ra,rb |
| 3003 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2522 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 3004 | 2523 | // <update flags> |
| 3005 | 2524 | return TRUE; |
| 3006 | 2525 | |
| r31142 | r31143 | |
| 3008 | 2527 | case 0x2ca: /* ADDZEOx */ |
| 3009 | 2528 | UML_CARRY(block, SPR32(SPR_XER), 29); // carry [xer],XER_CA |
| 3010 | 2529 | UML_ADDC(block, R32(G_RD(op)), R32(G_RA(op)), 0); // addc rd,ra,0 |
| 3011 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2530 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 3012 | 2531 | // <update flags> |
| 3013 | 2532 | return TRUE; |
| 3014 | 2533 | |
| r31142 | r31143 | |
| 3016 | 2535 | case 0x2ea: /* ADDMEOx */ |
| 3017 | 2536 | UML_CARRY(block, SPR32(SPR_XER), 29); // carry [xer],XER_CA |
| 3018 | 2537 | UML_ADDC(block, R32(G_RD(op)), R32(G_RA(op)), (UINT32)-1); // addc rd,ra,-1 |
| 3019 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 2538 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); |
| 3020 | 2539 | // <update flags> |
| 3021 | 2540 | return TRUE; |
| 3022 | 2541 | |
| 3023 | 2542 | case 0x028: /* SUBFx */ |
| 3024 | 2543 | case 0x228: /* SUBFOx */ |
| 3025 | 2544 | UML_SUB(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op))); // sub rd,rb,ra |
| 3026 | | generate_compute_flags(ppc, block, desc, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); |
| 2545 | generate_compute_flags(block, desc, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); |
| 3027 | 2546 | // <update flags> |
| 3028 | 2547 | return TRUE; |
| 3029 | 2548 | |
| 3030 | 2549 | case 0x008: /* SUBFCx */ |
| 3031 | 2550 | case 0x208: /* SUBFCOx */ |
| 3032 | 2551 | UML_SUB(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op))); // sub rd,rb,ra |
| 3033 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 2552 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 3034 | 2553 | // <update flags> |
| 3035 | 2554 | return TRUE; |
| 3036 | 2555 | |
| r31142 | r31143 | |
| 3039 | 2558 | UML_XOR(block, I0, SPR32(SPR_XER), XER_CA); // xor i0,[xer],XER_CA |
| 3040 | 2559 | UML_CARRY(block, I0, 29); // carry i0,XER_CA |
| 3041 | 2560 | UML_SUBB(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op))); // subc rd,rb,ra |
| 3042 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 2561 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 3043 | 2562 | // <update flags> |
| 3044 | 2563 | return TRUE; |
| 3045 | 2564 | |
| r31142 | r31143 | |
| 3048 | 2567 | UML_XOR(block, I0, SPR32(SPR_XER), XER_CA); // xor i0,[xer],XER_CA |
| 3049 | 2568 | UML_CARRY(block, I0, 29); // carry i0,XER_CA |
| 3050 | 2569 | UML_SUBB(block, R32(G_RD(op)), 0, R32(G_RA(op))); // subc rd,0,ra |
| 3051 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 2570 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 3052 | 2571 | // <update flags> |
| 3053 | 2572 | return TRUE; |
| 3054 | 2573 | |
| r31142 | r31143 | |
| 3057 | 2576 | UML_XOR(block, I0, SPR32(SPR_XER), XER_CA); // xor i0,[xer],XER_CA |
| 3058 | 2577 | UML_CARRY(block, I0, 29); // carry i0,XER_CA |
| 3059 | 2578 | UML_SUBB(block, R32(G_RD(op)), (UINT32)-1, R32(G_RA(op))); // subc rd,-1,ra |
| 3060 | | generate_compute_flags(ppc, block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 2579 | generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); |
| 3061 | 2580 | // <update flags> |
| 3062 | 2581 | return TRUE; |
| 3063 | 2582 | |
| 3064 | 2583 | case 0x068: /* NEGx */ |
| 3065 | 2584 | case 0x268: /* NEGOx */ |
| 3066 | 2585 | UML_SUB(block, R32(G_RD(op)), 0, R32(G_RA(op))); // sub rd,0,ra |
| 3067 | | generate_compute_flags(ppc, block, desc, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); |
| 2586 | generate_compute_flags(block, desc, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); |
| 3068 | 2587 | // <update flags> |
| 3069 | 2588 | return TRUE; |
| 3070 | 2589 | |
| 3071 | 2590 | case 0x000: /* CMP */ |
| 3072 | 2591 | UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb |
| 3073 | 2592 | UML_GETFLGS(block, I0, FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs |
| 3074 | | UML_LOAD(block, I0, ppc->impstate->cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte |
| 2593 | UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte |
| 3075 | 2594 | UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 3076 | 2595 | return TRUE; |
| 3077 | 2596 | |
| 3078 | 2597 | case 0x020: /* CMPL */ |
| 3079 | 2598 | UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb |
| 3080 | 2599 | UML_GETFLGS(block, I0, FLAG_Z | FLAG_C); // getflgs i0,zc |
| 3081 | | UML_LOAD(block, I0, ppc->impstate->cmpl_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmpl_cr_table,i0,byte |
| 2600 | UML_LOAD(block, I0, m_cmpl_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmpl_cr_table,i0,byte |
| 3082 | 2601 | UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 3083 | 2602 | return TRUE; |
| 3084 | 2603 | |
| r31142 | r31143 | |
| 3087 | 2606 | if (op & M_RC) |
| 3088 | 2607 | { |
| 3089 | 2608 | UML_TEST(block, R32(G_RD(op)), ~0); // test rd,~0 |
| 3090 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2609 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3091 | 2610 | } |
| 3092 | 2611 | return TRUE; |
| 3093 | 2612 | |
| r31142 | r31143 | |
| 3096 | 2615 | if (op & M_RC) |
| 3097 | 2616 | { |
| 3098 | 2617 | UML_TEST(block, R32(G_RD(op)), ~0); // test rd,~0 |
| 3099 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2618 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3100 | 2619 | } |
| 3101 | 2620 | return TRUE; |
| 3102 | 2621 | |
| 3103 | 2622 | case 0x0eb: /* MULLWx */ |
| 3104 | 2623 | case 0x2eb: /* MULLWOx */ |
| 3105 | 2624 | UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // muls rd,rd,ra,rb |
| 3106 | | generate_compute_flags(ppc, block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2625 | generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 3107 | 2626 | return TRUE; |
| 3108 | 2627 | |
| 3109 | 2628 | case 0x1cb: /* DIVWUx */ |
| r31142 | r31143 | |
| 3128 | 2647 | |
| 3129 | 2648 | UML_LABEL(block, compiler->labelnum++); // 0: |
| 3130 | 2649 | UML_DIVU(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // divu rd,rd,ra,rb |
| 3131 | | generate_compute_flags(ppc, block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2650 | generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 3132 | 2651 | |
| 3133 | 2652 | UML_LABEL(block, compiler->labelnum++); // 1: |
| 3134 | 2653 | return TRUE; |
| r31142 | r31143 | |
| 3181 | 2700 | |
| 3182 | 2701 | UML_LABEL(block, compiler->labelnum++); // 2: |
| 3183 | 2702 | UML_DIVS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // divs rd,rd,ra,rb |
| 3184 | | generate_compute_flags(ppc, block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2703 | generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 3185 | 2704 | |
| 3186 | 2705 | UML_LABEL(block, compiler->labelnum++); // 3: |
| 3187 | 2706 | return TRUE; |
| 3188 | 2707 | |
| 3189 | 2708 | case 0x01c: /* ANDx */ |
| 3190 | 2709 | UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // and ra,rs,rb |
| 3191 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2710 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3192 | 2711 | return TRUE; |
| 3193 | 2712 | |
| 3194 | 2713 | case 0x03c: /* ANDCx */ |
| 3195 | 2714 | UML_XOR(block, I0, R32(G_RB(op)), ~0); // xor i0,rb,~0 |
| 3196 | 2715 | UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), I0); // and ra,rs,i0 |
| 3197 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2716 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3198 | 2717 | return TRUE; |
| 3199 | 2718 | |
| 3200 | 2719 | case 0x1dc: /* NANDx */ |
| 3201 | 2720 | UML_AND(block, I0, R32(G_RS(op)), R32(G_RB(op))); // and i0,rs,rb |
| 3202 | 2721 | UML_XOR(block, R32(G_RA(op)), I0, ~0); // xor ra,i0,~0 |
| 3203 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2722 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3204 | 2723 | return TRUE; |
| 3205 | 2724 | |
| 3206 | 2725 | case 0x1bc: /* ORx */ |
| 3207 | 2726 | UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // or ra,rs,rb |
| 3208 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2727 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3209 | 2728 | return TRUE; |
| 3210 | 2729 | |
| 3211 | 2730 | case 0x19c: /* ORCx */ |
| 3212 | 2731 | UML_XOR(block, I0, R32(G_RB(op)), ~0); // xor i0,rb,~0 |
| 3213 | 2732 | UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), I0); // or ra,rs,i0 |
| 3214 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2733 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3215 | 2734 | return TRUE; |
| 3216 | 2735 | |
| 3217 | 2736 | case 0x07c: /* NORx */ |
| 3218 | 2737 | UML_OR(block, I0, R32(G_RS(op)), R32(G_RB(op))); // or i0,rs,rb |
| 3219 | 2738 | UML_XOR(block, R32(G_RA(op)), I0, ~0); // xor ra,i0,~0 |
| 3220 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2739 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3221 | 2740 | return TRUE; |
| 3222 | 2741 | |
| 3223 | 2742 | case 0x13c: /* XORx */ |
| 3224 | 2743 | UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // xor ra,rs,rb |
| 3225 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2744 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3226 | 2745 | return TRUE; |
| 3227 | 2746 | |
| 3228 | 2747 | case 0x11c: /* EQVx */ |
| 3229 | 2748 | UML_XOR(block, I0, R32(G_RS(op)), R32(G_RB(op))); // xor i0,rs,rb |
| 3230 | 2749 | UML_XOR(block, R32(G_RA(op)), I0, ~0); // xor ra,i0,~0 |
| 3231 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2750 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3232 | 2751 | return TRUE; |
| 3233 | 2752 | |
| 3234 | 2753 | case 0x018: /* SLWx */ |
| r31142 | r31143 | |
| 3250 | 2769 | // calculate S and Z flags |
| 3251 | 2770 | if (op & M_RC) |
| 3252 | 2771 | { |
| 3253 | | generate_shift_flags(ppc, block, desc, op); |
| 2772 | generate_shift_flags(block, desc, op); |
| 3254 | 2773 | } |
| 3255 | 2774 | |
| 3256 | 2775 | UML_LABEL(block, compiler->labelnum++); // 1: |
| r31142 | r31143 | |
| 3275 | 2794 | // calculate S and Z flags |
| 3276 | 2795 | if (op & M_RC) |
| 3277 | 2796 | { |
| 3278 | | generate_shift_flags(ppc, block, desc, op); |
| 2797 | generate_shift_flags(block, desc, op); |
| 3279 | 2798 | } |
| 3280 | 2799 | |
| 3281 | 2800 | UML_LABEL(block, compiler->labelnum++); // 1: |
| r31142 | r31143 | |
| 3313 | 2832 | // calculate S and Z flags |
| 3314 | 2833 | if (op & M_RC) |
| 3315 | 2834 | { |
| 3316 | | generate_shift_flags(ppc, block, desc, op); |
| 2835 | generate_shift_flags(block, desc, op); |
| 3317 | 2836 | } |
| 3318 | 2837 | return TRUE; |
| 3319 | 2838 | |
| r31142 | r31143 | |
| 3330 | 2849 | // calculate S and Z flags |
| 3331 | 2850 | if (op & M_RC) |
| 3332 | 2851 | { |
| 3333 | | generate_shift_flags(ppc, block, desc, op); |
| 2852 | generate_shift_flags(block, desc, op); |
| 3334 | 2853 | } |
| 3335 | 2854 | return TRUE; |
| 3336 | 2855 | |
| 3337 | 2856 | case 0x01a: /* CNTLZWx */ |
| 3338 | 2857 | UML_LZCNT(block, R32(G_RA(op)), R32(G_RS(op))); // lzcnt ra,rs |
| 3339 | 2858 | if (op & M_RC) |
| 3340 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2859 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3341 | 2860 | return TRUE; |
| 3342 | 2861 | |
| 3343 | 2862 | case 0x3ba: /* EXTSBx */ |
| 3344 | 2863 | UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), SIZE_BYTE); // sext ra,rs,byte |
| 3345 | 2864 | if (op & M_RC) |
| 3346 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2865 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3347 | 2866 | return TRUE; |
| 3348 | 2867 | |
| 3349 | 2868 | case 0x39a: /* EXTSHx */ |
| 3350 | 2869 | UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), SIZE_WORD); // sext ra,rs,word |
| 3351 | 2870 | if (op & M_RC) |
| 3352 | | generate_compute_flags(ppc, block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 2871 | generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // <update flags> |
| 3353 | 2872 | return TRUE; |
| 3354 | 2873 | |
| 3355 | 2874 | case 0x057: /* LBZX */ |
| 3356 | 2875 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3357 | 2876 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3358 | | UML_CALLH(block, *ppc->impstate->read8[ppc->impstate->mode]); // callh read8 |
| 2877 | UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 |
| 3359 | 2878 | UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff |
| 3360 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2879 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3361 | 2880 | return TRUE; |
| 3362 | 2881 | |
| 3363 | 2882 | case 0x117: /* LHZX */ |
| 3364 | 2883 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3365 | 2884 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3366 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2885 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 3367 | 2886 | UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff |
| 3368 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2887 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3369 | 2888 | return TRUE; |
| 3370 | 2889 | |
| 3371 | 2890 | case 0x157: /* LHAX */ |
| 3372 | 2891 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3373 | 2892 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3374 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2893 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 3375 | 2894 | UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word |
| 3376 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2895 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3377 | 2896 | return TRUE; |
| 3378 | 2897 | |
| 3379 | 2898 | case 0x017: /* LWZX */ |
| 3380 | 2899 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3381 | 2900 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3382 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 2901 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 3383 | 2902 | UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 |
| 3384 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2903 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3385 | 2904 | return TRUE; |
| 3386 | 2905 | |
| 3387 | 2906 | case 0x217: /* LFSX */ |
| 3388 | 2907 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3389 | 2908 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3390 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 3391 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), I0); // mov [tempdata],i0 |
| 3392 | | UML_FDFRFLT(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 3393 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2909 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 2910 | UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 |
| 2911 | UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 2912 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3394 | 2913 | return TRUE; |
| 3395 | 2914 | |
| 3396 | 2915 | case 0x257: /* LFDX */ |
| 3397 | 2916 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3398 | 2917 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3399 | | UML_CALLH(block, *ppc->impstate->read64[ppc->impstate->mode]); // callh read64 |
| 3400 | | UML_DMOV(block, mem(&ppc->impstate->tempdata.d), I0); // dmov [tempdata],i0 |
| 3401 | | UML_FDMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata] |
| 3402 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2918 | UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 |
| 2919 | UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 |
| 2920 | UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] |
| 2921 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3403 | 2922 | return TRUE; |
| 3404 | 2923 | |
| 3405 | 2924 | case 0x316: /* LHBRX */ |
| 3406 | 2925 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3407 | 2926 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3408 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2927 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 3409 | 2928 | UML_BSWAP(block, I0, I0); // bswap i0,i0 |
| 3410 | 2929 | UML_SHR(block, R32(G_RD(op)), I0, 16); // shr rd,i0,16 |
| 3411 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2930 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3412 | 2931 | return TRUE; |
| 3413 | 2932 | |
| 3414 | 2933 | case 0x216: /* LWBRX */ |
| 3415 | 2934 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3416 | 2935 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3417 | | UML_CALLH(block, *ppc->impstate->read32align[ppc->impstate->mode]); // callh read32align |
| 2936 | UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align |
| 3418 | 2937 | UML_BSWAP(block, R32(G_RD(op)), I0); // bswap rd,i0 |
| 3419 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2938 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3420 | 2939 | return TRUE; |
| 3421 | 2940 | |
| 3422 | 2941 | case 0x077: /* LBZUX */ |
| 3423 | 2942 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3424 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2943 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3425 | 2944 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3426 | | UML_CALLH(block, *ppc->impstate->read8[ppc->impstate->mode]); // callh read8 |
| 2945 | UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 |
| 3427 | 2946 | UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff |
| 3428 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3429 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2947 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2948 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3430 | 2949 | return TRUE; |
| 3431 | 2950 | |
| 3432 | 2951 | case 0x137: /* LHZUX */ |
| 3433 | 2952 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3434 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2953 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3435 | 2954 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3436 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2955 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 3437 | 2956 | UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff |
| 3438 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3439 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2957 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2958 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3440 | 2959 | return TRUE; |
| 3441 | 2960 | |
| 3442 | 2961 | case 0x177: /* LHAUX */ |
| 3443 | 2962 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3444 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2963 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3445 | 2964 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3446 | | UML_CALLH(block, *ppc->impstate->read16[ppc->impstate->mode]); // callh read16 |
| 2965 | UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 |
| 3447 | 2966 | UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word |
| 3448 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3449 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2967 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2968 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3450 | 2969 | return TRUE; |
| 3451 | 2970 | |
| 3452 | 2971 | case 0x037: /* LWZUX */ |
| 3453 | 2972 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3454 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2973 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3455 | 2974 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3456 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 2975 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 3457 | 2976 | UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 |
| 3458 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3459 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2977 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2978 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3460 | 2979 | return TRUE; |
| 3461 | 2980 | |
| 3462 | 2981 | case 0x237: /* LFSUX */ |
| 3463 | 2982 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3464 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2983 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3465 | 2984 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3466 | | UML_CALLH(block, *ppc->impstate->read32[ppc->impstate->mode]); // callh read32 |
| 3467 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), I0); // mov [tempdata],i0 |
| 3468 | | UML_FDFRFLT(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 3469 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3470 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2985 | UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 |
| 2986 | UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 |
| 2987 | UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword |
| 2988 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 2989 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3471 | 2990 | return TRUE; |
| 3472 | 2991 | |
| 3473 | 2992 | case 0x277: /* LFDUX */ |
| 3474 | 2993 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3475 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 2994 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3476 | 2995 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3477 | | UML_CALLH(block, *ppc->impstate->read64[ppc->impstate->mode]); // callh read64 |
| 3478 | | UML_DMOV(block, mem(&ppc->impstate->tempdata.d), I0); // dmov [tempdata],i0 |
| 3479 | | UML_FDMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata] |
| 3480 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3481 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 2996 | UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 |
| 2997 | UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 |
| 2998 | UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] |
| 2999 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 3000 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3482 | 3001 | return TRUE; |
| 3483 | 3002 | |
| 3484 | 3003 | case 0x014: /* LWARX */ |
| 3485 | 3004 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3486 | 3005 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3487 | | UML_CALLH(block, *ppc->impstate->read32align[ppc->impstate->mode]); // callh read32align |
| 3006 | UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align |
| 3488 | 3007 | UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 |
| 3489 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3008 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3490 | 3009 | return TRUE; |
| 3491 | 3010 | |
| 3492 | 3011 | case 0x255: /* LSWI */ |
| 3493 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra |
| 3494 | | UML_MOV(block, mem(&ppc->impstate->swcount), ((G_NB(op) - 1) & 0x1f) + 1); // mov [swcount],G_NB |
| 3495 | | UML_CALLH(block, *ppc->impstate->lsw[ppc->impstate->mode][G_RD(op)]); // call lsw[rd] |
| 3496 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3012 | UML_MOV(block, mem(&m_core->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra |
| 3013 | UML_MOV(block, mem(&m_core->swcount), ((G_NB(op) - 1) & 0x1f) + 1); // mov [swcount],G_NB |
| 3014 | UML_CALLH(block, *m_lsw[m_core->mode][G_RD(op)]); // call lsw[rd] |
| 3015 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3497 | 3016 | return TRUE; |
| 3498 | 3017 | |
| 3499 | 3018 | case 0x215: /* LSWX */ |
| 3500 | | UML_ADD(block, mem(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb |
| 3501 | | UML_AND(block, mem(&ppc->impstate->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f |
| 3502 | | UML_SUB(block, mem(&ppc->icount), mem(&ppc->icount), mem(&ppc->impstate->swcount));// sub icount,icount,[swcount] |
| 3503 | | UML_CALLHc(block, COND_NZ, *ppc->impstate->lsw[ppc->impstate->mode][G_RD(op)]); // call lsw[rd],nz |
| 3504 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3019 | UML_ADD(block, mem(&m_core->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb |
| 3020 | UML_AND(block, mem(&m_core->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f |
| 3021 | UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), mem(&m_core->swcount));// sub icount,icount,[swcount] |
| 3022 | UML_CALLHc(block, COND_NZ, *m_lsw[m_core->mode][G_RD(op)]); // call lsw[rd],nz |
| 3023 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3505 | 3024 | return TRUE; |
| 3506 | 3025 | |
| 3507 | 3026 | case 0x136: /* ECIWX */ |
| r31142 | r31143 | |
| 3512 | 3031 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3513 | 3032 | UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff |
| 3514 | 3033 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3515 | | UML_CALLH(block, *ppc->impstate->write8[ppc->impstate->mode]); // callh write8 |
| 3516 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3034 | UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 |
| 3035 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3517 | 3036 | return TRUE; |
| 3518 | 3037 | |
| 3519 | 3038 | case 0x197: /* STHX */ |
| 3520 | 3039 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3521 | 3040 | UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs |
| 3522 | 3041 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3523 | | UML_CALLH(block, *ppc->impstate->write16[ppc->impstate->mode]); // callh write16 |
| 3524 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3042 | UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 |
| 3043 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3525 | 3044 | return TRUE; |
| 3526 | 3045 | |
| 3527 | 3046 | case 0x097: /* STWX */ |
| 3528 | 3047 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3529 | 3048 | UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs |
| 3530 | 3049 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3531 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 3532 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3050 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 3051 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3533 | 3052 | return TRUE; |
| 3534 | 3053 | |
| 3535 | 3054 | case 0x297: /* STFSX */ |
| 3536 | 3055 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3537 | | UML_FSFRFLT(block, mem(&ppc->impstate->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 3538 | | UML_MOV(block, I1, mem(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata] |
| 3056 | UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 3057 | UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] |
| 3539 | 3058 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3540 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 3541 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3059 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 3060 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3542 | 3061 | return TRUE; |
| 3543 | 3062 | |
| 3544 | 3063 | case 0x3d7: /* STFIWX */ |
| 3545 | 3064 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3546 | | UML_FDMOV(block, mem(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3547 | | UML_MOV(block, I1, mem(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata.lo] |
| 3065 | UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3066 | UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata.lo] |
| 3548 | 3067 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3549 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 3550 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3068 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 3069 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3551 | 3070 | return TRUE; |
| 3552 | 3071 | |
| 3553 | 3072 | case 0x2d7: /* STFDX */ |
| 3554 | 3073 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3555 | | UML_FDMOV(block, mem(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3556 | | UML_DMOV(block, I1, mem(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata] |
| 3074 | UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3075 | UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] |
| 3557 | 3076 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3558 | | UML_CALLH(block, *ppc->impstate->write64[ppc->impstate->mode]); // callh write64 |
| 3559 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3077 | UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 |
| 3078 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3560 | 3079 | return TRUE; |
| 3561 | 3080 | |
| 3562 | 3081 | case 0x396: /* STHBRX */ |
| r31142 | r31143 | |
| 3564 | 3083 | UML_BSWAP(block, I1, R32(G_RS(op))); // bswap i1,rs |
| 3565 | 3084 | UML_SHR(block, I1, I1, 16); // shr i1,i1,16 |
| 3566 | 3085 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3567 | | UML_CALLH(block, *ppc->impstate->write16[ppc->impstate->mode]); // callh write16 |
| 3568 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3086 | UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 |
| 3087 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3569 | 3088 | return TRUE; |
| 3570 | 3089 | |
| 3571 | 3090 | case 0x296: /* STWBRX */ |
| 3572 | 3091 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3573 | 3092 | UML_BSWAP(block, I1, R32(G_RS(op))); // bswap i1,rs |
| 3574 | 3093 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3575 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 3576 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3094 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 3095 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3577 | 3096 | return TRUE; |
| 3578 | 3097 | |
| 3579 | 3098 | case 0x0f7: /* STBUX */ |
| 3580 | 3099 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3581 | 3100 | UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff |
| 3582 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 3101 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3583 | 3102 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3584 | | UML_CALLH(block, *ppc->impstate->write8[ppc->impstate->mode]); // callh write8 |
| 3585 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3586 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3103 | UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 |
| 3104 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 3105 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3587 | 3106 | return TRUE; |
| 3588 | 3107 | |
| 3589 | 3108 | case 0x1b7: /* STHUX */ |
| 3590 | 3109 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3591 | 3110 | UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs,0xffff |
| 3592 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 3111 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3593 | 3112 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3594 | | UML_CALLH(block, *ppc->impstate->write16[ppc->impstate->mode]); // callh write16 |
| 3595 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3596 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3113 | UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 |
| 3114 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 3115 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3597 | 3116 | return TRUE; |
| 3598 | 3117 | |
| 3599 | 3118 | case 0x0b7: /* STWUX */ |
| 3600 | 3119 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3601 | 3120 | UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs |
| 3602 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 3121 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3603 | 3122 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3604 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 3605 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3606 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3123 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 3124 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 3125 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3607 | 3126 | return TRUE; |
| 3608 | 3127 | |
| 3609 | 3128 | case 0x2b7: /* STFSUX */ |
| 3610 | 3129 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3611 | | UML_FSFRFLT(block, mem(&ppc->impstate->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 3612 | | UML_MOV(block, I1, mem(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata] |
| 3613 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 3130 | UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword |
| 3131 | UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] |
| 3132 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3614 | 3133 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3615 | | UML_CALLH(block, *ppc->impstate->write32[ppc->impstate->mode]); // callh write32 |
| 3616 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3617 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3134 | UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 |
| 3135 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 3136 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3618 | 3137 | return TRUE; |
| 3619 | 3138 | |
| 3620 | 3139 | case 0x2f7: /* STFDUX */ |
| 3621 | 3140 | UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3622 | | UML_FDMOV(block, mem(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3623 | | UML_DMOV(block, I1, mem(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata] |
| 3624 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), I0); // mov [updateaddr],i0 |
| 3141 | UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3142 | UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] |
| 3143 | UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 |
| 3625 | 3144 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3626 | | UML_CALLH(block, *ppc->impstate->write64[ppc->impstate->mode]); // callh write64 |
| 3627 | | UML_MOV(block, R32(G_RA(op)), mem(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3628 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3145 | UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 |
| 3146 | UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] |
| 3147 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3629 | 3148 | return TRUE; |
| 3630 | 3149 | |
| 3631 | 3150 | case 0x096: /* STWCX. */ |
| 3632 | 3151 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3633 | 3152 | UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs |
| 3634 | 3153 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3635 | | UML_CALLH(block, *ppc->impstate->write32align[ppc->impstate->mode]); // callh write32align |
| 3636 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3154 | UML_CALLH(block, *m_write32align[m_core->mode]); // callh write32align |
| 3155 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3637 | 3156 | |
| 3638 | 3157 | UML_CMP(block, I0, I0); // cmp i0,i0 |
| 3639 | 3158 | UML_GETFLGS(block, I0, FLAG_Z | FLAG_C | FLAG_S); // getflgs i0,zcs |
| 3640 | | UML_LOAD(block, I0, ppc->impstate->cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte |
| 3159 | UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte |
| 3641 | 3160 | UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 3642 | 3161 | |
| 3643 | | generate_compute_flags(ppc, block, desc, TRUE, 0, FALSE); // <update flags> |
| 3162 | generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags> |
| 3644 | 3163 | return TRUE; |
| 3645 | 3164 | |
| 3646 | 3165 | case 0x2d5: /* STSWI */ |
| 3647 | | UML_MOV(block, mem(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra |
| 3648 | | UML_MOV(block, mem(&ppc->impstate->swcount), ((G_NB(op) - 1) & 0x1f) + 1); // mov [swcount],G_NB |
| 3649 | | UML_CALLH(block, *ppc->impstate->stsw[ppc->impstate->mode][G_RD(op)]); // call stsw[rd] |
| 3650 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3166 | UML_MOV(block, mem(&m_core->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra |
| 3167 | UML_MOV(block, mem(&m_core->swcount), ((G_NB(op) - 1) & 0x1f) + 1); // mov [swcount],G_NB |
| 3168 | UML_CALLH(block, *m_stsw[m_core->mode][G_RD(op)]); // call stsw[rd] |
| 3169 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3651 | 3170 | return TRUE; |
| 3652 | 3171 | |
| 3653 | 3172 | case 0x295: /* STSWX */ |
| 3654 | | UML_ADD(block, mem(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb |
| 3655 | | UML_AND(block, mem(&ppc->impstate->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f |
| 3656 | | UML_SUB(block, mem(&ppc->icount), mem(&ppc->icount), mem(&ppc->impstate->swcount));// sub icount,icount,[swcount] |
| 3657 | | UML_CALLHc(block, COND_NZ, *ppc->impstate->stsw[ppc->impstate->mode][G_RD(op)]); // call stsw[rd] |
| 3658 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3173 | UML_ADD(block, mem(&m_core->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb |
| 3174 | UML_AND(block, mem(&m_core->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f |
| 3175 | UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), mem(&m_core->swcount));// sub icount,icount,[swcount] |
| 3176 | UML_CALLHc(block, COND_NZ, *m_stsw[m_core->mode][G_RD(op)]); // call stsw[rd] |
| 3177 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3659 | 3178 | return TRUE; |
| 3660 | 3179 | |
| 3661 | 3180 | case 0x1b6: /* ECOWX */ |
| r31142 | r31143 | |
| 3664 | 3183 | |
| 3665 | 3184 | case 0x036: /* DCBST */ |
| 3666 | 3185 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3667 | | UML_MOV(block, mem(&ppc->param0), I0); // mov [param0],i0 |
| 3668 | | UML_CALLC(block, (c_function)ppccom_dcstore_callback, ppc); |
| 3186 | UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 |
| 3187 | UML_CALLC(block, (c_function)cfunc_ppccom_dcstore_callback, this); |
| 3669 | 3188 | return TRUE; |
| 3670 | 3189 | |
| 3671 | 3190 | case 0x056: /* DCBF */ |
| r31142 | r31143 | |
| 3681 | 3200 | |
| 3682 | 3201 | case 0x3f6: /* DCBZ */ |
| 3683 | 3202 | UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3684 | | UML_AND(block, mem(&ppc->impstate->tempaddr), I0, ~(ppc->cache_line_size - 1)); |
| 3203 | UML_AND(block, mem(&m_core->tempaddr), I0, ~(m_cache_line_size - 1)); |
| 3685 | 3204 | // and [tempaddr],i0,~(cache_line_size - 1) |
| 3686 | | for (item = 0; item < ppc->cache_line_size / 8; item++) |
| 3205 | for (item = 0; item < m_cache_line_size / 8; item++) |
| 3687 | 3206 | { |
| 3688 | | UML_ADD(block, I0, mem(&ppc->impstate->tempaddr), 8 * item); // add i0,[tempaddr],8*item |
| 3207 | UML_ADD(block, I0, mem(&m_core->tempaddr), 8 * item); // add i0,[tempaddr],8*item |
| 3689 | 3208 | UML_DMOV(block, I1, 0); // dmov i1,0 |
| 3690 | | UML_CALLH(block, *ppc->impstate->write64[ppc->impstate->mode]); // callh write64 |
| 3209 | UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 |
| 3691 | 3210 | } |
| 3692 | 3211 | return TRUE; |
| 3693 | 3212 | |
| 3694 | 3213 | case 0x132: /* TLBIE */ |
| 3695 | | UML_MOV(block, mem(&ppc->param0), R32(G_RB(op))); // mov [param0],rb |
| 3696 | | UML_CALLC(block, (c_function)ppccom_execute_tlbie, ppc); // callc ppccom_execute_tlbie,ppc |
| 3214 | UML_MOV(block, mem(&m_core->param0), R32(G_RB(op))); // mov [param0],rb |
| 3215 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbie, this); // callc ppccom_execute_tlbie,ppc |
| 3697 | 3216 | return TRUE; |
| 3698 | 3217 | |
| 3699 | 3218 | case 0x172: /* TLBIA */ |
| 3700 | | UML_CALLC(block, (c_function)ppccom_execute_tlbia, ppc); // callc ppccom_execute_tlbia,ppc |
| 3219 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbia, this); // callc ppccom_execute_tlbia,ppc |
| 3701 | 3220 | return TRUE; |
| 3702 | 3221 | |
| 3703 | 3222 | case 0x3d2: /* TLBLD */ |
| 3704 | | assert(ppc->cap & PPCCAP_603_MMU); |
| 3705 | | UML_MOV(block, mem(&ppc->param0), R32(G_RB(op))); // mov [param0],rb |
| 3706 | | UML_MOV(block, mem(&ppc->param1), 0); // mov [param1],0 |
| 3707 | | UML_CALLC(block, (c_function)ppccom_execute_tlbl, ppc); // callc ppccom_execute_tlbl,ppc |
| 3223 | assert(m_cap & PPCCAP_603_MMU); |
| 3224 | UML_MOV(block, mem(&m_core->param0), R32(G_RB(op))); // mov [param0],rb |
| 3225 | UML_MOV(block, mem(&m_core->param1), 0); // mov [param1],0 |
| 3226 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbl, this); // callc ppccom_execute_tlbl,ppc |
| 3708 | 3227 | return TRUE; |
| 3709 | 3228 | |
| 3710 | 3229 | case 0x3f2: /* TLBLI */ |
| 3711 | | assert(ppc->cap & PPCCAP_603_MMU); |
| 3712 | | UML_MOV(block, mem(&ppc->param0), R32(G_RB(op))); // mov [param0],rb |
| 3713 | | UML_MOV(block, mem(&ppc->param1), 1); // mov [param1],1 |
| 3714 | | UML_CALLC(block, (c_function)ppccom_execute_tlbl, ppc); // callc ppccom_execute_tlbl,ppc |
| 3230 | assert(m_cap & PPCCAP_603_MMU); |
| 3231 | UML_MOV(block, mem(&m_core->param0), R32(G_RB(op))); // mov [param0],rb |
| 3232 | UML_MOV(block, mem(&m_core->param1), 1); // mov [param1],1 |
| 3233 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbl, this); // callc ppccom_execute_tlbl,ppc |
| 3715 | 3234 | return TRUE; |
| 3716 | 3235 | |
| 3717 | 3236 | case 0x013: /* MFCR */ |
| r31142 | r31143 | |
| 3747 | 3266 | UML_OR(block, R32(G_RD(op)), SPR32(spr), I0); // or [rd],[xer],i0 |
| 3748 | 3267 | } |
| 3749 | 3268 | else if (spr == SPROEA_PVR) |
| 3750 | | UML_MOV(block, R32(G_RD(op)), ppc->flavor); // mov rd,flavor |
| 3269 | UML_MOV(block, R32(G_RD(op)), m_flavor); // mov rd,flavor |
| 3751 | 3270 | else |
| 3752 | 3271 | { |
| 3753 | | generate_update_cycles(ppc, block, compiler, desc->pc, TRUE); // <update cycles> |
| 3754 | | UML_MOV(block, mem(&ppc->param0), spr); // mov [param0],spr |
| 3755 | | UML_CALLC(block, (c_function)ppccom_execute_mfspr, ppc); // callc ppccom_execute_mfspr,ppc |
| 3756 | | UML_MOV(block, R32(G_RD(op)), mem(&ppc->param1)); // mov rd,[param1] |
| 3272 | generate_update_cycles(block, compiler, desc->pc, TRUE); // <update cycles> |
| 3273 | UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr |
| 3274 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_mfspr, this); // callc ppccom_execute_mfspr,ppc |
| 3275 | UML_MOV(block, R32(G_RD(op)), mem(&m_core->param1)); // mov rd,[param1] |
| 3757 | 3276 | } |
| 3758 | 3277 | return TRUE; |
| 3759 | 3278 | } |
| r31142 | r31143 | |
| 3764 | 3283 | |
| 3765 | 3284 | case 0x293: /* MFSRIN */ |
| 3766 | 3285 | UML_SHR(block, I0, R32(G_RB(op)), 28); // shr i0,G_RB,28 |
| 3767 | | UML_LOAD(block, R32(G_RD(op)), &ppc->sr[0], I0, SIZE_DWORD, SCALE_x4); // load rd,sr,i0,dword |
| 3286 | UML_LOAD(block, R32(G_RD(op)), &m_core->sr[0], I0, SIZE_DWORD, SCALE_x4); // load rd,sr,i0,dword |
| 3768 | 3287 | return TRUE; |
| 3769 | 3288 | |
| 3770 | 3289 | case 0x173: /* MFTB */ |
| r31142 | r31143 | |
| 3772 | 3291 | UINT32 tbr = compute_spr(G_SPR(op)); |
| 3773 | 3292 | if (tbr != SPRVEA_TBL_R && tbr != SPRVEA_TBU_R) |
| 3774 | 3293 | return FALSE; |
| 3775 | | generate_update_cycles(ppc, block, compiler, desc->pc, TRUE); // <update cycles> |
| 3776 | | UML_MOV(block, mem(&ppc->param0), tbr); // mov [param0],tbr |
| 3777 | | UML_CALLC(block, (c_function)ppccom_execute_mftb, ppc); // callc ppccom_execute_mftb,ppc |
| 3778 | | UML_MOV(block, R32(G_RD(op)), mem(&ppc->param1)); // mov rd,[param1] |
| 3294 | generate_update_cycles(block, compiler, desc->pc, TRUE); // <update cycles> |
| 3295 | UML_MOV(block, mem(&m_core->param0), tbr); // mov [param0],tbr |
| 3296 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_mftb, this); // callc ppccom_execute_mftb,ppc |
| 3297 | UML_MOV(block, R32(G_RD(op)), mem(&m_core->param1)); // mov rd,[param1] |
| 3779 | 3298 | return TRUE; |
| 3780 | 3299 | } |
| 3781 | 3300 | |
| r31142 | r31143 | |
| 3792 | 3311 | return TRUE; |
| 3793 | 3312 | |
| 3794 | 3313 | case 0x092: /* MTMSR */ |
| 3795 | | if (ppc->cap & PPCCAP_603_MMU) |
| 3314 | if (m_cap & PPCCAP_603_MMU) |
| 3796 | 3315 | UML_XOR(block, I0, MSR32, R32(G_RS(op))); // xor i0,msr32,rs |
| 3797 | 3316 | UML_MOV(block, MSR32, R32(G_RS(op))); // mov msr,rs |
| 3798 | | if (ppc->cap & PPCCAP_603_MMU) |
| 3317 | if (m_cap & PPCCAP_603_MMU) |
| 3799 | 3318 | { |
| 3800 | 3319 | UML_TEST(block, I0, MSR603_TGPR); // test i0,tgpr |
| 3801 | | UML_CALLHc(block, COND_NZ, *ppc->impstate->swap_tgpr); // callh swap_tgpr,nz |
| 3320 | UML_CALLHc(block, COND_NZ, *m_swap_tgpr); // callh swap_tgpr,nz |
| 3802 | 3321 | } |
| 3803 | | generate_update_mode(ppc, block); // <update mode> |
| 3322 | generate_update_mode(block); // <update mode> |
| 3804 | 3323 | return TRUE; |
| 3805 | 3324 | |
| 3806 | 3325 | case 0x1d3: /* MTSPR */ |
| r31142 | r31143 | |
| 3817 | 3336 | ; // read only |
| 3818 | 3337 | else |
| 3819 | 3338 | { |
| 3820 | | generate_update_cycles(ppc, block, compiler, desc->pc, TRUE); // <update cycles> |
| 3821 | | UML_MOV(block, mem(&ppc->param0), spr); // mov [param0],spr |
| 3822 | | UML_MOV(block, mem(&ppc->param1), R32(G_RS(op))); // mov [param1],rs |
| 3823 | | UML_CALLC(block, (c_function)ppccom_execute_mtspr, ppc); // callc ppccom_execute_mtspr,ppc |
| 3339 | generate_update_cycles(block, compiler, desc->pc, TRUE); // <update cycles> |
| 3340 | UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr |
| 3341 | UML_MOV(block, mem(&m_core->param1), R32(G_RS(op))); // mov [param1],rs |
| 3342 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_mtspr, this); // callc ppccom_execute_mtspr,ppc |
| 3824 | 3343 | compiler->checkints = TRUE; |
| 3825 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3344 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3826 | 3345 | } |
| 3827 | 3346 | return TRUE; |
| 3828 | 3347 | } |
| 3829 | 3348 | |
| 3830 | 3349 | case 0x0d2: /* MTSR */ |
| 3831 | 3350 | UML_MOV(block, SR32(G_SR(op)), R32(G_RS(op))); // mov sr[G_SR],rs |
| 3832 | | UML_CALLC(block, (c_function)ppccom_tlb_flush, ppc); // callc ppccom_tlb_flush,ppc |
| 3351 | UML_CALLC(block, (c_function)cfunc_ppccom_tlb_flush, this); // callc ppccom_tlb_flush,ppc |
| 3833 | 3352 | return TRUE; |
| 3834 | 3353 | |
| 3835 | 3354 | case 0x0f2: /* MTSRIN */ |
| 3836 | 3355 | UML_SHR(block, I0, R32(G_RB(op)), 28); // shr i0,G_RB,28 |
| 3837 | | UML_STORE(block, &ppc->sr[0], I0, R32(G_RS(op)), SIZE_DWORD, SCALE_x4); // store sr,i0,rs,dword |
| 3838 | | UML_CALLC(block, (c_function)ppccom_tlb_flush, ppc); // callc ppccom_tlb_flush,ppc |
| 3356 | UML_STORE(block, &m_core->sr[0], I0, R32(G_RS(op)), SIZE_DWORD, SCALE_x4); // store sr,i0,rs,dword |
| 3357 | UML_CALLC(block, (c_function)cfunc_ppccom_tlb_flush, this); // callc ppccom_tlb_flush,ppc |
| 3839 | 3358 | return TRUE; |
| 3840 | 3359 | |
| 3841 | 3360 | case 0x200: /* MCRXR */ |
| r31142 | r31143 | |
| 3849 | 3368 | case 0x106: /* ICBT */ |
| 3850 | 3369 | case 0x1c6: /* DCCCI */ |
| 3851 | 3370 | case 0x3c6: /* ICCCI */ |
| 3852 | | assert(ppc->cap & PPCCAP_4XX); |
| 3371 | assert(m_cap & PPCCAP_4XX); |
| 3853 | 3372 | /* effective no-nop */ |
| 3854 | 3373 | return TRUE; |
| 3855 | 3374 | |
| 3856 | 3375 | case 0x1e6: /* DCREAD */ |
| 3857 | 3376 | case 0x3e6: /* ICREAD */ |
| 3858 | | assert(ppc->cap & PPCCAP_4XX); |
| 3377 | assert(m_cap & PPCCAP_4XX); |
| 3859 | 3378 | UML_MOV(block, R32(G_RT(op)), 0); // mov rt,0 |
| 3860 | 3379 | return TRUE; |
| 3861 | 3380 | |
| 3862 | 3381 | case 0x143: /* MFDCR */ |
| 3863 | 3382 | { |
| 3864 | 3383 | UINT32 spr = compute_spr(G_SPR(op)); |
| 3865 | | assert(ppc->cap & PPCCAP_4XX); |
| 3866 | | generate_update_cycles(ppc, block, compiler, desc->pc, TRUE); // <update cycles> |
| 3867 | | UML_MOV(block, mem(&ppc->param0), spr); // mov [param0],spr |
| 3868 | | UML_CALLC(block, (c_function)ppccom_execute_mfdcr, ppc); // callc ppccom_execute_mfdcr,ppc |
| 3869 | | UML_MOV(block, R32(G_RD(op)), mem(&ppc->param1)); // mov rd,[param1] |
| 3384 | assert(m_cap & PPCCAP_4XX); |
| 3385 | generate_update_cycles(block, compiler, desc->pc, TRUE); // <update cycles> |
| 3386 | UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr |
| 3387 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_mfdcr, this); // callc ppccom_execute_mfdcr,ppc |
| 3388 | UML_MOV(block, R32(G_RD(op)), mem(&m_core->param1)); // mov rd,[param1] |
| 3870 | 3389 | return TRUE; |
| 3871 | 3390 | } |
| 3872 | 3391 | |
| 3873 | 3392 | case 0x1c3: /* MTDCR */ |
| 3874 | 3393 | { |
| 3875 | 3394 | UINT32 spr = compute_spr(G_SPR(op)); |
| 3876 | | assert(ppc->cap & PPCCAP_4XX); |
| 3877 | | generate_update_cycles(ppc, block, compiler, desc->pc, TRUE); // <update cycles> |
| 3878 | | UML_MOV(block, mem(&ppc->param0), spr); // mov [param0],spr |
| 3879 | | UML_MOV(block, mem(&ppc->param1), R32(G_RS(op))); // mov [param1],rs |
| 3880 | | UML_CALLC(block, (c_function)ppccom_execute_mtdcr, ppc); // callc ppccom_execute_mtdcr,ppc |
| 3395 | assert(m_cap & PPCCAP_4XX); |
| 3396 | generate_update_cycles(block, compiler, desc->pc, TRUE); // <update cycles> |
| 3397 | UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr |
| 3398 | UML_MOV(block, mem(&m_core->param1), R32(G_RS(op))); // mov [param1],rs |
| 3399 | UML_CALLC(block, (c_function)cfunc_ppccom_execute_mtdcr, this); // callc ppccom_execute_mtdcr,ppc |
| 3881 | 3400 | compiler->checkints = TRUE; |
| 3882 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3401 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3883 | 3402 | return TRUE; |
| 3884 | 3403 | } |
| 3885 | 3404 | |
| 3886 | 3405 | case 0x083: /* WRTEE */ |
| 3887 | | assert(ppc->cap & PPCCAP_4XX); |
| 3406 | assert(m_cap & PPCCAP_4XX); |
| 3888 | 3407 | UML_ROLINS(block, MSR32, R32(G_RS(op)), 0, MSR_EE); // rolins msr,rs,0,MSR_EE |
| 3889 | 3408 | compiler->checkints = TRUE; |
| 3890 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3409 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3891 | 3410 | return TRUE; |
| 3892 | 3411 | |
| 3893 | 3412 | case 0x0a3: /* WRTEEI */ |
| 3894 | | assert(ppc->cap & PPCCAP_4XX); |
| 3413 | assert(m_cap & PPCCAP_4XX); |
| 3895 | 3414 | if (op & MSR_EE) |
| 3896 | 3415 | { |
| 3897 | 3416 | UML_OR(block, MSR32, MSR32, MSR_EE); // or msr,msr,MSR_EE |
| 3898 | 3417 | compiler->checkints = TRUE; |
| 3899 | | generate_update_cycles(ppc, block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3418 | generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // <update cycles> |
| 3900 | 3419 | } |
| 3901 | 3420 | else |
| 3902 | 3421 | UML_AND(block, MSR32, MSR32, ~MSR_EE); // and msr,msr,~MSR_EE |
| r31142 | r31143 | |
| 3917 | 3436 | the 0x3b group |
| 3918 | 3437 | -------------------------------------------------*/ |
| 3919 | 3438 | |
| 3920 | | static int generate_instruction_3b(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 3439 | int ppc_device::generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 3921 | 3440 | { |
| 3922 | 3441 | UINT32 op = desc->opptr.l[0]; |
| 3923 | 3442 | UINT32 opswitch = (op >> 1) & 0x1f; |
| r31142 | r31143 | |
| 3925 | 3444 | switch (opswitch) |
| 3926 | 3445 | { |
| 3927 | 3446 | case 0x15: /* FADDSx */ |
| 3928 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3929 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3447 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3448 | return generate_instruction_3f(block, compiler, desc); |
| 3930 | 3449 | UML_FDADD(block, F0, F64(G_RA(op)), F64(G_RB(op))); // fdadd f0,ra,rb |
| 3931 | 3450 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3932 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3451 | generate_fp_flags(block, desc, TRUE); |
| 3933 | 3452 | return TRUE; |
| 3934 | 3453 | |
| 3935 | 3454 | case 0x14: /* FSUBSx */ |
| 3936 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3937 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3455 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3456 | return generate_instruction_3f(block, compiler, desc); |
| 3938 | 3457 | UML_FDSUB(block, F0, F64(G_RA(op)), F64(G_RB(op))); // fdsub f0,ra,rb |
| 3939 | 3458 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3940 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3459 | generate_fp_flags(block, desc, TRUE); |
| 3941 | 3460 | return TRUE; |
| 3942 | 3461 | |
| 3943 | 3462 | case 0x19: /* FMULSx */ |
| 3944 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3945 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3463 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3464 | return generate_instruction_3f(block, compiler, desc); |
| 3946 | 3465 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3947 | 3466 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3948 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3467 | generate_fp_flags(block, desc, TRUE); |
| 3949 | 3468 | return TRUE; |
| 3950 | 3469 | |
| 3951 | 3470 | case 0x12: /* FDIVSx */ |
| 3952 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3953 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3471 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3472 | return generate_instruction_3f(block, compiler, desc); |
| 3954 | 3473 | UML_FDDIV(block, F0, F64(G_RA(op)), F64(G_RB(op))); // fddiv f0,ra,rb |
| 3955 | 3474 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3956 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3475 | generate_fp_flags(block, desc, TRUE); |
| 3957 | 3476 | return TRUE; |
| 3958 | 3477 | |
| 3959 | 3478 | case 0x16: /* FSQRTSx */ |
| 3960 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3961 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3479 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3480 | return generate_instruction_3f(block, compiler, desc); |
| 3962 | 3481 | UML_FDSQRT(block, F0, F64(G_RB(op))); // fdsqrt f0,rb |
| 3963 | 3482 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3964 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3483 | generate_fp_flags(block, desc, TRUE); |
| 3965 | 3484 | return TRUE; |
| 3966 | 3485 | |
| 3967 | 3486 | case 0x18: /* FRESx */ |
| 3968 | 3487 | UML_FSFRFLT(block, F0, F64(G_RB(op)), SIZE_QWORD); // fsfrlt f0,rb,qword |
| 3969 | 3488 | UML_FSRECIP(block, F0, F0); // fsrecip f0,f0 |
| 3970 | 3489 | UML_FDFRFLT(block, F64(G_RD(op)), F0, SIZE_DWORD); // fdfrflt rd,f0,dword |
| 3971 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3490 | generate_fp_flags(block, desc, TRUE); |
| 3972 | 3491 | return TRUE; |
| 3973 | 3492 | |
| 3974 | 3493 | case 0x1d: /* FMADDSx */ |
| 3975 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3976 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3494 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3495 | return generate_instruction_3f(block, compiler, desc); |
| 3977 | 3496 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3978 | 3497 | UML_FDADD(block, F0, F0, F64(G_RB(op))); // fdadd f0,f0,rb |
| 3979 | 3498 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3980 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3499 | generate_fp_flags(block, desc, TRUE); |
| 3981 | 3500 | return TRUE; |
| 3982 | 3501 | |
| 3983 | 3502 | case 0x1c: /* FMSUBSx */ |
| 3984 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3985 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3503 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3504 | return generate_instruction_3f(block, compiler, desc); |
| 3986 | 3505 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3987 | 3506 | UML_FDSUB(block, F0, F0, F64(G_RB(op))); // fdsub f0,f0,rb |
| 3988 | 3507 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3989 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3508 | generate_fp_flags(block, desc, TRUE); |
| 3990 | 3509 | return TRUE; |
| 3991 | 3510 | |
| 3992 | 3511 | case 0x1f: /* FNMADDSx */ |
| 3993 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3994 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3512 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3513 | return generate_instruction_3f(block, compiler, desc); |
| 3995 | 3514 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3996 | 3515 | UML_FDADD(block, F0, F0, F64(G_RB(op))); // fdadd f0,f0,rb |
| 3997 | 3516 | UML_FDNEG(block, F0, F0); // fdneg f0,f0 |
| 3998 | 3517 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 3999 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3518 | generate_fp_flags(block, desc, TRUE); |
| 4000 | 3519 | return TRUE; |
| 4001 | 3520 | |
| 4002 | 3521 | case 0x1e: /* FNMSUBSx */ |
| 4003 | | if (!(ppc->impstate->drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 4004 | | return generate_instruction_3f(ppc, block, compiler, desc); |
| 3522 | if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) |
| 3523 | return generate_instruction_3f(block, compiler, desc); |
| 4005 | 3524 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 4006 | 3525 | UML_FDSUB(block, F0, F64(G_RB(op)), F0); // fdsub f0,rb,f0 |
| 4007 | 3526 | UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 |
| 4008 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3527 | generate_fp_flags(block, desc, TRUE); |
| 4009 | 3528 | return TRUE; |
| 4010 | 3529 | } |
| 4011 | 3530 | |
| r31142 | r31143 | |
| 4019 | 3538 | the 0x3f group |
| 4020 | 3539 | -------------------------------------------------*/ |
| 4021 | 3540 | |
| 4022 | | static int generate_instruction_3f(powerpc_state *ppc, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 3541 | int ppc_device::generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 4023 | 3542 | { |
| 4024 | 3543 | UINT32 op = desc->opptr.l[0]; |
| 4025 | 3544 | UINT32 opswitch = (op >> 1) & 0x3ff; |
| r31142 | r31143 | |
| 4031 | 3550 | { |
| 4032 | 3551 | case 0x15: /* FADDx */ |
| 4033 | 3552 | UML_FDADD(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdadd rd,ra,rb |
| 4034 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3553 | generate_fp_flags(block, desc, TRUE); |
| 4035 | 3554 | return TRUE; |
| 4036 | 3555 | |
| 4037 | 3556 | case 0x14: /* FSUBx */ |
| 4038 | 3557 | UML_FDSUB(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdsub rd,ra,rb |
| 4039 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3558 | generate_fp_flags(block, desc, TRUE); |
| 4040 | 3559 | return TRUE; |
| 4041 | 3560 | |
| 4042 | 3561 | case 0x19: /* FMULx */ |
| 4043 | 3562 | UML_FDMUL(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_REGC(op))); // fdmul rd,ra,rc |
| 4044 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3563 | generate_fp_flags(block, desc, TRUE); |
| 4045 | 3564 | return TRUE; |
| 4046 | 3565 | |
| 4047 | 3566 | case 0x12: /* FDIVx */ |
| 4048 | 3567 | UML_FDDIV(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fddiv rd,ra,rb |
| 4049 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3568 | generate_fp_flags(block, desc, TRUE); |
| 4050 | 3569 | return TRUE; |
| 4051 | 3570 | |
| 4052 | 3571 | case 0x16: /* FSQRTx */ |
| 4053 | 3572 | UML_FDSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdsqrt rd,rb |
| 4054 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3573 | generate_fp_flags(block, desc, TRUE); |
| 4055 | 3574 | return TRUE; |
| 4056 | 3575 | |
| 4057 | 3576 | case 0x1a: /* FRSQRTEx */ |
| 4058 | 3577 | UML_FDRSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdrsqrt rd,rb |
| 4059 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3578 | generate_fp_flags(block, desc, TRUE); |
| 4060 | 3579 | return TRUE; |
| 4061 | 3580 | |
| 4062 | 3581 | case 0x17: /* FSELx */ |
| 4063 | | UML_FDCMP(block, F64(G_RA(op)), mem(&ppc->impstate->fp0)); // fdcmp f0,ra,[fp0] |
| 3582 | UML_FDCMP(block, F64(G_RA(op)), mem(&m_core->fp0)); // fdcmp f0,ra,[fp0] |
| 4064 | 3583 | UML_FDMOVc(block, COND_AE, F64(G_RD(op)), F64(G_REGC(op))); // fdmov rd,rc,AE |
| 4065 | 3584 | UML_FDMOVc(block, COND_B, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb,B |
| 4066 | 3585 | return TRUE; |
| r31142 | r31143 | |
| 4068 | 3587 | case 0x1d: /* FMADDx */ |
| 4069 | 3588 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 4070 | 3589 | UML_FDADD(block, F64(G_RD(op)), F0, F64(G_RB(op))); // fdadd rd,f0,rb |
| 4071 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3590 | generate_fp_flags(block, desc, TRUE); |
| 4072 | 3591 | return TRUE; |
| 4073 | 3592 | |
| 4074 | 3593 | case 0x1f: /* FNMADDx */ |
| 4075 | 3594 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 4076 | 3595 | UML_FDADD(block, F0, F0, F64(G_RB(op))); // fdadd f0,f0,rb |
| 4077 | 3596 | UML_FDNEG(block, F64(G_RD(op)), F0); // fdneg rd,f0 |
| 4078 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3597 | generate_fp_flags(block, desc, TRUE); |
| 4079 | 3598 | return TRUE; |
| 4080 | 3599 | |
| 4081 | 3600 | case 0x1c: /* FMSUBx */ |
| 4082 | 3601 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 4083 | 3602 | UML_FDSUB(block, F64(G_RD(op)), F0, F64(G_RB(op))); // fdsub rd,f0,rb |
| 4084 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3603 | generate_fp_flags(block, desc, TRUE); |
| 4085 | 3604 | return TRUE; |
| 4086 | 3605 | |
| 4087 | 3606 | case 0x1e: /* FNMSUBx */ |
| 4088 | 3607 | UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 4089 | 3608 | UML_FDSUB(block, F64(G_RD(op)), F64(G_RB(op)), F0); // fdsub rd,rb,f0 |
| 4090 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3609 | generate_fp_flags(block, desc, TRUE); |
| 4091 | 3610 | return TRUE; |
| 4092 | 3611 | } |
| 4093 | 3612 | } |
| r31142 | r31143 | |
| 4104 | 3623 | case 0x020: /* FCMPO */ |
| 4105 | 3624 | UML_FDCMP(block, F64(G_RA(op)), F64(G_RB(op))); // fdcmp ra,rb |
| 4106 | 3625 | UML_GETFLGS(block, I0, FLAG_C | FLAG_Z | FLAG_U); // getflgs i0,czu |
| 4107 | | UML_LOAD(block, I0, ppc->impstate->fcmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,fcmp_cr_table,i0,byte |
| 3626 | UML_LOAD(block, I0, m_fcmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,fcmp_cr_table,i0,byte |
| 4108 | 3627 | UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] |
| 4109 | 3628 | return TRUE; |
| 4110 | 3629 | |
| 4111 | 3630 | case 0x00c: /* FRSPx */ |
| 4112 | 3631 | UML_FDRNDS(block, F64(G_RD(op)), F64(G_RB(op))); // fdrnds rd,rb |
| 4113 | | generate_fp_flags(ppc, block, desc, TRUE); |
| 3632 | generate_fp_flags(block, desc, TRUE); |
| 4114 | 3633 | return TRUE; |
| 4115 | 3634 | |
| 4116 | 3635 | case 0x00e: /* FCTIWx */ |
| 4117 | 3636 | UML_FDTOINT(block, I0, F64(G_RB(op)), SIZE_DWORD, ROUND_DEFAULT); // fdtoint i0,rb,dword,default |
| 4118 | | UML_DAND(block, mem(&ppc->impstate->tempdata.w.l), I0, 0xffffffff);// dand i0,i0,0xffffffff |
| 4119 | | UML_FDMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.w.l)); // fdmovr rd,i0 |
| 3637 | UML_DAND(block, mem(&m_core->tempdata.w.l), I0, 0xffffffff);// dand i0,i0,0xffffffff |
| 3638 | UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l)); // fdmovr rd,i0 |
| 4120 | 3639 | return TRUE; |
| 4121 | 3640 | |
| 4122 | 3641 | case 0x00f: /* FCTIWZx */ |
| 4123 | 3642 | UML_FDTOINT(block, I0, F64(G_RB(op)), SIZE_DWORD, ROUND_TRUNC); // fdtoint i0,rb,dword,default |
| 4124 | | UML_DAND(block, mem(&ppc->impstate->tempdata.w.l), I0, 0xffffffff);// dand i0,i0,0xffffffff |
| 4125 | | UML_FDMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.w.l)); // fdmovr rd,i0 |
| 3643 | UML_DAND(block, mem(&m_core->tempdata.w.l), I0, 0xffffffff);// dand i0,i0,0xffffffff |
| 3644 | UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l)); // fdmovr rd,i0 |
| 4126 | 3645 | return TRUE; |
| 4127 | 3646 | |
| 4128 | 3647 | case 0x028: /* FNEGx */ |
| r31142 | r31143 | |
| 4157 | 3676 | return TRUE; |
| 4158 | 3677 | |
| 4159 | 3678 | case 0x247: /* MFFSx */ |
| 4160 | | UML_MOV(block, mem(&ppc->impstate->tempdata.w.l), FPSCR32); // mov [tempdata],fpscr |
| 4161 | | UML_FSMOV(block, F64(G_RD(op)), mem(&ppc->impstate->tempdata.d)); // fsmov rd,fpscr |
| 3679 | UML_MOV(block, mem(&m_core->tempdata.w.l), FPSCR32); // mov [tempdata],fpscr |
| 3680 | UML_FSMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fsmov rd,fpscr |
| 4162 | 3681 | return TRUE; |
| 4163 | 3682 | |
| 4164 | 3683 | case 0x2c7: /* MTFSFx */ |
| 4165 | | UML_FDMOV(block, mem(&ppc->impstate->tempdata.d), F64(G_RB(op))); // fdmov [tempdata],fb |
| 4166 | | UML_ROLINS(block, FPSCR32, mem(&ppc->impstate->tempdata.w.l), 0, compute_crf_mask(G_FM(op))); |
| 3684 | UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RB(op))); // fdmov [tempdata],fb |
| 3685 | UML_ROLINS(block, FPSCR32, mem(&m_core->tempdata.w.l), 0, compute_crf_mask(G_FM(op))); |
| 4167 | 3686 | // rolins fpscr,rb,0,crf_mask |
| 4168 | 3687 | return TRUE; |
| 4169 | 3688 | |
| r31142 | r31143 | |
| 4188 | 3707 | including disassembly of a PowerPC instruction |
| 4189 | 3708 | -------------------------------------------------*/ |
| 4190 | 3709 | |
| 4191 | | static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) |
| 3710 | void ppc_device::log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) |
| 4192 | 3711 | { |
| 4193 | 3712 | char buffer[100]; |
| 4194 | 3713 | if (LOG_UML) |
| r31142 | r31143 | |
| 4205 | 3724 | flags |
| 4206 | 3725 | -------------------------------------------------*/ |
| 4207 | 3726 | |
| 4208 | | static const char *log_desc_flags_to_string(UINT32 flags) |
| 3727 | const char *ppc_device::log_desc_flags_to_string(UINT32 flags) |
| 4209 | 3728 | { |
| 4210 | 3729 | static char tempbuf[30]; |
| 4211 | 3730 | char *dest = tempbuf; |
| r31142 | r31143 | |
| 4259 | 3778 | log_register_list - log a list of GPR registers |
| 4260 | 3779 | -------------------------------------------------*/ |
| 4261 | 3780 | |
| 4262 | | static void log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist) |
| 3781 | void ppc_device::log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist) |
| 4263 | 3782 | { |
| 4264 | 3783 | static const char *const crtext[4] = { "lt", "gt", "eq", "so" }; |
| 4265 | 3784 | int count = 0; |
| r31142 | r31143 | |
| 4362 | 3881 | log_opcode_desc - log a list of descriptions |
| 4363 | 3882 | -------------------------------------------------*/ |
| 4364 | 3883 | |
| 4365 | | static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) |
| 3884 | void ppc_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) |
| 4366 | 3885 | { |
| 4367 | 3886 | /* open the file, creating it if necessary */ |
| 4368 | 3887 | if (indent == 0) |
| r31142 | r31143 | |
| 4401 | 3920 | } |
| 4402 | 3921 | } |
| 4403 | 3922 | |
| 4404 | | |
| 4405 | | |
| 4406 | | /*************************************************************************** |
| 4407 | | PPC 4XX VARIANTS |
| 4408 | | ***************************************************************************/ |
| 4409 | | |
| 4410 | | /*------------------------------------------------- |
| 4411 | | ppcdrc4xx_get_info - PowerPC 4XX-specific |
| 4412 | | information getter |
| 4413 | | -------------------------------------------------*/ |
| 4414 | | |
| 4415 | | static CPU_GET_INFO( ppcdrc4xx ) |
| 4416 | | { |
| 4417 | | powerpc_state *ppc = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; |
| 4418 | | CPU_GET_INFO_CALL(ppcdrc); |
| 4419 | | ppc4xx_get_info(ppc, state, info); |
| 4420 | | } |
| 4421 | | |
| 4422 | | |
| 4423 | | /*------------------------------------------------- |
| 4424 | | ppcdrc4xx_set_info - PowerPC 4XX-specific |
| 4425 | | information setter |
| 4426 | | -------------------------------------------------*/ |
| 4427 | | |
| 4428 | | static CPU_SET_INFO( ppcdrc4xx ) |
| 4429 | | { |
| 4430 | | powerpc_state *ppc = get_safe_token(device); |
| 4431 | | CPU_SET_INFO_CALL(ppcdrc); |
| 4432 | | ppc4xx_set_info(ppc, state, info); |
| 4433 | | } |
| 4434 | | |
| 4435 | | |
| 4436 | | /*------------------------------------------------- |
| 4437 | | ppc403ga_init - PowerPC 403GA-specific |
| 4438 | | initialization |
| 4439 | | -------------------------------------------------*/ |
| 4440 | | |
| 4441 | | static CPU_INIT( ppc403ga ) |
| 4442 | | { |
| 4443 | | ppcdrc_init(PPC_MODEL_403GA, PPCCAP_4XX, 1, device, irqcallback); |
| 4444 | | } |
| 4445 | | |
| 4446 | | |
| 4447 | | /*------------------------------------------------- |
| 4448 | | ppc403ga_get_info - PowerPC 403GA-specific |
| 4449 | | information getter |
| 4450 | | -------------------------------------------------*/ |
| 4451 | | |
| 4452 | | CPU_GET_INFO( ppc403ga ) |
| 4453 | | { |
| 4454 | | switch (state) |
| 4455 | | { |
| 4456 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4457 | | |
| 4458 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4459 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc403ga); break; |
| 4460 | | case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppcdrc4xx); break; |
| 4461 | | |
| 4462 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4463 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 403GA"); break; |
| 4464 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc403ga"); break; |
| 4465 | | |
| 4466 | | /* --- everything else is handled generically --- */ |
| 4467 | | default: CPU_GET_INFO_CALL(ppcdrc4xx); break; |
| 4468 | | } |
| 4469 | | } |
| 4470 | | |
| 4471 | | |
| 4472 | | /*------------------------------------------------- |
| 4473 | | ppc403gcx_init - PowerPC 403GCX-specific |
| 4474 | | initialization |
| 4475 | | -------------------------------------------------*/ |
| 4476 | | |
| 4477 | | static CPU_INIT( ppc403gcx ) |
| 4478 | | { |
| 4479 | | ppcdrc_init(PPC_MODEL_403GCX, PPCCAP_4XX, 1, device, irqcallback); |
| 4480 | | } |
| 4481 | | |
| 4482 | | |
| 4483 | | /*------------------------------------------------- |
| 4484 | | ppc403gcx_get_info - PowerPC 403GCX-specific |
| 4485 | | information getter |
| 4486 | | -------------------------------------------------*/ |
| 4487 | | |
| 4488 | | CPU_GET_INFO( ppc403gcx ) |
| 4489 | | { |
| 4490 | | switch (state) |
| 4491 | | { |
| 4492 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4493 | | |
| 4494 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4495 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc403gcx); break; |
| 4496 | | case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppcdrc4xx); break; |
| 4497 | | |
| 4498 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4499 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 403GCX"); break; |
| 4500 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc403gcx"); break; |
| 4501 | | |
| 4502 | | /* --- everything else is handled generically --- */ |
| 4503 | | default: CPU_GET_INFO_CALL(ppcdrc4xx); break; |
| 4504 | | } |
| 4505 | | } |
| 4506 | | |
| 4507 | | |
| 4508 | | |
| 4509 | | /*------------------------------------------------- |
| 4510 | | ppc405gp_init - PowerPC 405GP-specific |
| 4511 | | initialization |
| 4512 | | -------------------------------------------------*/ |
| 4513 | | |
| 4514 | | static CPU_INIT( ppc405gp ) |
| 4515 | | { |
| 4516 | | ppcdrc_init(PPC_MODEL_405GP, PPCCAP_4XX | PPCCAP_VEA, 1, device, irqcallback); |
| 4517 | | } |
| 4518 | | |
| 4519 | | |
| 4520 | | /*------------------------------------------------- |
| 4521 | | ppc405gp_get_info - PowerPC 405GP-specific |
| 4522 | | information getter |
| 4523 | | -------------------------------------------------*/ |
| 4524 | | |
| 4525 | | CPU_GET_INFO( ppc405gp ) |
| 4526 | | { |
| 4527 | | switch (state) |
| 4528 | | { |
| 4529 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4530 | | |
| 4531 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4532 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc405gp); break; |
| 4533 | | case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppcdrc4xx); break; |
| 4534 | | |
| 4535 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4536 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 405GP"); break; |
| 4537 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc405gp"); break; |
| 4538 | | |
| 4539 | | /* --- everything else is handled generically --- */ |
| 4540 | | default: CPU_GET_INFO_CALL(ppcdrc4xx); break; |
| 4541 | | } |
| 4542 | | } |
| 4543 | | |
| 4544 | | |
| 4545 | | /*************************************************************************** |
| 4546 | | PPC 6XX VARIANTS |
| 4547 | | ***************************************************************************/ |
| 4548 | | |
| 4549 | | /*------------------------------------------------- |
| 4550 | | ppc601_init - PowerPC 601-specific |
| 4551 | | initialization |
| 4552 | | -------------------------------------------------*/ |
| 4553 | | |
| 4554 | | static CPU_INIT( ppc601 ) |
| 4555 | | { |
| 4556 | | ppcdrc_init(PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT, 0/* no TB */, device, irqcallback); |
| 4557 | | } |
| 4558 | | |
| 4559 | | |
| 4560 | | /*------------------------------------------------- |
| 4561 | | ppc601_get_info - PowerPC 601-specific |
| 4562 | | information getter |
| 4563 | | -------------------------------------------------*/ |
| 4564 | | |
| 4565 | | CPU_GET_INFO( ppc601 ) |
| 4566 | | { |
| 4567 | | switch (state) |
| 4568 | | { |
| 4569 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4570 | | |
| 4571 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4572 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc601); break; |
| 4573 | | |
| 4574 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4575 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 601"); break; |
| 4576 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc601"); break; |
| 4577 | | |
| 4578 | | /* --- everything else is handled generically --- */ |
| 4579 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4580 | | } |
| 4581 | | } |
| 4582 | | |
| 4583 | | |
| 4584 | | /*------------------------------------------------- |
| 4585 | | ppc602_init - PowerPC 602-specific |
| 4586 | | initialization |
| 4587 | | -------------------------------------------------*/ |
| 4588 | | |
| 4589 | | static CPU_INIT( ppc602 ) |
| 4590 | | { |
| 4591 | | ppcdrc_init(PPC_MODEL_602, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, device, irqcallback); |
| 4592 | | } |
| 4593 | | |
| 4594 | | |
| 4595 | | /*------------------------------------------------- |
| 4596 | | ppc602_get_info - PowerPC 602-specific |
| 4597 | | information getter |
| 4598 | | -------------------------------------------------*/ |
| 4599 | | |
| 4600 | | CPU_GET_INFO( ppc602 ) |
| 4601 | | { |
| 4602 | | switch (state) |
| 4603 | | { |
| 4604 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4605 | | |
| 4606 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4607 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc602); break; |
| 4608 | | |
| 4609 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4610 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 602"); break; |
| 4611 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc602"); break; |
| 4612 | | |
| 4613 | | /* --- everything else is handled generically --- */ |
| 4614 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4615 | | } |
| 4616 | | } |
| 4617 | | |
| 4618 | | |
| 4619 | | /*------------------------------------------------- |
| 4620 | | ppc603_init - PowerPC 603-specific |
| 4621 | | initialization |
| 4622 | | -------------------------------------------------*/ |
| 4623 | | |
| 4624 | | static CPU_INIT( ppc603 ) |
| 4625 | | { |
| 4626 | | ppcdrc_init(PPC_MODEL_603, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, device, irqcallback); |
| 4627 | | } |
| 4628 | | |
| 4629 | | |
| 4630 | | /*------------------------------------------------- |
| 4631 | | ppc603_get_info - PowerPC 603-specific |
| 4632 | | information getter |
| 4633 | | -------------------------------------------------*/ |
| 4634 | | |
| 4635 | | CPU_GET_INFO( ppc603 ) |
| 4636 | | { |
| 4637 | | switch (state) |
| 4638 | | { |
| 4639 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4640 | | |
| 4641 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4642 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc603); break; |
| 4643 | | |
| 4644 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4645 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603"); break; |
| 4646 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc603"); break; |
| 4647 | | |
| 4648 | | /* --- everything else is handled generically --- */ |
| 4649 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4650 | | } |
| 4651 | | } |
| 4652 | | |
| 4653 | | |
| 4654 | | /*------------------------------------------------- |
| 4655 | | ppc603e_init - PowerPC 603e-specific |
| 4656 | | initialization |
| 4657 | | -------------------------------------------------*/ |
| 4658 | | |
| 4659 | | static CPU_INIT( ppc603e ) |
| 4660 | | { |
| 4661 | | ppcdrc_init(PPC_MODEL_603E, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, device, irqcallback); |
| 4662 | | } |
| 4663 | | |
| 4664 | | |
| 4665 | | /*------------------------------------------------- |
| 4666 | | ppc603e_get_info - PowerPC 603e-specific |
| 4667 | | information getter |
| 4668 | | -------------------------------------------------*/ |
| 4669 | | |
| 4670 | | CPU_GET_INFO( ppc603e ) |
| 4671 | | { |
| 4672 | | switch (state) |
| 4673 | | { |
| 4674 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4675 | | |
| 4676 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4677 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc603e); break; |
| 4678 | | |
| 4679 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4680 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603e"); break; |
| 4681 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc603e"); break; |
| 4682 | | |
| 4683 | | /* --- everything else is handled generically --- */ |
| 4684 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4685 | | } |
| 4686 | | } |
| 4687 | | |
| 4688 | | |
| 4689 | | /*------------------------------------------------- |
| 4690 | | ppc603r_init - PowerPC 603r-specific |
| 4691 | | initialization |
| 4692 | | -------------------------------------------------*/ |
| 4693 | | |
| 4694 | | static CPU_INIT( ppc603r ) |
| 4695 | | { |
| 4696 | | ppcdrc_init(PPC_MODEL_603R, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, device, irqcallback); |
| 4697 | | } |
| 4698 | | |
| 4699 | | |
| 4700 | | /*------------------------------------------------- |
| 4701 | | ppc603r_get_info - PowerPC 603r-specific |
| 4702 | | information getter |
| 4703 | | -------------------------------------------------*/ |
| 4704 | | |
| 4705 | | CPU_GET_INFO( ppc603r ) |
| 4706 | | { |
| 4707 | | switch (state) |
| 4708 | | { |
| 4709 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4710 | | |
| 4711 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4712 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc603r); break; |
| 4713 | | |
| 4714 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4715 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603R"); break; |
| 4716 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc603r"); break; |
| 4717 | | |
| 4718 | | /* --- everything else is handled generically --- */ |
| 4719 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4720 | | } |
| 4721 | | } |
| 4722 | | |
| 4723 | | |
| 4724 | | /*------------------------------------------------- |
| 4725 | | ppc604_init - PowerPC 604-specific |
| 4726 | | initialization |
| 4727 | | -------------------------------------------------*/ |
| 4728 | | |
| 4729 | | static CPU_INIT( ppc604 ) |
| 4730 | | { |
| 4731 | | ppcdrc_init(PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU, 4, device, irqcallback); |
| 4732 | | } |
| 4733 | | |
| 4734 | | |
| 4735 | | /*------------------------------------------------- |
| 4736 | | ppc604_get_info - PowerPC 604-specific |
| 4737 | | information getter |
| 4738 | | -------------------------------------------------*/ |
| 4739 | | |
| 4740 | | CPU_GET_INFO( ppc604 ) |
| 4741 | | { |
| 4742 | | switch (state) |
| 4743 | | { |
| 4744 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4745 | | |
| 4746 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4747 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc604); break; |
| 4748 | | |
| 4749 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4750 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 604"); break; |
| 4751 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc604"); break; |
| 4752 | | |
| 4753 | | /* --- everything else is handled generically --- */ |
| 4754 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4755 | | } |
| 4756 | | } |
| 4757 | | |
| 4758 | | |
| 4759 | | |
| 4760 | | /*************************************************************************** |
| 4761 | | MPC VARIANTS |
| 4762 | | ***************************************************************************/ |
| 4763 | | |
| 4764 | | /*------------------------------------------------- |
| 4765 | | mpc8240_init - PowerPC MPC8240-specific |
| 4766 | | initialization |
| 4767 | | -------------------------------------------------*/ |
| 4768 | | |
| 4769 | | static CPU_INIT( mpc8240 ) |
| 4770 | | { |
| 4771 | | ppcdrc_init(PPC_MODEL_MPC8240, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4/* unknown */, device, irqcallback); |
| 4772 | | } |
| 4773 | | |
| 4774 | | |
| 4775 | | /*------------------------------------------------- |
| 4776 | | mpc8240_get_info - PowerPC MPC8240-specific |
| 4777 | | information getter |
| 4778 | | -------------------------------------------------*/ |
| 4779 | | |
| 4780 | | CPU_GET_INFO( mpc8240 ) |
| 4781 | | { |
| 4782 | | switch (state) |
| 4783 | | { |
| 4784 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4785 | | |
| 4786 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4787 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(mpc8240); break; |
| 4788 | | |
| 4789 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4790 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC MPC8240"); break; |
| 4791 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "mpc8240"); break; |
| 4792 | | |
| 4793 | | /* --- everything else is handled generically --- */ |
| 4794 | | default: CPU_GET_INFO_CALL(ppcdrc); break; |
| 4795 | | } |
| 4796 | | } |
| 4797 | | |
| 4798 | | |
| 4799 | | ppc403ga_device::ppc403ga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) |
| 4800 | | : ppc4xx_device(mconfig, type, tag, owner, clock, CPU_GET_INFO_NAME(ppc403ga)) |
| 4801 | | { |
| 4802 | | } |
| 4803 | | |
| 4804 | | const device_type PPC403GA = &legacy_device_creator<ppc403ga_device>; |
| 4805 | | |
| 4806 | | ppc403gcx_device::ppc403gcx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) |
| 4807 | | : ppc4xx_device(mconfig, type, tag, owner, clock, CPU_GET_INFO_NAME(ppc403gcx)) |
| 4808 | | { |
| 4809 | | } |
| 4810 | | |
| 4811 | | const device_type PPC403GCX = &legacy_device_creator<ppc403gcx_device>; |
| 4812 | | |
| 4813 | | ppc405gp_device::ppc405gp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) |
| 4814 | | : ppc4xx_device(mconfig, type, tag, owner, clock, CPU_GET_INFO_NAME(ppc405gp)) |
| 4815 | | { |
| 4816 | | } |
| 4817 | | |
| 4818 | | const device_type PPC405GP = &legacy_device_creator<ppc405gp_device>; |
| 4819 | | |
| 4820 | | ppc4xx_device::ppc4xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, cpu_get_info_func info) |
| 4821 | | : legacy_cpu_device(mconfig, type, tag, owner, clock, info) |
| 4822 | | { |
| 4823 | | } |
| 4824 | | |
| 4825 | | DEFINE_LEGACY_CPU_DEVICE(PPC601, ppc601); |
| 4826 | | DEFINE_LEGACY_CPU_DEVICE(PPC602, ppc602); |
| 4827 | | DEFINE_LEGACY_CPU_DEVICE(PPC603, ppc603); |
| 4828 | | DEFINE_LEGACY_CPU_DEVICE(PPC603E, ppc603e); |
| 4829 | | DEFINE_LEGACY_CPU_DEVICE(PPC603R, ppc603r); |
| 4830 | | DEFINE_LEGACY_CPU_DEVICE(PPC604, ppc604); |
| 4831 | | DEFINE_LEGACY_CPU_DEVICE(MPC8240, mpc8240); |
trunk/src/emu/cpu/powerpc/ppccom.c
| r31142 | r31143 | |
| 10 | 10 | |
| 11 | 11 | #include "emu.h" |
| 12 | 12 | #include "ppccom.h" |
| 13 | #include "ppcfe.h" |
| 13 | 14 | |
| 14 | 15 | |
| 15 | 16 | /*************************************************************************** |
| r31142 | r31143 | |
| 33 | 34 | |
| 34 | 35 | |
| 35 | 36 | /*************************************************************************** |
| 36 | | FUNCTION PROTOTYPES |
| 37 | PRIVATE GLOBAL VARIABLES |
| 37 | 38 | ***************************************************************************/ |
| 38 | 39 | |
| 39 | | static TIMER_CALLBACK( ppc4xx_fit_callback ); |
| 40 | | static TIMER_CALLBACK( ppc4xx_pit_callback ); |
| 41 | | static TIMER_CALLBACK( ppc4xx_spu_callback ); |
| 42 | | static TIMER_CALLBACK( decrementer_int_callback ); |
| 40 | /* lookup table for FP modes */ |
| 41 | static const UINT8 fpmode_source[4] = |
| 42 | { |
| 43 | uml::ROUND_ROUND, |
| 44 | uml::ROUND_TRUNC, |
| 45 | uml::ROUND_CEIL, |
| 46 | uml::ROUND_FLOOR |
| 47 | }; |
| 43 | 48 | |
| 44 | | static TIMER_CALLBACK( ppc4xx_buffered_dma_callback ); |
| 49 | /* flag lookup table for SZ */ |
| 50 | static const UINT8 sz_cr_table_source[32] = |
| 51 | { |
| 52 | /* ..... */ 0x4, |
| 53 | /* ....C */ 0x4, |
| 54 | /* ...V. */ 0x4, |
| 55 | /* ...VC */ 0x4, |
| 56 | /* ..Z.. */ 0x2, |
| 57 | /* ..Z.C */ 0x2, |
| 58 | /* ..ZV. */ 0x2, |
| 59 | /* ..ZVC */ 0x2, |
| 60 | /* .S... */ 0x8, |
| 61 | /* .S..C */ 0x8, |
| 62 | /* .S.V. */ 0x8, |
| 63 | /* .S.VC */ 0x8, |
| 64 | /* .SZ.. */ 0x2, |
| 65 | /* .SZ.C */ 0x2, |
| 66 | /* .SZV. */ 0x2, |
| 67 | /* .SZVC */ 0x2, |
| 68 | /* U.... */ 0x4, |
| 69 | /* U...C */ 0x4, |
| 70 | /* U..V. */ 0x4, |
| 71 | /* U..VC */ 0x4, |
| 72 | /* U.Z.. */ 0x2, |
| 73 | /* U.Z.C */ 0x2, |
| 74 | /* U.ZV. */ 0x2, |
| 75 | /* U.ZVC */ 0x2, |
| 76 | /* US... */ 0x8, |
| 77 | /* US..C */ 0x8, |
| 78 | /* US.V. */ 0x8, |
| 79 | /* US.VC */ 0x8, |
| 80 | /* USZ.. */ 0x2, |
| 81 | /* USZ.C */ 0x2, |
| 82 | /* USZV. */ 0x2, |
| 83 | /* USZVC */ 0x2 |
| 84 | }; |
| 45 | 85 | |
| 46 | | static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state); |
| 86 | /* flag lookup table for CMP */ |
| 87 | static const UINT8 cmp_cr_table_source[32] = |
| 88 | { |
| 89 | /* ..... */ 0x4, |
| 90 | /* ....C */ 0x4, |
| 91 | /* ...V. */ 0x8, |
| 92 | /* ...VC */ 0x8, |
| 93 | /* ..Z.. */ 0x2, |
| 94 | /* ..Z.C */ 0x2, |
| 95 | /* ..ZV. */ 0x2, |
| 96 | /* ..ZVC */ 0x2, |
| 97 | /* .S... */ 0x8, |
| 98 | /* .S..C */ 0x8, |
| 99 | /* .S.V. */ 0x4, |
| 100 | /* .S.VC */ 0x4, |
| 101 | /* .SZ.. */ 0x2, |
| 102 | /* .SZ.C */ 0x2, |
| 103 | /* .SZV. */ 0x2, |
| 104 | /* .SZVC */ 0x2, |
| 105 | /* U.... */ 0x4, |
| 106 | /* U...C */ 0x4, |
| 107 | /* U..V. */ 0x8, |
| 108 | /* U..VC */ 0x8, |
| 109 | /* U.Z.. */ 0x2, |
| 110 | /* U.Z.C */ 0x2, |
| 111 | /* U.ZV. */ 0x2, |
| 112 | /* U.ZVC */ 0x2, |
| 113 | /* US... */ 0x8, |
| 114 | /* US..C */ 0x8, |
| 115 | /* US.V. */ 0x4, |
| 116 | /* US.VC */ 0x4, |
| 117 | /* USZ.. */ 0x2, |
| 118 | /* USZ.C */ 0x2, |
| 119 | /* USZV. */ 0x2, |
| 120 | /* USZVC */ 0x2 |
| 121 | }; |
| 47 | 122 | |
| 48 | | static void ppc4xx_dma_update_irq_states(powerpc_state *ppc); |
| 49 | | static int ppc4xx_dma_fetch_transmit_byte(powerpc_state *ppc, int dmachan, UINT8 *byte); |
| 50 | | static int ppc4xx_dma_handle_receive_byte(powerpc_state *ppc, int dmachan, UINT8 byte); |
| 51 | | static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan); |
| 123 | /* flag lookup table for CMPL */ |
| 124 | static const UINT8 cmpl_cr_table_source[32] = |
| 125 | { |
| 126 | /* ..... */ 0x4, |
| 127 | /* ....C */ 0x8, |
| 128 | /* ...V. */ 0x4, |
| 129 | /* ...VC */ 0x8, |
| 130 | /* ..Z.. */ 0x2, |
| 131 | /* ..Z.C */ 0x2, |
| 132 | /* ..ZV. */ 0x2, |
| 133 | /* ..ZVC */ 0x2, |
| 134 | /* .S... */ 0x4, |
| 135 | /* .S..C */ 0x8, |
| 136 | /* .S.V. */ 0x4, |
| 137 | /* .S.VC */ 0x8, |
| 138 | /* .SZ.. */ 0x2, |
| 139 | /* .SZ.C */ 0x2, |
| 140 | /* .SZV. */ 0x2, |
| 141 | /* .SZVC */ 0x2, |
| 142 | /* U.... */ 0x4, |
| 143 | /* U...C */ 0x8, |
| 144 | /* U..V. */ 0x4, |
| 145 | /* U..VC */ 0x8, |
| 146 | /* U.Z.. */ 0x2, |
| 147 | /* U.Z.C */ 0x2, |
| 148 | /* U.ZV. */ 0x2, |
| 149 | /* U.ZVC */ 0x2, |
| 150 | /* US... */ 0x4, |
| 151 | /* US..C */ 0x8, |
| 152 | /* US.V. */ 0x4, |
| 153 | /* US.VC */ 0x8, |
| 154 | /* USZ.. */ 0x2, |
| 155 | /* USZ.C */ 0x2, |
| 156 | /* USZV. */ 0x2, |
| 157 | /* USZVC */ 0x2 |
| 158 | }; |
| 52 | 159 | |
| 53 | | static void ppc4xx_spu_update_irq_states(powerpc_state *ppc); |
| 54 | | static void ppc4xx_spu_timer_reset(powerpc_state *ppc); |
| 160 | /* flag lookup table for FCMP */ |
| 161 | static const UINT8 fcmp_cr_table_source[32] = |
| 162 | { |
| 163 | /* ..... */ 0x4, |
| 164 | /* ....C */ 0x8, |
| 165 | /* ...V. */ 0x4, |
| 166 | /* ...VC */ 0x8, |
| 167 | /* ..Z.. */ 0x2, |
| 168 | /* ..Z.C */ 0xa, |
| 169 | /* ..ZV. */ 0x2, |
| 170 | /* ..ZVC */ 0xa, |
| 171 | /* .S... */ 0x4, |
| 172 | /* .S..C */ 0x8, |
| 173 | /* .S.V. */ 0x4, |
| 174 | /* .S.VC */ 0x8, |
| 175 | /* .SZ.. */ 0x2, |
| 176 | /* .SZ.C */ 0xa, |
| 177 | /* .SZV. */ 0x2, |
| 178 | /* .SZVC */ 0xa, |
| 179 | /* U.... */ 0x5, |
| 180 | /* U...C */ 0x9, |
| 181 | /* U..V. */ 0x5, |
| 182 | /* U..VC */ 0x9, |
| 183 | /* U.Z.. */ 0x3, |
| 184 | /* U.Z.C */ 0xb, |
| 185 | /* U.ZV. */ 0x3, |
| 186 | /* U.ZVC */ 0xb, |
| 187 | /* US... */ 0x5, |
| 188 | /* US..C */ 0x9, |
| 189 | /* US.V. */ 0x5, |
| 190 | /* US.VC */ 0x9, |
| 191 | /* USZ.. */ 0x3, |
| 192 | /* USZ.C */ 0xb, |
| 193 | /* USZV. */ 0x3, |
| 194 | /* USZVC */ 0xb |
| 195 | }; |
| 55 | 196 | |
| 56 | 197 | |
| 198 | const device_type PPC601 = &device_creator<ppc601_device>; |
| 199 | const device_type PPC602 = &device_creator<ppc602_device>; |
| 200 | const device_type PPC603 = &device_creator<ppc603_device>; |
| 201 | const device_type PPC603E = &device_creator<ppc603e_device>; |
| 202 | const device_type PPC603R = &device_creator<ppc603r_device>; |
| 203 | const device_type PPC604 = &device_creator<ppc604_device>; |
| 204 | const device_type MPC8240 = &device_creator<mpc8240_device>; |
| 205 | const device_type PPC403GA = &device_creator<ppc403ga_device>; |
| 206 | const device_type PPC403GCX = &device_creator<ppc403gcx_device>; |
| 207 | const device_type PPC405GP = &device_creator<ppc405gp_device>; |
| 57 | 208 | |
| 209 | |
| 210 | ppc_device::ppc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int address_bits, int data_bits, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor, address_map_constructor internal_map) |
| 211 | : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) |
| 212 | , m_program_config("program", ENDIANNESS_BIG, data_bits, address_bits, 0, internal_map) |
| 213 | , c_bus_frequency(0) |
| 214 | , m_core(NULL) |
| 215 | , m_bus_freq_multiplier(1) |
| 216 | , m_vtlb(NULL) |
| 217 | , m_flavor(flavor) |
| 218 | , m_cap(cap) |
| 219 | , m_tb_divisor(tb_divisor) |
| 220 | , m_dcstore_handler(NULL) |
| 221 | , m_cache(CACHE_SIZE + sizeof(internal_ppc_state)) |
| 222 | , m_drcuml(NULL) |
| 223 | , m_drcfe(NULL) |
| 224 | , m_drcoptions(0) |
| 225 | { |
| 226 | m_program_config.m_logaddr_width = 32; |
| 227 | m_program_config.m_page_shift = POWERPC_MIN_PAGE_SHIFT; |
| 228 | memset(m_ext_dma_read_handler, 0, sizeof(m_ext_dma_read_handler)); |
| 229 | memset(m_ext_dma_write_handler, 0, sizeof(m_ext_dma_write_handler)); |
| 230 | } |
| 231 | |
| 232 | //ppc403_device::ppc403_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 233 | // : ppc_device(mconfig, PPC403, "PPC403", tag, owner, clock, "ppc403", 32?, 64?) |
| 234 | //{ |
| 235 | //} |
| 236 | // |
| 237 | //ppc405_device::ppc405_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 238 | // : ppc_device(mconfig, PPC405, "PPC405", tag, owner, clock, "ppc405", 32?, 64?) |
| 239 | //{ |
| 240 | //} |
| 241 | |
| 242 | ppc603_device::ppc603_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 243 | : ppc_device(mconfig, PPC603, "PowerPC 603", tag, owner, clock, "ppc603", 32, 64, PPC_MODEL_603, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) |
| 244 | { |
| 245 | } |
| 246 | |
| 247 | ppc603e_device::ppc603e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 248 | : ppc_device(mconfig, PPC603E, "PowerPC 603e", tag, owner, clock, "ppc603e", 32, 64, PPC_MODEL_603E, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) |
| 249 | { |
| 250 | } |
| 251 | |
| 252 | ppc603r_device::ppc603r_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 253 | : ppc_device(mconfig, PPC603R, "PowerPC 603R", tag, owner, clock, "ppc603r", 32, 64, PPC_MODEL_603R, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) |
| 254 | { |
| 255 | } |
| 256 | |
| 257 | ppc602_device::ppc602_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 258 | : ppc_device(mconfig, PPC602, "PowerPC 602", tag, owner, clock, "ppc602", 32, 64, PPC_MODEL_602, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) |
| 259 | { |
| 260 | } |
| 261 | |
| 262 | mpc8240_device::mpc8240_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 263 | : ppc_device(mconfig, MPC8240, "PowerPC MPC8240", tag, owner, clock, "mpc8240", 32, 64, PPC_MODEL_MPC8240, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4/* unknown */, NULL) |
| 264 | { |
| 265 | } |
| 266 | |
| 267 | ppc601_device::ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 268 | : ppc_device(mconfig, PPC601, "PowerPC 601", tag, owner, clock, "ppc601", 32, 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT, 0/* no TB */, NULL) |
| 269 | { |
| 270 | } |
| 271 | |
| 272 | ppc604_device::ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 273 | : ppc_device(mconfig, PPC604, "PowerPC 604", tag, owner, clock, "ppc604", 32, 64, PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU, 4, NULL) |
| 274 | { |
| 275 | } |
| 276 | |
| 277 | static ADDRESS_MAP_START( internal_ppc4xx, AS_PROGRAM, 32, ppc4xx_device ) |
| 278 | AM_RANGE(0x40000000, 0x4000000f) AM_READWRITE8(ppc4xx_spu_r, ppc4xx_spu_w, 0xffffffff) |
| 279 | ADDRESS_MAP_END |
| 280 | |
| 281 | ppc4xx_device::ppc4xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor) |
| 282 | : ppc_device(mconfig, type, name, tag, owner, clock, shortname, 31, 32, flavor, cap, tb_divisor, ADDRESS_MAP_NAME(internal_ppc4xx)) |
| 283 | { |
| 284 | } |
| 285 | |
| 286 | ppc403ga_device::ppc403ga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 287 | : ppc4xx_device(mconfig, PPC403GA, "PowerPC 403GA", tag, owner, clock, "ppc403ga", PPC_MODEL_403GA, PPCCAP_4XX, 1) |
| 288 | { |
| 289 | } |
| 290 | |
| 291 | ppc403gcx_device::ppc403gcx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 292 | : ppc4xx_device(mconfig, PPC403GCX, "PowerPC 403GCX", tag, owner, clock, "ppc403gcx", PPC_MODEL_403GCX, PPCCAP_4XX, 1) |
| 293 | { |
| 294 | } |
| 295 | |
| 296 | ppc405gp_device::ppc405gp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 297 | : ppc4xx_device(mconfig, PPC405GP, "PowerPC 405GP", tag, owner, clock, "ppc405gp", PPC_MODEL_405GP, PPCCAP_4XX | PPCCAP_VEA, 1) |
| 298 | { |
| 299 | } |
| 300 | |
| 301 | |
| 58 | 302 | /*************************************************************************** |
| 59 | 303 | INLINE FUNCTIONS |
| 60 | 304 | ***************************************************************************/ |
| r31142 | r31143 | |
| 78 | 322 | get_cr - return the current CR value |
| 79 | 323 | -------------------------------------------------*/ |
| 80 | 324 | |
| 81 | | INLINE UINT32 get_cr(powerpc_state *ppc) |
| 325 | inline UINT32 ppc_device::get_cr() |
| 82 | 326 | { |
| 83 | | return ((ppc->cr[0] & 0x0f) << 28) | |
| 84 | | ((ppc->cr[1] & 0x0f) << 24) | |
| 85 | | ((ppc->cr[2] & 0x0f) << 20) | |
| 86 | | ((ppc->cr[3] & 0x0f) << 16) | |
| 87 | | ((ppc->cr[4] & 0x0f) << 12) | |
| 88 | | ((ppc->cr[5] & 0x0f) << 8) | |
| 89 | | ((ppc->cr[6] & 0x0f) << 4) | |
| 90 | | ((ppc->cr[7] & 0x0f) << 0); |
| 327 | return ((m_core->cr[0] & 0x0f) << 28) | |
| 328 | ((m_core->cr[1] & 0x0f) << 24) | |
| 329 | ((m_core->cr[2] & 0x0f) << 20) | |
| 330 | ((m_core->cr[3] & 0x0f) << 16) | |
| 331 | ((m_core->cr[4] & 0x0f) << 12) | |
| 332 | ((m_core->cr[5] & 0x0f) << 8) | |
| 333 | ((m_core->cr[6] & 0x0f) << 4) | |
| 334 | ((m_core->cr[7] & 0x0f) << 0); |
| 91 | 335 | } |
| 92 | 336 | |
| 93 | 337 | |
| r31142 | r31143 | |
| 95 | 339 | set_cr - set the current CR value |
| 96 | 340 | -------------------------------------------------*/ |
| 97 | 341 | |
| 98 | | INLINE void set_cr(powerpc_state *ppc, UINT32 value) |
| 342 | inline void ppc_device::set_cr(UINT32 value) |
| 99 | 343 | { |
| 100 | | ppc->cr[0] = value >> 28; |
| 101 | | ppc->cr[1] = value >> 24; |
| 102 | | ppc->cr[2] = value >> 20; |
| 103 | | ppc->cr[3] = value >> 16; |
| 104 | | ppc->cr[4] = value >> 12; |
| 105 | | ppc->cr[5] = value >> 8; |
| 106 | | ppc->cr[6] = value >> 4; |
| 107 | | ppc->cr[7] = value >> 0; |
| 344 | m_core->cr[0] = value >> 28; |
| 345 | m_core->cr[1] = value >> 24; |
| 346 | m_core->cr[2] = value >> 20; |
| 347 | m_core->cr[3] = value >> 16; |
| 348 | m_core->cr[4] = value >> 12; |
| 349 | m_core->cr[5] = value >> 8; |
| 350 | m_core->cr[6] = value >> 4; |
| 351 | m_core->cr[7] = value >> 0; |
| 108 | 352 | } |
| 109 | 353 | |
| 110 | 354 | |
| r31142 | r31143 | |
| 112 | 356 | get_xer - return the current XER value |
| 113 | 357 | -------------------------------------------------*/ |
| 114 | 358 | |
| 115 | | INLINE UINT32 get_xer(powerpc_state *ppc) |
| 359 | inline UINT32 ppc_device::get_xer() |
| 116 | 360 | { |
| 117 | | return ppc->spr[SPR_XER] | (ppc->xerso << 31); |
| 361 | return m_core->spr[SPR_XER] | (m_core->xerso << 31); |
| 118 | 362 | } |
| 119 | 363 | |
| 120 | 364 | |
| r31142 | r31143 | |
| 122 | 366 | set_xer - set the current XER value |
| 123 | 367 | -------------------------------------------------*/ |
| 124 | 368 | |
| 125 | | INLINE void set_xer(powerpc_state *ppc, UINT32 value) |
| 369 | inline void ppc_device::set_xer(UINT32 value) |
| 126 | 370 | { |
| 127 | | ppc->spr[SPR_XER] = value & ~XER_SO; |
| 128 | | ppc->xerso = value >> 31; |
| 371 | m_core->spr[SPR_XER] = value & ~XER_SO; |
| 372 | m_core->xerso = value >> 31; |
| 129 | 373 | } |
| 130 | 374 | |
| 131 | 375 | |
| r31142 | r31143 | |
| 134 | 378 | value |
| 135 | 379 | -------------------------------------------------*/ |
| 136 | 380 | |
| 137 | | INLINE UINT64 get_timebase(powerpc_state *ppc) |
| 381 | inline UINT64 ppc_device::get_timebase() |
| 138 | 382 | { |
| 139 | | if (!ppc->tb_divisor) |
| 383 | if (!m_tb_divisor) |
| 140 | 384 | { |
| 141 | | return (ppc->device->total_cycles() - ppc->tb_zero_cycles); |
| 385 | return (total_cycles() - m_tb_zero_cycles); |
| 142 | 386 | } |
| 143 | 387 | |
| 144 | | return (ppc->device->total_cycles() - ppc->tb_zero_cycles) / ppc->tb_divisor; |
| 388 | return (total_cycles() - m_tb_zero_cycles) / m_tb_divisor; |
| 145 | 389 | } |
| 146 | 390 | |
| 147 | 391 | |
| r31142 | r31143 | |
| 149 | 393 | set_timebase - set the timebase |
| 150 | 394 | -------------------------------------------------*/ |
| 151 | 395 | |
| 152 | | INLINE void set_timebase(powerpc_state *ppc, UINT64 newtb) |
| 396 | inline void ppc_device::set_timebase(UINT64 newtb) |
| 153 | 397 | { |
| 154 | | ppc->tb_zero_cycles = ppc->device->total_cycles() - newtb * ppc->tb_divisor; |
| 398 | m_tb_zero_cycles = total_cycles() - newtb * m_tb_divisor; |
| 155 | 399 | } |
| 156 | 400 | |
| 157 | 401 | |
| r31142 | r31143 | |
| 160 | 404 | decrementer value |
| 161 | 405 | -------------------------------------------------*/ |
| 162 | 406 | |
| 163 | | INLINE UINT32 get_decrementer(powerpc_state *ppc) |
| 407 | inline UINT32 ppc_device::get_decrementer() |
| 164 | 408 | { |
| 165 | | INT64 cycles_until_zero = ppc->dec_zero_cycles - ppc->device->total_cycles(); |
| 409 | INT64 cycles_until_zero = m_dec_zero_cycles - total_cycles(); |
| 166 | 410 | cycles_until_zero = MAX(cycles_until_zero, 0); |
| 167 | 411 | |
| 168 | | if (!ppc->tb_divisor) |
| 412 | if (!m_tb_divisor) |
| 169 | 413 | { |
| 170 | 414 | return 0; |
| 171 | 415 | } |
| 172 | 416 | |
| 173 | | return cycles_until_zero / ppc->tb_divisor; |
| 417 | return cycles_until_zero / m_tb_divisor; |
| 174 | 418 | } |
| 175 | 419 | |
| 176 | 420 | |
| r31142 | r31143 | |
| 178 | 422 | set_decrementer - set the decremeter |
| 179 | 423 | -------------------------------------------------*/ |
| 180 | 424 | |
| 181 | | INLINE void set_decrementer(powerpc_state *ppc, UINT32 newdec) |
| 425 | inline void ppc_device::set_decrementer(UINT32 newdec) |
| 182 | 426 | { |
| 183 | | UINT64 cycles_until_done = ((UINT64)newdec + 1) * ppc->tb_divisor; |
| 184 | | UINT32 curdec = get_decrementer(ppc); |
| 427 | UINT64 cycles_until_done = ((UINT64)newdec + 1) * m_tb_divisor; |
| 428 | UINT32 curdec = get_decrementer(); |
| 185 | 429 | |
| 186 | | if (!ppc->tb_divisor) |
| 430 | if (!m_tb_divisor) |
| 187 | 431 | { |
| 188 | 432 | return; |
| 189 | 433 | } |
| 190 | 434 | |
| 191 | 435 | if (PRINTF_DECREMENTER) |
| 192 | 436 | { |
| 193 | | UINT64 total = ppc->device->total_cycles(); |
| 437 | UINT64 total = total_cycles(); |
| 194 | 438 | osd_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%08X%08X timer=%08X%08X\n", |
| 195 | | curdec, newdec, ppc->tb_divisor, |
| 439 | curdec, newdec, m_tb_divisor, |
| 196 | 440 | (UINT32)(total >> 32), (UINT32)total, (UINT32)(cycles_until_done >> 32), (UINT32)cycles_until_done); |
| 197 | 441 | } |
| 198 | 442 | |
| 199 | | ppc->dec_zero_cycles = ppc->device->total_cycles() + cycles_until_done; |
| 200 | | ppc->decrementer_int_timer->adjust(ppc->device->cycles_to_attotime(cycles_until_done)); |
| 443 | m_dec_zero_cycles = total_cycles() + cycles_until_done; |
| 444 | m_decrementer_int_timer->adjust(cycles_to_attotime(cycles_until_done)); |
| 201 | 445 | |
| 202 | 446 | if ((INT32)curdec >= 0 && (INT32)newdec < 0) |
| 203 | | ppc->irq_pending |= 0x02; |
| 447 | m_core->irq_pending |= 0x02; |
| 204 | 448 | } |
| 205 | 449 | |
| 206 | 450 | |
| r31142 | r31143 | |
| 306 | 550 | ***************************************************************************/ |
| 307 | 551 | |
| 308 | 552 | /*------------------------------------------------- |
| 309 | | ppccom_init - initialize the powerpc_state |
| 553 | device_start - initialize the powerpc_state |
| 310 | 554 | structure based on the configured type |
| 311 | 555 | -------------------------------------------------*/ |
| 312 | 556 | |
| 313 | | void ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT32 cap, int tb_divisor, legacy_cpu_device *device, device_irq_acknowledge_delegate irqcallback) |
| 557 | void ppc_device::device_start() |
| 314 | 558 | { |
| 315 | | const powerpc_config *config = (const powerpc_config *)device->static_config(); |
| 559 | /* allocate the core from the near cache */ |
| 560 | m_core = (internal_ppc_state *)m_cache.alloc_near(sizeof(internal_ppc_state)); |
| 561 | memset(m_core, 0, sizeof(internal_ppc_state)); |
| 316 | 562 | |
| 563 | m_entry = NULL; |
| 564 | m_nocode = NULL; |
| 565 | m_out_of_cycles = NULL; |
| 566 | m_tlb_mismatch = NULL; |
| 567 | m_swap_tgpr = NULL; |
| 568 | memset(m_lsw, 0, sizeof(m_lsw)); |
| 569 | memset(m_stsw, 0, sizeof(m_stsw)); |
| 570 | memset(m_read8, 0, sizeof(m_read8)); |
| 571 | memset(m_write8, 0, sizeof(m_write8)); |
| 572 | memset(m_read16, 0, sizeof(m_read16)); |
| 573 | memset(m_read16mask, 0, sizeof(m_read16mask)); |
| 574 | memset(m_write16, 0, sizeof(m_write16)); |
| 575 | memset(m_write16mask, 0, sizeof(m_write16mask)); |
| 576 | memset(m_read32, 0, sizeof(m_read32)); |
| 577 | memset(m_read32align, 0, sizeof(m_read32align)); |
| 578 | memset(m_read32mask, 0, sizeof(m_read32mask)); |
| 579 | memset(m_write32, 0, sizeof(m_write32)); |
| 580 | memset(m_write32align, 0, sizeof(m_write32align)); |
| 581 | memset(m_write32mask, 0, sizeof(m_write32mask)); |
| 582 | memset(m_read64, 0, sizeof(m_read64)); |
| 583 | memset(m_read64mask, 0, sizeof(m_read64mask)); |
| 584 | memset(m_write64, 0, sizeof(m_write64)); |
| 585 | memset(m_write64mask, 0, sizeof(m_write64mask)); |
| 586 | memset(m_exception, 0, sizeof(m_exception)); |
| 587 | memset(m_exception_norecover, 0, sizeof(m_exception_norecover)); |
| 588 | |
| 589 | /* initialize the implementation state tables */ |
| 590 | memcpy(m_fpmode, fpmode_source, sizeof(fpmode_source)); |
| 591 | memcpy(m_sz_cr_table, sz_cr_table_source, sizeof(sz_cr_table_source)); |
| 592 | memcpy(m_cmp_cr_table, cmp_cr_table_source, sizeof(cmp_cr_table_source)); |
| 593 | memcpy(m_cmpl_cr_table, cmpl_cr_table_source, sizeof(cmpl_cr_table_source)); |
| 594 | memcpy(m_fcmp_cr_table, fcmp_cr_table_source, sizeof(fcmp_cr_table_source)); |
| 595 | |
| 317 | 596 | /* initialize based on the config */ |
| 318 | | memset(ppc, 0, sizeof(*ppc)); |
| 319 | | ppc->flavor = flavor; |
| 320 | | ppc->cap = cap; |
| 321 | | ppc->cache_line_size = 32; |
| 322 | | ppc->tb_divisor = tb_divisor; |
| 323 | | ppc->cpu_clock = device->clock(); |
| 324 | | ppc->irq_callback = irqcallback; |
| 325 | | ppc->device = device; |
| 326 | | ppc->program = &device->space(AS_PROGRAM); |
| 327 | | ppc->direct = &ppc->program->direct(); |
| 328 | | ppc->system_clock = (config != NULL) ? config->bus_frequency : device->clock(); |
| 329 | | ppc->dcr_read_func = read32_delegate(); |
| 330 | | ppc->dcr_write_func = write32_delegate(); |
| 597 | m_ppc_tb_base_icount = 0; |
| 598 | m_ppc_dec_base_icount = 0; |
| 599 | m_ppc_dec_trigger_cycle = 0; |
| 600 | m_bus_freq_multiplier = 0; |
| 331 | 601 | |
| 332 | | ppc->tb_divisor = (ppc->tb_divisor * device->clock() + ppc->system_clock / 2 - 1) / ppc->system_clock; |
| 333 | | ppc->codexor = 0; |
| 334 | | if (!(cap & PPCCAP_4XX) && device->space_config()->m_endianness != ENDIANNESS_NATIVE) |
| 335 | | ppc->codexor = 4; |
| 602 | m_npc = 0; |
| 603 | memset(m_dcr, 0, sizeof(m_dcr)); |
| 336 | 604 | |
| 605 | m_lr = 0; |
| 606 | m_ctr = 0; |
| 607 | m_xer = 0; |
| 608 | m_pvr = 0; |
| 609 | m_srr0 = 0; |
| 610 | m_srr1 = 0; |
| 611 | m_srr2 = 0; |
| 612 | m_srr3 = 0; |
| 613 | m_hid0 = 0; |
| 614 | m_hid1 = 0; |
| 615 | m_hid2 = 0; |
| 616 | m_sdr1 = 0; |
| 617 | memset(m_sprg, 0, sizeof(m_sprg)); |
| 618 | |
| 619 | m_dsisr = 0; |
| 620 | m_dar = 0; |
| 621 | m_ear = 0; |
| 622 | m_dmiss = 0; |
| 623 | m_dcmp = 0; |
| 624 | m_hash1 = 0; |
| 625 | m_hash2 = 0; |
| 626 | m_imiss = 0; |
| 627 | m_icmp = 0; |
| 628 | m_rpa = 0; |
| 629 | |
| 630 | memset(m_ibat, 0, sizeof(m_ibat)); |
| 631 | memset(m_dbat, 0, sizeof(m_dbat)); |
| 632 | |
| 633 | m_evpr = 0; |
| 634 | m_exier = 0; |
| 635 | m_exisr = 0; |
| 636 | m_bear = 0; |
| 637 | m_besr = 0; |
| 638 | m_iocr = 0; |
| 639 | memset(m_br, 0, sizeof(m_br)); |
| 640 | m_iabr = 0; |
| 641 | m_esr = 0; |
| 642 | m_iccr = 0; |
| 643 | m_dccr = 0; |
| 644 | m_pit = 0; |
| 645 | m_pit_counter = 0; |
| 646 | m_pit_int_enable = 0; |
| 647 | m_tsr = 0; |
| 648 | m_dbsr = 0; |
| 649 | m_sgr = 0; |
| 650 | m_pid = 0; |
| 651 | m_pbl1 = 0; |
| 652 | m_pbl2 = 0; |
| 653 | m_pbu1 = 0; |
| 654 | m_pbu2 = 0; |
| 655 | m_fit_bit = 0; |
| 656 | m_fit_int_enable = 0; |
| 657 | m_wdt_bit = 0; |
| 658 | m_wdt_int_enable = 0; |
| 659 | m_dac1 = 0; |
| 660 | m_dac2 = 0; |
| 661 | m_iac1 = 0; |
| 662 | m_iac2 = 0; |
| 663 | |
| 664 | memset(&m_spu_old, 0, sizeof(m_spu_old)); |
| 665 | memset(m_dma, 0, sizeof(m_dma)); |
| 666 | m_dmasr = 0; |
| 667 | |
| 668 | m_reserved = 0; |
| 669 | m_reserved_address = 0; |
| 670 | m_interrupt_pending = 0; |
| 671 | m_tb = 0; |
| 672 | m_dec = 0; |
| 673 | m_dec_frac = 0; |
| 674 | memset(m_fpr, 0, sizeof(m_fpr)); |
| 675 | m_lt = 0; |
| 676 | m_sp = 0; |
| 677 | m_tcr = 0; |
| 678 | m_ibr = 0; |
| 679 | m_esasrr = 0; |
| 680 | m_sebr = 0; |
| 681 | m_ser = 0; |
| 682 | |
| 683 | memset(&m_spu, 0, sizeof(m_spu)); |
| 684 | m_pit_reload = 0; |
| 685 | m_irqstate = 0; |
| 686 | memset(m_buffered_dma_rate, 0, sizeof(m_buffered_dma_rate)); |
| 687 | m_codexor = 0; |
| 688 | m_system_clock = 0; |
| 689 | m_cpu_clock = 0; |
| 690 | m_tb_zero_cycles = 0; |
| 691 | m_dec_zero_cycles = 0; |
| 692 | |
| 693 | m_arg1 = 0; |
| 694 | m_fastram_select = 0; |
| 695 | memset(m_fastram, 0, sizeof(m_fastram)); |
| 696 | m_hotspot_select = 0; |
| 697 | memset(m_hotspot, 0, sizeof(m_hotspot)); |
| 698 | |
| 699 | m_cache_line_size = 32; |
| 700 | m_cpu_clock = clock(); |
| 701 | m_program = &space(AS_PROGRAM); |
| 702 | m_direct = &m_program->direct(); |
| 703 | m_system_clock = c_bus_frequency != 0 ? c_bus_frequency : clock(); |
| 704 | m_dcr_read_func = read32_delegate(); |
| 705 | m_dcr_write_func = write32_delegate(); |
| 706 | |
| 707 | m_tb_divisor = (m_tb_divisor * clock() + m_system_clock / 2 - 1) / m_system_clock; |
| 708 | m_codexor = 0; |
| 709 | if (!(m_cap & PPCCAP_4XX) && space_config()->m_endianness != ENDIANNESS_NATIVE) |
| 710 | m_codexor = 4; |
| 711 | |
| 337 | 712 | /* allocate the virtual TLB */ |
| 338 | | ppc->vtlb = vtlb_alloc(device, AS_PROGRAM, (cap & PPCCAP_603_MMU) ? PPC603_FIXED_TLB_ENTRIES : 0, POWERPC_TLB_ENTRIES); |
| 713 | m_vtlb = vtlb_alloc(this, AS_PROGRAM, (m_cap & PPCCAP_603_MMU) ? PPC603_FIXED_TLB_ENTRIES : 0, POWERPC_TLB_ENTRIES); |
| 339 | 714 | |
| 340 | 715 | /* allocate a timer for the compare interrupt */ |
| 341 | | if ((cap & PPCCAP_OEA) && (ppc->tb_divisor)) |
| 342 | | ppc->decrementer_int_timer = device->machine().scheduler().timer_alloc(FUNC(decrementer_int_callback), ppc); |
| 716 | if ((m_cap & PPCCAP_OEA) && (m_tb_divisor)) |
| 717 | m_decrementer_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::decrementer_int_callback), this)); |
| 343 | 718 | |
| 344 | 719 | /* and for the 4XX interrupts if needed */ |
| 345 | | if (cap & PPCCAP_4XX) |
| 720 | if (m_cap & PPCCAP_4XX) |
| 346 | 721 | { |
| 347 | | ppc->fit_timer = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_fit_callback), ppc); |
| 348 | | ppc->pit_timer = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_pit_callback), ppc); |
| 349 | | ppc->spu.timer = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_spu_callback), ppc); |
| 722 | m_fit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_fit_callback), this)); |
| 723 | m_pit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_pit_callback), this)); |
| 724 | m_spu.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_spu_callback), this)); |
| 350 | 725 | } |
| 351 | 726 | |
| 352 | | if (cap & PPCCAP_4XX) |
| 727 | if (m_cap & PPCCAP_4XX) |
| 353 | 728 | { |
| 354 | | ppc->buffered_dma_timer[0] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 355 | | ppc->buffered_dma_timer[1] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 356 | | ppc->buffered_dma_timer[2] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 357 | | ppc->buffered_dma_timer[3] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 729 | m_buffered_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); |
| 730 | m_buffered_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); |
| 731 | m_buffered_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); |
| 732 | m_buffered_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); |
| 358 | 733 | |
| 359 | | ppc->buffered_dma_rate[0] = 10000; |
| 360 | | ppc->buffered_dma_rate[1] = 10000; |
| 361 | | ppc->buffered_dma_rate[2] = 10000; |
| 362 | | ppc->buffered_dma_rate[3] = 10000; |
| 734 | m_buffered_dma_rate[0] = 10000; |
| 735 | m_buffered_dma_rate[1] = 10000; |
| 736 | m_buffered_dma_rate[2] = 10000; |
| 737 | m_buffered_dma_rate[3] = 10000; |
| 363 | 738 | } |
| 364 | 739 | |
| 365 | 740 | /* register for save states */ |
| 366 | | device->save_item(NAME(ppc->pc)); |
| 367 | | device->save_item(NAME(ppc->r)); |
| 368 | | device->save_item(NAME(ppc->f)); |
| 369 | | device->save_item(NAME(ppc->cr)); |
| 370 | | device->save_item(NAME(ppc->xerso)); |
| 371 | | device->save_item(NAME(ppc->fpscr)); |
| 372 | | device->save_item(NAME(ppc->msr)); |
| 373 | | device->save_item(NAME(ppc->sr)); |
| 374 | | device->save_item(NAME(ppc->spr)); |
| 375 | | device->save_item(NAME(ppc->dcr)); |
| 376 | | if (cap & PPCCAP_4XX) |
| 741 | save_item(NAME(m_core->pc)); |
| 742 | save_item(NAME(m_core->r)); |
| 743 | save_item(NAME(m_core->f)); |
| 744 | save_item(NAME(m_core->cr)); |
| 745 | save_item(NAME(m_core->xerso)); |
| 746 | save_item(NAME(m_core->fpscr)); |
| 747 | save_item(NAME(m_core->msr)); |
| 748 | save_item(NAME(m_core->sr)); |
| 749 | save_item(NAME(m_core->spr)); |
| 750 | save_item(NAME(m_dcr)); |
| 751 | if (m_cap & PPCCAP_4XX) |
| 377 | 752 | { |
| 378 | | device->save_item(NAME(ppc->spu.regs)); |
| 379 | | device->save_item(NAME(ppc->spu.txbuf)); |
| 380 | | device->save_item(NAME(ppc->spu.rxbuf)); |
| 381 | | device->save_item(NAME(ppc->spu.rxbuffer)); |
| 382 | | device->save_item(NAME(ppc->spu.rxin)); |
| 383 | | device->save_item(NAME(ppc->spu.rxout)); |
| 384 | | device->save_item(NAME(ppc->pit_reload)); |
| 385 | | device->save_item(NAME(ppc->irqstate)); |
| 753 | save_item(NAME(m_spu.regs)); |
| 754 | save_item(NAME(m_spu.txbuf)); |
| 755 | save_item(NAME(m_spu.rxbuf)); |
| 756 | save_item(NAME(m_spu.rxbuffer)); |
| 757 | save_item(NAME(m_spu.rxin)); |
| 758 | save_item(NAME(m_spu.rxout)); |
| 759 | save_item(NAME(m_pit_reload)); |
| 760 | save_item(NAME(m_irqstate)); |
| 386 | 761 | } |
| 387 | | if (cap & PPCCAP_603_MMU) |
| 762 | if (m_cap & PPCCAP_603_MMU) |
| 388 | 763 | { |
| 389 | | device->save_item(NAME(ppc->mmu603_cmp)); |
| 390 | | device->save_item(NAME(ppc->mmu603_hash)); |
| 391 | | device->save_item(NAME(ppc->mmu603_r)); |
| 764 | save_item(NAME(m_core->mmu603_cmp)); |
| 765 | save_item(NAME(m_core->mmu603_hash)); |
| 766 | save_item(NAME(m_core->mmu603_r)); |
| 392 | 767 | } |
| 393 | | device->save_item(NAME(ppc->irq_pending)); |
| 394 | | device->save_item(NAME(ppc->tb_zero_cycles)); |
| 395 | | device->save_item(NAME(ppc->dec_zero_cycles)); |
| 768 | save_item(NAME(m_core->irq_pending)); |
| 769 | save_item(NAME(m_tb_zero_cycles)); |
| 770 | save_item(NAME(m_dec_zero_cycles)); |
| 771 | |
| 772 | // Register debugger state |
| 773 | state_add(PPC_PC, "PC", m_core->pc).formatstr("%08X"); |
| 774 | state_add(PPC_MSR, "MSR", m_core->msr).formatstr("%08X"); |
| 775 | state_add(PPC_CR, "CR", m_debugger_temp).callimport().callexport().formatstr("%08X"); |
| 776 | state_add(PPC_LR, "LR", m_core->spr[SPR_LR]).formatstr("%08X"); |
| 777 | state_add(PPC_CTR, "CTR", m_core->spr[SPR_CTR]).formatstr("%08X"); |
| 778 | state_add(PPC_XER, "XER", m_debugger_temp).callimport().callexport().formatstr("%08X"); |
| 779 | state_add(PPC_SRR0, "SRR0", m_core->spr[SPROEA_SRR0]).formatstr("%08X"); |
| 780 | state_add(PPC_SRR1, "SRR1", m_core->spr[SPROEA_SRR1]).formatstr("%08X"); |
| 781 | state_add(PPC_SPRG0, "SPRG0", m_core->spr[SPROEA_SPRG0]).formatstr("%08X"); |
| 782 | state_add(PPC_SPRG1, "SPRG1", m_core->spr[SPROEA_SPRG1]).formatstr("%08X"); |
| 783 | state_add(PPC_SPRG2, "SPRG2", m_core->spr[SPROEA_SPRG2]).formatstr("%08X"); |
| 784 | state_add(PPC_SPRG3, "SPRG3", m_core->spr[SPROEA_SPRG3]).formatstr("%08X"); |
| 785 | state_add(PPC_SDR1, "SDR1", m_core->spr[SPROEA_SDR1]).formatstr("%08X"); |
| 786 | state_add(PPC_EXIER, "EXIER", m_dcr[DCR4XX_EXIER]).formatstr("%08X"); |
| 787 | state_add(PPC_EXISR, "EXISR", m_dcr[DCR4XX_EXISR]).formatstr("%08X"); |
| 788 | state_add(PPC_EVPR, "EVPR", m_core->spr[SPR4XX_EVPR]).formatstr("%08X"); |
| 789 | state_add(PPC_IOCR, "IOCR", m_dcr[DCR4XX_EXISR]).formatstr("%08X"); |
| 790 | state_add(PPC_TBH, "TBH", m_debugger_temp).callimport().callexport().formatstr("%08X"); |
| 791 | state_add(PPC_TBL, "TBL", m_debugger_temp).callimport().callexport().formatstr("%08X"); |
| 792 | state_add(PPC_DEC, "DEC", m_debugger_temp).callimport().callexport().formatstr("%08X"); |
| 793 | |
| 794 | state_add(PPC_SR0, "SR0", m_core->sr[0]).formatstr("%08X"); |
| 795 | state_add(PPC_SR1, "SR1", m_core->sr[1]).formatstr("%08X"); |
| 796 | state_add(PPC_SR2, "SR2", m_core->sr[2]).formatstr("%08X"); |
| 797 | state_add(PPC_SR3, "SR3", m_core->sr[3]).formatstr("%08X"); |
| 798 | state_add(PPC_SR4, "SR4", m_core->sr[4]).formatstr("%08X"); |
| 799 | state_add(PPC_SR5, "SR5", m_core->sr[5]).formatstr("%08X"); |
| 800 | state_add(PPC_SR6, "SR6", m_core->sr[6]).formatstr("%08X"); |
| 801 | state_add(PPC_SR7, "SR7", m_core->sr[7]).formatstr("%08X"); |
| 802 | state_add(PPC_SR8, "SR8", m_core->sr[8]).formatstr("%08X"); |
| 803 | state_add(PPC_SR9, "SR9", m_core->sr[9]).formatstr("%08X"); |
| 804 | state_add(PPC_SR10, "SR10", m_core->sr[10]).formatstr("%08X"); |
| 805 | state_add(PPC_SR11, "SR11", m_core->sr[11]).formatstr("%08X"); |
| 806 | state_add(PPC_SR12, "SR12", m_core->sr[12]).formatstr("%08X"); |
| 807 | state_add(PPC_SR13, "SR13", m_core->sr[13]).formatstr("%08X"); |
| 808 | state_add(PPC_SR14, "SR14", m_core->sr[14]).formatstr("%08X"); |
| 809 | state_add(PPC_SR15, "SR15", m_core->sr[15]).formatstr("%08X"); |
| 810 | |
| 811 | state_add(PPC_R0, "R0", m_core->r[0]).formatstr("%08X"); |
| 812 | state_add(PPC_R1, "R1", m_core->r[1]).formatstr("%08X"); |
| 813 | state_add(PPC_R2, "R2", m_core->r[2]).formatstr("%08X"); |
| 814 | state_add(PPC_R3, "R3", m_core->r[3]).formatstr("%08X"); |
| 815 | state_add(PPC_R4, "R4", m_core->r[4]).formatstr("%08X"); |
| 816 | state_add(PPC_R5, "R5", m_core->r[5]).formatstr("%08X"); |
| 817 | state_add(PPC_R6, "R6", m_core->r[6]).formatstr("%08X"); |
| 818 | state_add(PPC_R7, "R7", m_core->r[7]).formatstr("%08X"); |
| 819 | state_add(PPC_R8, "R8", m_core->r[8]).formatstr("%08X"); |
| 820 | state_add(PPC_R9, "R9", m_core->r[9]).formatstr("%08X"); |
| 821 | state_add(PPC_R10, "R10", m_core->r[10]).formatstr("%08X"); |
| 822 | state_add(PPC_R11, "R11", m_core->r[11]).formatstr("%08X"); |
| 823 | state_add(PPC_R12, "R12", m_core->r[12]).formatstr("%08X"); |
| 824 | state_add(PPC_R13, "R13", m_core->r[13]).formatstr("%08X"); |
| 825 | state_add(PPC_R14, "R14", m_core->r[14]).formatstr("%08X"); |
| 826 | state_add(PPC_R15, "R15", m_core->r[15]).formatstr("%08X"); |
| 827 | state_add(PPC_R16, "R16", m_core->r[16]).formatstr("%08X"); |
| 828 | state_add(PPC_R17, "R17", m_core->r[17]).formatstr("%08X"); |
| 829 | state_add(PPC_R18, "R18", m_core->r[18]).formatstr("%08X"); |
| 830 | state_add(PPC_R19, "R19", m_core->r[19]).formatstr("%08X"); |
| 831 | state_add(PPC_R20, "R20", m_core->r[20]).formatstr("%08X"); |
| 832 | state_add(PPC_R21, "R21", m_core->r[21]).formatstr("%08X"); |
| 833 | state_add(PPC_R22, "R22", m_core->r[22]).formatstr("%08X"); |
| 834 | state_add(PPC_R23, "R23", m_core->r[23]).formatstr("%08X"); |
| 835 | state_add(PPC_R24, "R24", m_core->r[24]).formatstr("%08X"); |
| 836 | state_add(PPC_R25, "R25", m_core->r[25]).formatstr("%08X"); |
| 837 | state_add(PPC_R26, "R26", m_core->r[26]).formatstr("%08X"); |
| 838 | state_add(PPC_R27, "R27", m_core->r[27]).formatstr("%08X"); |
| 839 | state_add(PPC_R28, "R28", m_core->r[28]).formatstr("%08X"); |
| 840 | state_add(PPC_R29, "R29", m_core->r[29]).formatstr("%08X"); |
| 841 | state_add(PPC_R30, "R30", m_core->r[30]).formatstr("%08X"); |
| 842 | state_add(PPC_R31, "R31", m_core->r[31]).formatstr("%08X"); |
| 843 | |
| 844 | state_add(PPC_F0, "F0", m_core->f[0]).formatstr("%12s"); |
| 845 | state_add(PPC_F1, "F1", m_core->f[1]).formatstr("%12s"); |
| 846 | state_add(PPC_F2, "F2", m_core->f[2]).formatstr("%12s"); |
| 847 | state_add(PPC_F3, "F3", m_core->f[3]).formatstr("%12s"); |
| 848 | state_add(PPC_F4, "F4", m_core->f[4]).formatstr("%12s"); |
| 849 | state_add(PPC_F5, "F5", m_core->f[5]).formatstr("%12s"); |
| 850 | state_add(PPC_F6, "F6", m_core->f[6]).formatstr("%12s"); |
| 851 | state_add(PPC_F7, "F7", m_core->f[7]).formatstr("%12s"); |
| 852 | state_add(PPC_F8, "F8", m_core->f[8]).formatstr("%12s"); |
| 853 | state_add(PPC_F9, "F9", m_core->f[9]).formatstr("%12s"); |
| 854 | state_add(PPC_F10, "F10", m_core->f[10]).formatstr("%12s"); |
| 855 | state_add(PPC_F11, "F11", m_core->f[11]).formatstr("%12s"); |
| 856 | state_add(PPC_F12, "F12", m_core->f[12]).formatstr("%12s"); |
| 857 | state_add(PPC_F13, "F13", m_core->f[13]).formatstr("%12s"); |
| 858 | state_add(PPC_F14, "F14", m_core->f[14]).formatstr("%12s"); |
| 859 | state_add(PPC_F15, "F15", m_core->f[15]).formatstr("%12s"); |
| 860 | state_add(PPC_F16, "F16", m_core->f[16]).formatstr("%12s"); |
| 861 | state_add(PPC_F17, "F17", m_core->f[17]).formatstr("%12s"); |
| 862 | state_add(PPC_F18, "F18", m_core->f[18]).formatstr("%12s"); |
| 863 | state_add(PPC_F19, "F19", m_core->f[19]).formatstr("%12s"); |
| 864 | state_add(PPC_F20, "F20", m_core->f[20]).formatstr("%12s"); |
| 865 | state_add(PPC_F21, "F21", m_core->f[21]).formatstr("%12s"); |
| 866 | state_add(PPC_F22, "F22", m_core->f[22]).formatstr("%12s"); |
| 867 | state_add(PPC_F23, "F23", m_core->f[23]).formatstr("%12s"); |
| 868 | state_add(PPC_F24, "F24", m_core->f[24]).formatstr("%12s"); |
| 869 | state_add(PPC_F25, "F25", m_core->f[25]).formatstr("%12s"); |
| 870 | state_add(PPC_F26, "F26", m_core->f[26]).formatstr("%12s"); |
| 871 | state_add(PPC_F27, "F27", m_core->f[27]).formatstr("%12s"); |
| 872 | state_add(PPC_F28, "F28", m_core->f[28]).formatstr("%12s"); |
| 873 | state_add(PPC_F29, "F29", m_core->f[29]).formatstr("%12s"); |
| 874 | state_add(PPC_F30, "F30", m_core->f[30]).formatstr("%12s"); |
| 875 | state_add(PPC_F31, "F31", m_core->f[31]).formatstr("%12s"); |
| 876 | state_add(PPC_FPSCR, "FPSCR", m_core->fpscr).formatstr("%08X"); |
| 877 | |
| 878 | state_add(STATE_GENPC, "GENPC", m_core->pc).noshow(); |
| 879 | state_add(STATE_GENSP, "GENSP", m_core->r[31]).noshow(); |
| 880 | state_add(STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).noshow().formatstr("%1s"); |
| 881 | |
| 882 | m_icountptr = &m_core->icount; |
| 883 | |
| 884 | UINT32 flags = 0; |
| 885 | /* initialize the UML generator */ |
| 886 | if (LOG_UML) |
| 887 | flags |= DRCUML_OPTION_LOG_UML; |
| 888 | if (LOG_NATIVE) |
| 889 | flags |= DRCUML_OPTION_LOG_NATIVE; |
| 890 | m_drcuml = auto_alloc(machine(), drcuml_state(*this, m_cache, flags, 8, 32, 2)); |
| 891 | |
| 892 | /* add symbols for our stuff */ |
| 893 | m_drcuml->symbol_add(&m_core->pc, sizeof(m_core->pc), "pc"); |
| 894 | m_drcuml->symbol_add(&m_core->icount, sizeof(m_core->icount), "icount"); |
| 895 | for (int regnum = 0; regnum < 32; regnum++) |
| 896 | { |
| 897 | char buf[10]; |
| 898 | sprintf(buf, "r%d", regnum); |
| 899 | m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf); |
| 900 | sprintf(buf, "fpr%d", regnum); |
| 901 | m_drcuml->symbol_add(&m_core->f[regnum], sizeof(m_core->f[regnum]), buf); |
| 902 | } |
| 903 | for (int regnum = 0; regnum < 8; regnum++) |
| 904 | { |
| 905 | char buf[10]; |
| 906 | sprintf(buf, "cr%d", regnum); |
| 907 | m_drcuml->symbol_add(&m_core->cr[regnum], sizeof(m_core->cr[regnum]), buf); |
| 908 | } |
| 909 | m_drcuml->symbol_add(&m_core->xerso, sizeof(m_core->xerso), "xerso"); |
| 910 | m_drcuml->symbol_add(&m_core->fpscr, sizeof(m_core->fpscr), "fpscr"); |
| 911 | m_drcuml->symbol_add(&m_core->msr, sizeof(m_core->msr), "msr"); |
| 912 | m_drcuml->symbol_add(&m_core->sr, sizeof(m_core->sr), "sr"); |
| 913 | m_drcuml->symbol_add(&m_core->spr[SPR_XER], sizeof(m_core->spr[SPR_XER]), "xer"); |
| 914 | m_drcuml->symbol_add(&m_core->spr[SPR_LR], sizeof(m_core->spr[SPR_LR]), "lr"); |
| 915 | m_drcuml->symbol_add(&m_core->spr[SPR_CTR], sizeof(m_core->spr[SPR_CTR]), "ctr"); |
| 916 | m_drcuml->symbol_add(&m_core->spr, sizeof(m_core->spr), "spr"); |
| 917 | m_drcuml->symbol_add(&m_dcr, sizeof(m_dcr), "dcr"); |
| 918 | m_drcuml->symbol_add(&m_core->param0, sizeof(m_core->param0), "param0"); |
| 919 | m_drcuml->symbol_add(&m_core->param1, sizeof(m_core->param1), "param1"); |
| 920 | m_drcuml->symbol_add(&m_core->irq_pending, sizeof(m_core->irq_pending), "irq_pending"); |
| 921 | m_drcuml->symbol_add(&m_core->mode, sizeof(m_core->mode), "mode"); |
| 922 | m_drcuml->symbol_add(&m_core->arg0, sizeof(m_core->arg0), "arg0"); |
| 923 | m_drcuml->symbol_add(&m_arg1, sizeof(m_arg1), "arg1"); |
| 924 | m_drcuml->symbol_add(&m_core->updateaddr, sizeof(m_core->updateaddr), "updateaddr"); |
| 925 | m_drcuml->symbol_add(&m_core->swcount, sizeof(m_core->swcount), "swcount"); |
| 926 | m_drcuml->symbol_add(&m_core->tempaddr, sizeof(m_core->tempaddr), "tempaddr"); |
| 927 | m_drcuml->symbol_add(&m_core->tempdata, sizeof(m_core->tempdata), "tempdata"); |
| 928 | m_drcuml->symbol_add(&m_core->fp0, sizeof(m_core->fp0), "fp0"); |
| 929 | m_drcuml->symbol_add(&m_fpmode, sizeof(m_fpmode), "fpmode"); |
| 930 | m_drcuml->symbol_add(&m_sz_cr_table, sizeof(m_sz_cr_table), "sz_cr_table"); |
| 931 | m_drcuml->symbol_add(&m_cmp_cr_table, sizeof(m_cmp_cr_table), "cmp_cr_table"); |
| 932 | m_drcuml->symbol_add(&m_cmpl_cr_table, sizeof(m_cmpl_cr_table), "cmpl_cr_table"); |
| 933 | m_drcuml->symbol_add(&m_fcmp_cr_table, sizeof(m_fcmp_cr_table), "fcmp_cr_table"); |
| 934 | |
| 935 | /* initialize the front-end helper */ |
| 936 | m_drcfe = auto_alloc(machine(), ppc_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); |
| 937 | |
| 938 | /* compute the register parameters */ |
| 939 | for (int regnum = 0; regnum < 32; regnum++) |
| 940 | { |
| 941 | m_regmap[regnum] = uml::mem(&m_core->r[regnum]); |
| 942 | m_fdregmap[regnum] = uml::mem(&m_core->f[regnum]); |
| 943 | } |
| 944 | |
| 945 | /* if we have registers to spare, assign r0, r1, r2 to leftovers */ |
| 946 | if (!DISABLE_FAST_REGISTERS) |
| 947 | { |
| 948 | drcbe_info beinfo; |
| 949 | m_drcuml->get_backend_info(beinfo); |
| 950 | if (beinfo.direct_iregs > 5) |
| 951 | m_regmap[0] = uml::I5; |
| 952 | if (beinfo.direct_iregs > 6) |
| 953 | m_regmap[1] = uml::I6; |
| 954 | if (beinfo.direct_iregs > 7) |
| 955 | m_regmap[2] = uml::I7; |
| 956 | } |
| 957 | |
| 958 | /* mark the cache dirty so it is updated on next execute */ |
| 959 | m_cache_dirty = TRUE; |
| 396 | 960 | } |
| 397 | 961 | |
| 962 | void ppc_device::state_export(const device_state_entry &entry) |
| 963 | { |
| 964 | switch (entry.index()) |
| 965 | { |
| 966 | case PPC_CR: |
| 967 | m_debugger_temp = get_cr(); |
| 968 | break; |
| 398 | 969 | |
| 970 | case PPC_XER: |
| 971 | m_debugger_temp = get_xer(); |
| 972 | break; |
| 973 | |
| 974 | case PPC_TBH: |
| 975 | m_debugger_temp = get_timebase() >> 32; |
| 976 | break; |
| 977 | |
| 978 | case PPC_TBL: |
| 979 | m_debugger_temp = (UINT32)get_timebase(); |
| 980 | break; |
| 981 | |
| 982 | case PPC_DEC: |
| 983 | m_debugger_temp = get_decrementer(); |
| 984 | break; |
| 985 | } |
| 986 | } |
| 987 | |
| 988 | void ppc_device::state_import(const device_state_entry &entry) |
| 989 | { |
| 990 | switch (entry.index()) |
| 991 | { |
| 992 | case PPC_CR: |
| 993 | set_cr(m_debugger_temp); |
| 994 | break; |
| 995 | |
| 996 | case PPC_XER: |
| 997 | set_xer(m_debugger_temp); |
| 998 | break; |
| 999 | |
| 1000 | case PPC_TBL: |
| 1001 | set_timebase((get_timebase() & ~U64(0x00ffffff00000000)) | m_debugger_temp); |
| 1002 | break; |
| 1003 | |
| 1004 | case PPC_TBH: |
| 1005 | set_timebase((get_timebase() & ~U64(0x00000000ffffffff)) | ((UINT64)(m_debugger_temp & 0x00ffffff) << 32)); |
| 1006 | break; |
| 1007 | |
| 1008 | case PPC_DEC: |
| 1009 | set_decrementer(m_debugger_temp); |
| 1010 | break; |
| 1011 | } |
| 1012 | } |
| 1013 | |
| 1014 | |
| 1015 | void ppc_device::state_string_export(const device_state_entry &entry, astring &string) |
| 1016 | { |
| 1017 | switch (entry.index()) |
| 1018 | { |
| 1019 | case PPC_F0: |
| 1020 | string.printf("%12f", m_core->f[0]); |
| 1021 | break; |
| 1022 | |
| 1023 | case PPC_F1: |
| 1024 | string.printf("%12f", m_core->f[1]); |
| 1025 | break; |
| 1026 | |
| 1027 | case PPC_F2: |
| 1028 | string.printf("%12f", m_core->f[2]); |
| 1029 | break; |
| 1030 | |
| 1031 | case PPC_F3: |
| 1032 | string.printf("%12f", m_core->f[3]); |
| 1033 | break; |
| 1034 | |
| 1035 | case PPC_F4: |
| 1036 | string.printf("%12f", m_core->f[4]); |
| 1037 | break; |
| 1038 | |
| 1039 | case PPC_F5: |
| 1040 | string.printf("%12f", m_core->f[5]); |
| 1041 | break; |
| 1042 | |
| 1043 | case PPC_F6: |
| 1044 | string.printf("%12f", m_core->f[6]); |
| 1045 | break; |
| 1046 | |
| 1047 | case PPC_F7: |
| 1048 | string.printf("%12f", m_core->f[7]); |
| 1049 | break; |
| 1050 | |
| 1051 | case PPC_F8: |
| 1052 | string.printf("%12f", m_core->f[8]); |
| 1053 | break; |
| 1054 | |
| 1055 | case PPC_F9: |
| 1056 | string.printf("%12f", m_core->f[9]); |
| 1057 | break; |
| 1058 | |
| 1059 | case PPC_F10: |
| 1060 | string.printf("%12f", m_core->f[10]); |
| 1061 | break; |
| 1062 | |
| 1063 | case PPC_F11: |
| 1064 | string.printf("%12f", m_core->f[11]); |
| 1065 | break; |
| 1066 | |
| 1067 | case PPC_F12: |
| 1068 | string.printf("%12f", m_core->f[12]); |
| 1069 | break; |
| 1070 | |
| 1071 | case PPC_F13: |
| 1072 | string.printf("%12f", m_core->f[13]); |
| 1073 | break; |
| 1074 | |
| 1075 | case PPC_F14: |
| 1076 | string.printf("%12f", m_core->f[14]); |
| 1077 | break; |
| 1078 | |
| 1079 | case PPC_F15: |
| 1080 | string.printf("%12f", m_core->f[15]); |
| 1081 | break; |
| 1082 | |
| 1083 | case PPC_F16: |
| 1084 | string.printf("%12f", m_core->f[16]); |
| 1085 | break; |
| 1086 | |
| 1087 | case PPC_F17: |
| 1088 | string.printf("%12f", m_core->f[17]); |
| 1089 | break; |
| 1090 | |
| 1091 | case PPC_F18: |
| 1092 | string.printf("%12f", m_core->f[18]); |
| 1093 | break; |
| 1094 | |
| 1095 | case PPC_F19: |
| 1096 | string.printf("%12f", m_core->f[19]); |
| 1097 | break; |
| 1098 | |
| 1099 | case PPC_F20: |
| 1100 | string.printf("%12f", m_core->f[20]); |
| 1101 | break; |
| 1102 | |
| 1103 | case PPC_F21: |
| 1104 | string.printf("%12f", m_core->f[21]); |
| 1105 | break; |
| 1106 | |
| 1107 | case PPC_F22: |
| 1108 | string.printf("%12f", m_core->f[22]); |
| 1109 | break; |
| 1110 | |
| 1111 | case PPC_F23: |
| 1112 | string.printf("%12f", m_core->f[23]); |
| 1113 | break; |
| 1114 | |
| 1115 | case PPC_F24: |
| 1116 | string.printf("%12f", m_core->f[24]); |
| 1117 | break; |
| 1118 | |
| 1119 | case PPC_F25: |
| 1120 | string.printf("%12f", m_core->f[25]); |
| 1121 | break; |
| 1122 | |
| 1123 | case PPC_F26: |
| 1124 | string.printf("%12f", m_core->f[26]); |
| 1125 | break; |
| 1126 | |
| 1127 | case PPC_F27: |
| 1128 | string.printf("%12f", m_core->f[27]); |
| 1129 | break; |
| 1130 | |
| 1131 | case PPC_F28: |
| 1132 | string.printf("%12f", m_core->f[28]); |
| 1133 | break; |
| 1134 | |
| 1135 | case PPC_F29: |
| 1136 | string.printf("%12f", m_core->f[29]); |
| 1137 | break; |
| 1138 | |
| 1139 | case PPC_F30: |
| 1140 | string.printf("%12f", m_core->f[30]); |
| 1141 | break; |
| 1142 | |
| 1143 | case PPC_F31: |
| 1144 | string.printf("%12f", m_core->f[31]); |
| 1145 | break; |
| 1146 | } |
| 1147 | } |
| 1148 | |
| 1149 | |
| 399 | 1150 | /*------------------------------------------------- |
| 400 | 1151 | ppccom_exit - common cleanup/exit |
| 401 | 1152 | -------------------------------------------------*/ |
| 402 | 1153 | |
| 403 | | void ppccom_exit(powerpc_state *ppc) |
| 1154 | void ppc_device::device_stop() |
| 404 | 1155 | { |
| 405 | | if (ppc->vtlb != NULL) |
| 406 | | vtlb_free(ppc->vtlb); |
| 1156 | if (m_vtlb != NULL) |
| 1157 | vtlb_free(m_vtlb); |
| 1158 | m_vtlb = NULL; |
| 1159 | |
| 1160 | /* clean up the DRC */ |
| 1161 | auto_free(machine(), m_drcfe); |
| 1162 | auto_free(machine(), m_drcuml); |
| 407 | 1163 | } |
| 408 | 1164 | |
| 409 | 1165 | |
| r31142 | r31143 | |
| 412 | 1168 | registers |
| 413 | 1169 | -------------------------------------------------*/ |
| 414 | 1170 | |
| 415 | | void ppccom_reset(powerpc_state *ppc) |
| 1171 | void ppc_device::device_reset() |
| 416 | 1172 | { |
| 417 | | int tlbindex; |
| 418 | | |
| 419 | 1173 | /* initialize the OEA state */ |
| 420 | | if (ppc->cap & PPCCAP_OEA) |
| 1174 | if (m_cap & PPCCAP_OEA) |
| 421 | 1175 | { |
| 422 | 1176 | /* PC to the reset vector; MSR has IP set to start */ |
| 423 | | ppc->pc = 0xfff00100; |
| 424 | | ppc->msr = MSROEA_IP; |
| 1177 | m_core->pc = 0xfff00100; |
| 1178 | m_core->msr = MSROEA_IP; |
| 425 | 1179 | |
| 426 | 1180 | /* reset the decrementer */ |
| 427 | | ppc->dec_zero_cycles = ppc->device->total_cycles(); |
| 428 | | if (ppc->tb_divisor) |
| 1181 | m_dec_zero_cycles = total_cycles(); |
| 1182 | if (m_tb_divisor) |
| 429 | 1183 | { |
| 430 | | decrementer_int_callback(ppc->device->machine(), ppc, 0); |
| 1184 | decrementer_int_callback(NULL, 0); |
| 431 | 1185 | } |
| 432 | 1186 | } |
| 433 | 1187 | |
| 434 | 1188 | /* initialize the 4XX state */ |
| 435 | | if (ppc->cap & PPCCAP_4XX) |
| 1189 | if (m_cap & PPCCAP_4XX) |
| 436 | 1190 | { |
| 437 | 1191 | /* PC to the last word; MSR to 0 */ |
| 438 | | ppc->pc = 0xfffffffc; |
| 439 | | ppc->msr = 0; |
| 1192 | m_core->pc = 0xfffffffc; |
| 1193 | m_core->msr = 0; |
| 440 | 1194 | |
| 441 | 1195 | /* reset the SPU status */ |
| 442 | | ppc->spr[SPR4XX_TCR] &= ~PPC4XX_TCR_WRC_MASK; |
| 443 | | ppc->spu.regs[SPU4XX_LINE_STATUS] = 0x06; |
| 1196 | m_core->spr[SPR4XX_TCR] &= ~PPC4XX_TCR_WRC_MASK; |
| 1197 | m_spu.regs[SPU4XX_LINE_STATUS] = 0x06; |
| 444 | 1198 | } |
| 445 | 1199 | |
| 446 | 1200 | /* initialize the 602 HID0 register */ |
| 447 | | if (ppc->flavor == PPC_MODEL_602) |
| 448 | | ppc->spr[SPR603_HID0] = 1; |
| 1201 | if (m_flavor == PPC_MODEL_602) |
| 1202 | m_core->spr[SPR603_HID0] = 1; |
| 449 | 1203 | |
| 450 | 1204 | /* time base starts here */ |
| 451 | | ppc->tb_zero_cycles = ppc->device->total_cycles(); |
| 1205 | m_tb_zero_cycles = total_cycles(); |
| 452 | 1206 | |
| 453 | 1207 | /* clear interrupts */ |
| 454 | | ppc->irq_pending = 0; |
| 1208 | m_core->irq_pending = 0; |
| 455 | 1209 | |
| 456 | 1210 | /* flush the TLB */ |
| 457 | | vtlb_flush_dynamic(ppc->vtlb); |
| 458 | | if (ppc->cap & PPCCAP_603_MMU) |
| 459 | | for (tlbindex = 0; tlbindex < PPC603_FIXED_TLB_ENTRIES; tlbindex++) |
| 460 | | vtlb_load(ppc->vtlb, tlbindex, 0, 0, 0); |
| 1211 | vtlb_flush_dynamic(m_vtlb); |
| 1212 | if (m_cap & PPCCAP_603_MMU) |
| 1213 | { |
| 1214 | for (int tlbindex = 0; tlbindex < PPC603_FIXED_TLB_ENTRIES; tlbindex++) |
| 1215 | { |
| 1216 | vtlb_load(m_vtlb, tlbindex, 0, 0, 0); |
| 1217 | } |
| 1218 | } |
| 1219 | |
| 1220 | /* Mark the cache dirty */ |
| 1221 | m_core->mode = 0; |
| 1222 | m_cache_dirty = TRUE; |
| 461 | 1223 | } |
| 462 | 1224 | |
| 463 | 1225 | |
| r31142 | r31143 | |
| 466 | 1228 | CPU |
| 467 | 1229 | -------------------------------------------------*/ |
| 468 | 1230 | |
| 469 | | offs_t ppccom_dasm(powerpc_state *ppc, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) |
| 1231 | offs_t ppc_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) |
| 470 | 1232 | { |
| 471 | 1233 | extern offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); |
| 472 | 1234 | UINT32 op = *(UINT32 *)oprom; |
| r31142 | r31143 | |
| 480 | 1242 | callback if installed |
| 481 | 1243 | -------------------------------------------------*/ |
| 482 | 1244 | |
| 483 | | void ppccom_dcstore_callback(powerpc_state *ppc) |
| 1245 | void ppc_device::ppccom_dcstore_callback() |
| 484 | 1246 | { |
| 485 | | if (ppc->dcstore_handler != NULL) |
| 1247 | if (m_dcstore_handler != NULL) |
| 486 | 1248 | { |
| 487 | | ppc->dcstore_handler(ppc->device, ppc->param0); |
| 1249 | m_dcstore_handler(this, m_core->param0); |
| 488 | 1250 | } |
| 489 | 1251 | } |
| 490 | 1252 | |
| r31142 | r31143 | |
| 500 | 1262 | filling |
| 501 | 1263 | -------------------------------------------------*/ |
| 502 | 1264 | |
| 503 | | static UINT32 ppccom_translate_address_internal(powerpc_state *ppc, int intention, offs_t *address) |
| 1265 | UINT32 ppc_device::ppccom_translate_address_internal(int intention, offs_t &address) |
| 504 | 1266 | { |
| 505 | 1267 | int transpriv = ((intention & TRANSLATE_USER_MASK) == 0); // 1 for supervisor, 0 for user |
| 506 | 1268 | int transtype = intention & TRANSLATE_TYPE_MASK; |
| r31142 | r31143 | |
| 509 | 1271 | UINT32 segreg; |
| 510 | 1272 | |
| 511 | 1273 | /* 4xx case: "TLB" really just caches writes and checks compare registers */ |
| 512 | | if (ppc->cap & PPCCAP_4XX) |
| 1274 | if (m_cap & PPCCAP_4XX) |
| 513 | 1275 | { |
| 514 | 1276 | /* we don't support the MMU of the 403GCX */ |
| 515 | | if (ppc->flavor == PPC_MODEL_403GCX && (ppc->msr & MSROEA_DR)) |
| 1277 | if (m_flavor == PPC_MODEL_403GCX && (m_core->msr & MSROEA_DR)) |
| 516 | 1278 | fatalerror("MMU enabled but not supported!\n"); |
| 517 | 1279 | |
| 518 | 1280 | /* only check if PE is enabled */ |
| 519 | | if (transtype == TRANSLATE_WRITE && (ppc->msr & MSR4XX_PE)) |
| 1281 | if (transtype == TRANSLATE_WRITE && (m_core->msr & MSR4XX_PE)) |
| 520 | 1282 | { |
| 521 | 1283 | /* are we within one of the protection ranges? */ |
| 522 | | int inrange1 = ((*address >> 12) >= (ppc->spr[SPR4XX_PBL1] >> 12) && (*address >> 12) < (ppc->spr[SPR4XX_PBU1] >> 12)); |
| 523 | | int inrange2 = ((*address >> 12) >= (ppc->spr[SPR4XX_PBL2] >> 12) && (*address >> 12) < (ppc->spr[SPR4XX_PBU2] >> 12)); |
| 1284 | int inrange1 = ((address >> 12) >= (m_core->spr[SPR4XX_PBL1] >> 12) && (address >> 12) < (m_core->spr[SPR4XX_PBU1] >> 12)); |
| 1285 | int inrange2 = ((address >> 12) >= (m_core->spr[SPR4XX_PBL2] >> 12) && (address >> 12) < (m_core->spr[SPR4XX_PBU2] >> 12)); |
| 524 | 1286 | |
| 525 | 1287 | /* if PX == 1, writes are only allowed OUTSIDE of the bounds */ |
| 526 | | if (((ppc->msr & MSR4XX_PX) && (inrange1 || inrange2)) || (!(ppc->msr & MSR4XX_PX) && (!inrange1 && !inrange2))) |
| 1288 | if (((m_core->msr & MSR4XX_PX) && (inrange1 || inrange2)) || (!(m_core->msr & MSR4XX_PX) && (!inrange1 && !inrange2))) |
| 527 | 1289 | return 0x002; |
| 528 | 1290 | } |
| 529 | | *address &= 0x7fffffff; |
| 1291 | address &= 0x7fffffff; |
| 530 | 1292 | return 0x001; |
| 531 | 1293 | } |
| 532 | 1294 | |
| 533 | 1295 | /* only applies if we support the OEA */ |
| 534 | | if (!(ppc->cap & PPCCAP_OEA)) |
| 1296 | if (!(m_cap & PPCCAP_OEA)) |
| 535 | 1297 | return 0x001; |
| 536 | 1298 | |
| 537 | 1299 | /* also no translation necessary if translation is disabled */ |
| 538 | | if ((transtype == TRANSLATE_FETCH && (ppc->msr & MSROEA_IR) == 0) || (transtype != TRANSLATE_FETCH && (ppc->msr & MSROEA_DR) == 0)) |
| 1300 | if ((transtype == TRANSLATE_FETCH && (m_core->msr & MSROEA_IR) == 0) || (transtype != TRANSLATE_FETCH && (m_core->msr & MSROEA_DR) == 0)) |
| 539 | 1301 | return 0x001; |
| 540 | 1302 | |
| 541 | 1303 | /* first scan the appropriate BAT */ |
| 542 | | if (ppc->cap & PPCCAP_601BAT) |
| 1304 | if (m_cap & PPCCAP_601BAT) |
| 543 | 1305 | { |
| 544 | 1306 | for (batnum = 0; batnum < 4; batnum++) |
| 545 | 1307 | { |
| 546 | | UINT32 upper = ppc->spr[SPROEA_IBAT0U + 2*batnum + 0]; |
| 547 | | UINT32 lower = ppc->spr[SPROEA_IBAT0U + 2*batnum + 1]; |
| 1308 | UINT32 upper = m_core->spr[SPROEA_IBAT0U + 2*batnum + 0]; |
| 1309 | UINT32 lower = m_core->spr[SPROEA_IBAT0U + 2*batnum + 1]; |
| 548 | 1310 | int privbit = ((intention & TRANSLATE_USER_MASK) == 0) ? 3 : 2; |
| 549 | 1311 | |
| 550 | 1312 | // printf("bat %d upper = %08x privbit %d\n", batnum, upper, privbit); |
| r31142 | r31143 | |
| 557 | 1319 | UINT32 key = (upper >> privbit) & 1; |
| 558 | 1320 | |
| 559 | 1321 | /* check for a hit against this bucket */ |
| 560 | | if ((*address & mask) == (upper & mask)) |
| 1322 | if ((address & mask) == (upper & mask)) |
| 561 | 1323 | { |
| 562 | 1324 | /* verify protection; if we fail, return false and indicate a protection violation */ |
| 563 | 1325 | if (!page_access_allowed(transtype, key, upper & 3)) |
| r31142 | r31143 | |
| 566 | 1328 | } |
| 567 | 1329 | |
| 568 | 1330 | /* otherwise we're good */ |
| 569 | | addrout = (lower & mask) | (*address & ~mask); |
| 570 | | *address = addrout; // top 9 bits from top 9 of PBN |
| 1331 | addrout = (lower & mask) | (address & ~mask); |
| 1332 | address = addrout; // top 9 bits from top 9 of PBN |
| 571 | 1333 | return 0x001; |
| 572 | 1334 | } |
| 573 | 1335 | } |
| r31142 | r31143 | |
| 579 | 1341 | |
| 580 | 1342 | for (batnum = 0; batnum < 4; batnum++) |
| 581 | 1343 | { |
| 582 | | UINT32 upper = ppc->spr[batbase + 2*batnum + 0]; |
| 1344 | UINT32 upper = m_core->spr[batbase + 2*batnum + 0]; |
| 583 | 1345 | |
| 584 | 1346 | /* check user/supervisor valid bit */ |
| 585 | 1347 | if ((upper >> transpriv) & 0x01) |
| r31142 | r31143 | |
| 587 | 1349 | UINT32 mask = (~upper << 15) & 0xfffe0000; |
| 588 | 1350 | |
| 589 | 1351 | /* check for a hit against this bucket */ |
| 590 | | if ((*address & mask) == (upper & mask)) |
| 1352 | if ((address & mask) == (upper & mask)) |
| 591 | 1353 | { |
| 592 | | UINT32 lower = ppc->spr[batbase + 2*batnum + 1]; |
| 1354 | UINT32 lower = m_core->spr[batbase + 2*batnum + 1]; |
| 593 | 1355 | |
| 594 | 1356 | /* verify protection; if we fail, return false and indicate a protection violation */ |
| 595 | 1357 | if (!page_access_allowed(transtype, 1, lower & 3)) |
| r31142 | r31143 | |
| 598 | 1360 | } |
| 599 | 1361 | |
| 600 | 1362 | /* otherwise we're good */ |
| 601 | | *address = (lower & mask) | (*address & ~mask); |
| 1363 | address = (lower & mask) | (address & ~mask); |
| 602 | 1364 | return 0x001; |
| 603 | 1365 | } |
| 604 | 1366 | } |
| r31142 | r31143 | |
| 606 | 1368 | } |
| 607 | 1369 | |
| 608 | 1370 | /* look up the segment register */ |
| 609 | | segreg = ppc->sr[*address >> 28]; |
| 1371 | segreg = m_core->sr[address >> 28]; |
| 610 | 1372 | if (transtype == TRANSLATE_FETCH && (segreg & 0x10000000)) |
| 611 | 1373 | return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); |
| 612 | 1374 | |
| 613 | 1375 | /* check for memory-forced I/O */ |
| 614 | | if (ppc->cap & PPCCAP_MFIOC) |
| 1376 | if (m_cap & PPCCAP_MFIOC) |
| 615 | 1377 | { |
| 616 | 1378 | if ((transtype != TRANSLATE_FETCH) && ((segreg & 0x87f00000) == 0x87f00000)) |
| 617 | 1379 | { |
| 618 | | *address = ((segreg & 0xf)<<28) | (*address & 0x0fffffff); |
| 1380 | address = ((segreg & 0xf)<<28) | (address & 0x0fffffff); |
| 619 | 1381 | return 1; |
| 620 | 1382 | } |
| 621 | 1383 | else if (segreg & 0x80000000) |
| r31142 | r31143 | |
| 625 | 1387 | } |
| 626 | 1388 | |
| 627 | 1389 | /* get hash table information from SD1 */ |
| 628 | | hashbase = ppc->spr[SPROEA_SDR1] & 0xffff0000; |
| 629 | | hashmask = ((ppc->spr[SPROEA_SDR1] & 0x1ff) << 16) | 0xffff; |
| 630 | | hash = (segreg & 0x7ffff) ^ ((*address >> 12) & 0xffff); |
| 1390 | hashbase = m_core->spr[SPROEA_SDR1] & 0xffff0000; |
| 1391 | hashmask = ((m_core->spr[SPROEA_SDR1] & 0x1ff) << 16) | 0xffff; |
| 1392 | hash = (segreg & 0x7ffff) ^ ((address >> 12) & 0xffff); |
| 631 | 1393 | |
| 632 | 1394 | /* if we're simulating the 603 MMU, fill in the data and stop here */ |
| 633 | | if (ppc->cap & PPCCAP_603_MMU) |
| 1395 | if (m_cap & PPCCAP_603_MMU) |
| 634 | 1396 | { |
| 635 | | UINT32 entry = vtlb_table(ppc->vtlb)[*address >> 12]; |
| 636 | | ppc->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((*address >> 22) & 0x3f); |
| 637 | | ppc->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask); |
| 638 | | ppc->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask); |
| 1397 | UINT32 entry = vtlb_table(m_vtlb)[address >> 12]; |
| 1398 | m_core->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((address >> 22) & 0x3f); |
| 1399 | m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask); |
| 1400 | m_core->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask); |
| 639 | 1401 | if ((entry & (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) == (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) |
| 640 | 1402 | { |
| 641 | | *address = (entry & 0xfffff000) | (*address & 0x00000fff); |
| 1403 | address = (entry & 0xfffff000) | (address & 0x00000fff); |
| 642 | 1404 | return 0x001; |
| 643 | 1405 | } |
| 644 | 1406 | return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); |
| r31142 | r31143 | |
| 648 | 1410 | for (hashnum = 0; hashnum < 2; hashnum++) |
| 649 | 1411 | { |
| 650 | 1412 | offs_t ptegaddr = hashbase | ((hash << 6) & hashmask); |
| 651 | | UINT32 *ptegptr = (UINT32 *)ppc->program->get_read_ptr(ptegaddr); |
| 1413 | UINT32 *ptegptr = (UINT32 *)m_program->get_read_ptr(ptegaddr); |
| 652 | 1414 | |
| 653 | 1415 | /* should only have valid memory here, but make sure */ |
| 654 | 1416 | if (ptegptr != NULL) |
| 655 | 1417 | { |
| 656 | | UINT32 targetupper = 0x80000000 | ((segreg & 0xffffff) << 7) | (hashnum << 6) | ((*address >> 22) & 0x3f); |
| 1418 | UINT32 targetupper = 0x80000000 | ((segreg & 0xffffff) << 7) | (hashnum << 6) | ((address >> 22) & 0x3f); |
| 657 | 1419 | int ptenum; |
| 658 | 1420 | |
| 659 | 1421 | /* scan PTEs */ |
| r31142 | r31143 | |
| 676 | 1438 | } |
| 677 | 1439 | |
| 678 | 1440 | /* otherwise we're good */ |
| 679 | | *address = (pteglower & 0xfffff000) | (*address & 0x00000fff); |
| 1441 | address = (pteglower & 0xfffff000) | (address & 0x00000fff); |
| 680 | 1442 | return (pteglower >> 7) & 1; |
| 681 | 1443 | } |
| 682 | 1444 | } |
| r31142 | r31143 | |
| 695 | 1457 | from logical to physical |
| 696 | 1458 | -------------------------------------------------*/ |
| 697 | 1459 | |
| 698 | | int ppccom_translate_address(powerpc_state *ppc, address_spacenum space, int intention, offs_t *address) |
| 1460 | bool ppc_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) |
| 699 | 1461 | { |
| 700 | 1462 | /* only applies to the program address space */ |
| 701 | | if (space != AS_PROGRAM) |
| 1463 | if (spacenum != AS_PROGRAM) |
| 702 | 1464 | return TRUE; |
| 703 | 1465 | |
| 704 | 1466 | /* translation is successful if the internal routine returns 0 or 1 */ |
| 705 | | return (ppccom_translate_address_internal(ppc, intention, address) <= 1); |
| 1467 | return (ppccom_translate_address_internal(intention, address) <= 1); |
| 706 | 1468 | } |
| 707 | 1469 | |
| 708 | 1470 | |
| r31142 | r31143 | |
| 710 | 1472 | ppccom_tlb_fill - handle a missing TLB entry |
| 711 | 1473 | -------------------------------------------------*/ |
| 712 | 1474 | |
| 713 | | void ppccom_tlb_fill(powerpc_state *ppc) |
| 1475 | void ppc_device::ppccom_tlb_fill() |
| 714 | 1476 | { |
| 715 | | vtlb_fill(ppc->vtlb, ppc->param0, ppc->param1); |
| 1477 | vtlb_fill(m_vtlb, m_core->param0, m_core->param1); |
| 716 | 1478 | } |
| 717 | 1479 | |
| 718 | 1480 | |
| r31142 | r31143 | |
| 721 | 1483 | including fixed entries |
| 722 | 1484 | -------------------------------------------------*/ |
| 723 | 1485 | |
| 724 | | void ppccom_tlb_flush(powerpc_state *ppc) |
| 1486 | void ppc_device::ppccom_tlb_flush() |
| 725 | 1487 | { |
| 726 | | vtlb_flush_dynamic(ppc->vtlb); |
| 1488 | vtlb_flush_dynamic(m_vtlb); |
| 727 | 1489 | } |
| 728 | 1490 | |
| 729 | 1491 | |
| r31142 | r31143 | |
| 737 | 1499 | instruction |
| 738 | 1500 | -------------------------------------------------*/ |
| 739 | 1501 | |
| 740 | | void ppccom_execute_tlbie(powerpc_state *ppc) |
| 1502 | void ppc_device::ppccom_execute_tlbie() |
| 741 | 1503 | { |
| 742 | | vtlb_flush_address(ppc->vtlb, ppc->param0); |
| 1504 | vtlb_flush_address(m_vtlb, m_core->param0); |
| 743 | 1505 | } |
| 744 | 1506 | |
| 745 | 1507 | |
| r31142 | r31143 | |
| 748 | 1510 | instruction |
| 749 | 1511 | -------------------------------------------------*/ |
| 750 | 1512 | |
| 751 | | void ppccom_execute_tlbia(powerpc_state *ppc) |
| 1513 | void ppc_device::ppccom_execute_tlbia() |
| 752 | 1514 | { |
| 753 | | vtlb_flush_dynamic(ppc->vtlb); |
| 1515 | vtlb_flush_dynamic(m_vtlb); |
| 754 | 1516 | } |
| 755 | 1517 | |
| 756 | 1518 | |
| r31142 | r31143 | |
| 759 | 1521 | instruction |
| 760 | 1522 | -------------------------------------------------*/ |
| 761 | 1523 | |
| 762 | | void ppccom_execute_tlbl(powerpc_state *ppc) |
| 1524 | void ppc_device::ppccom_execute_tlbl() |
| 763 | 1525 | { |
| 764 | | UINT32 address = ppc->param0; |
| 765 | | int isitlb = ppc->param1; |
| 1526 | UINT32 address = m_core->param0; |
| 1527 | int isitlb = m_core->param1; |
| 766 | 1528 | vtlb_entry flags = 0; |
| 767 | 1529 | int entrynum; |
| 768 | 1530 | |
| 769 | 1531 | /* determine entry number; we use rand() for associativity */ |
| 770 | | entrynum = ((address >> 12) & 0x1f) | (ppc->device->machine().rand() & 0x20) | (isitlb ? 0x40 : 0); |
| 1532 | entrynum = ((address >> 12) & 0x1f) | (machine().rand() & 0x20) | (isitlb ? 0x40 : 0); |
| 771 | 1533 | |
| 772 | 1534 | /* determine the flags */ |
| 773 | 1535 | flags = VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED; |
| 774 | | if (ppc->spr[SPR603_RPA] & 0x80) |
| 1536 | if (m_core->spr[SPR603_RPA] & 0x80) |
| 775 | 1537 | flags |= VTLB_WRITE_ALLOWED; |
| 776 | 1538 | if (isitlb) |
| 777 | 1539 | flags |= VTLB_FETCH_ALLOWED; |
| 778 | 1540 | |
| 779 | 1541 | /* load the entry */ |
| 780 | | vtlb_load(ppc->vtlb, entrynum, 1, address, (ppc->spr[SPR603_RPA] & 0xfffff000) | flags); |
| 1542 | vtlb_load(m_vtlb, entrynum, 1, address, (m_core->spr[SPR603_RPA] & 0xfffff000) | flags); |
| 781 | 1543 | } |
| 782 | 1544 | |
| 783 | 1545 | |
| r31142 | r31143 | |
| 786 | 1548 | instruction |
| 787 | 1549 | -------------------------------------------------*/ |
| 788 | 1550 | |
| 789 | | void ppccom_execute_mftb(powerpc_state *ppc) |
| 1551 | void ppc_device::ppccom_execute_mftb() |
| 790 | 1552 | { |
| 791 | | switch (ppc->param0) |
| 1553 | switch (m_core->param0) |
| 792 | 1554 | { |
| 793 | 1555 | /* user mode timebase read */ |
| 794 | 1556 | case SPRVEA_TBL_R: |
| 795 | | ppc->param1 = get_timebase(ppc); |
| 1557 | m_core->param1 = get_timebase(); |
| 796 | 1558 | break; |
| 797 | 1559 | case SPRVEA_TBU_R: |
| 798 | | ppc->param1 = get_timebase(ppc) >> 32; |
| 1560 | m_core->param1 = get_timebase() >> 32; |
| 799 | 1561 | break; |
| 800 | 1562 | } |
| 801 | 1563 | } |
| r31142 | r31143 | |
| 806 | 1568 | instruction |
| 807 | 1569 | -------------------------------------------------*/ |
| 808 | 1570 | |
| 809 | | void ppccom_execute_mfspr(powerpc_state *ppc) |
| 1571 | void ppc_device::ppccom_execute_mfspr() |
| 810 | 1572 | { |
| 811 | 1573 | /* handle OEA SPRs */ |
| 812 | | if (ppc->cap & PPCCAP_OEA) |
| 1574 | if (m_cap & PPCCAP_OEA) |
| 813 | 1575 | { |
| 814 | | switch (ppc->param0) |
| 1576 | switch (m_core->param0) |
| 815 | 1577 | { |
| 816 | 1578 | /* read-through no-ops */ |
| 817 | 1579 | case SPROEA_DSISR: |
| r31142 | r31143 | |
| 837 | 1599 | case SPROEA_DBAT3L: |
| 838 | 1600 | case SPROEA_DBAT3U: |
| 839 | 1601 | case SPROEA_DABR: |
| 840 | | ppc->param1 = ppc->spr[ppc->param0]; |
| 1602 | m_core->param1 = m_core->spr[m_core->param0]; |
| 841 | 1603 | return; |
| 842 | 1604 | |
| 843 | 1605 | /* decrementer */ |
| 844 | 1606 | case SPROEA_DEC: |
| 845 | | ppc->param1 = get_decrementer(ppc); |
| 1607 | m_core->param1 = get_decrementer(); |
| 846 | 1608 | return; |
| 847 | 1609 | } |
| 848 | 1610 | } |
| 849 | 1611 | |
| 850 | 1612 | /* handle 603 SPRs */ |
| 851 | | if (ppc->cap & PPCCAP_603_MMU) |
| 1613 | if (m_cap & PPCCAP_603_MMU) |
| 852 | 1614 | { |
| 853 | | switch (ppc->param0) |
| 1615 | switch (m_core->param0) |
| 854 | 1616 | { |
| 855 | 1617 | /* read-through no-ops */ |
| 856 | 1618 | case SPR603_DMISS: |
| r31142 | r31143 | |
| 864 | 1626 | case SPR603_HID1: |
| 865 | 1627 | case SPR603_IABR: |
| 866 | 1628 | case SPR603_HID2: |
| 867 | | ppc->param1 = ppc->spr[ppc->param0]; |
| 1629 | m_core->param1 = m_core->spr[m_core->param0]; |
| 868 | 1630 | return; |
| 869 | 1631 | |
| 870 | 1632 | /* timebase */ |
| 871 | 1633 | case SPR603_TBL_R: |
| 872 | | ppc->param1 = get_timebase(ppc); |
| 1634 | m_core->param1 = get_timebase(); |
| 873 | 1635 | return; |
| 874 | 1636 | case SPR603_TBU_R: |
| 875 | | ppc->param1 = (get_timebase(ppc) >> 32) & 0xffffff; |
| 1637 | m_core->param1 = (get_timebase() >> 32) & 0xffffff; |
| 876 | 1638 | return; |
| 877 | 1639 | } |
| 878 | 1640 | } |
| 879 | 1641 | |
| 880 | 1642 | /* handle 4XX SPRs */ |
| 881 | | if (ppc->cap & PPCCAP_4XX) |
| 1643 | if (m_cap & PPCCAP_4XX) |
| 882 | 1644 | { |
| 883 | | switch (ppc->param0) |
| 1645 | switch (m_core->param0) |
| 884 | 1646 | { |
| 885 | 1647 | /* read-through no-ops */ |
| 886 | 1648 | case SPR4XX_EVPR: |
| r31142 | r31143 | |
| 901 | 1663 | case SPR4XX_PBU1: |
| 902 | 1664 | case SPR4XX_PBL2: |
| 903 | 1665 | case SPR4XX_PBU2: |
| 904 | | ppc->param1 = ppc->spr[ppc->param0]; |
| 1666 | m_core->param1 = m_core->spr[m_core->param0]; |
| 905 | 1667 | return; |
| 906 | 1668 | |
| 907 | 1669 | /* timebase */ |
| 908 | 1670 | case SPR4XX_TBLO: |
| 909 | 1671 | case SPR4XX_TBLU: |
| 910 | | ppc->param1 = get_timebase(ppc); |
| 1672 | m_core->param1 = get_timebase(); |
| 911 | 1673 | return; |
| 912 | 1674 | case SPR4XX_TBHI: |
| 913 | 1675 | case SPR4XX_TBHU: |
| 914 | | ppc->param1 = (get_timebase(ppc) >> 32) & 0xffffff; |
| 1676 | m_core->param1 = (get_timebase() >> 32) & 0xffffff; |
| 915 | 1677 | return; |
| 916 | 1678 | } |
| 917 | 1679 | } |
| 918 | 1680 | |
| 919 | 1681 | /* default handling */ |
| 920 | | osd_printf_debug("SPR %03X read\n", ppc->param0); |
| 921 | | ppc->param1 = ppc->spr[ppc->param0]; |
| 1682 | osd_printf_debug("SPR %03X read\n", m_core->param0); |
| 1683 | m_core->param1 = m_core->spr[m_core->param0]; |
| 922 | 1684 | } |
| 923 | 1685 | |
| 924 | 1686 | |
| r31142 | r31143 | |
| 927 | 1689 | instruction |
| 928 | 1690 | -------------------------------------------------*/ |
| 929 | 1691 | |
| 930 | | void ppccom_execute_mtspr(powerpc_state *ppc) |
| 1692 | void ppc_device::ppccom_execute_mtspr() |
| 931 | 1693 | { |
| 932 | 1694 | /* handle OEA SPRs */ |
| 933 | | if (ppc->cap & PPCCAP_OEA) |
| 1695 | if (m_cap & PPCCAP_OEA) |
| 934 | 1696 | { |
| 935 | | switch (ppc->param0) |
| 1697 | switch (m_core->param0) |
| 936 | 1698 | { |
| 937 | 1699 | /* write-through no-ops */ |
| 938 | 1700 | case SPROEA_DSISR: |
| r31142 | r31143 | |
| 941 | 1703 | case SPROEA_SRR1: |
| 942 | 1704 | case SPROEA_EAR: |
| 943 | 1705 | case SPROEA_DABR: |
| 944 | | ppc->spr[ppc->param0] = ppc->param1; |
| 1706 | m_core->spr[m_core->param0] = m_core->param1; |
| 945 | 1707 | return; |
| 946 | 1708 | |
| 947 | 1709 | /* registers that affect the memory map */ |
| r31142 | r31143 | |
| 962 | 1724 | case SPROEA_DBAT2U: |
| 963 | 1725 | case SPROEA_DBAT3L: |
| 964 | 1726 | case SPROEA_DBAT3U: |
| 965 | | ppc->spr[ppc->param0] = ppc->param1; |
| 966 | | ppccom_tlb_flush(ppc); |
| 1727 | m_core->spr[m_core->param0] = m_core->param1; |
| 1728 | ppccom_tlb_flush(); |
| 967 | 1729 | return; |
| 968 | 1730 | |
| 969 | 1731 | /* decrementer */ |
| 970 | 1732 | case SPROEA_DEC: |
| 971 | | set_decrementer(ppc, ppc->param1); |
| 1733 | set_decrementer(m_core->param1); |
| 972 | 1734 | return; |
| 973 | 1735 | } |
| 974 | 1736 | } |
| 975 | 1737 | |
| 976 | 1738 | /* handle 603 SPRs */ |
| 977 | | if (ppc->cap & PPCCAP_603_MMU) |
| 1739 | if (m_cap & PPCCAP_603_MMU) |
| 978 | 1740 | { |
| 979 | | switch (ppc->param0) |
| 1741 | switch (m_core->param0) |
| 980 | 1742 | { |
| 981 | 1743 | /* read-only */ |
| 982 | 1744 | case SPR603_DMISS: |
| r31142 | r31143 | |
| 993 | 1755 | case SPR603_HID1: |
| 994 | 1756 | case SPR603_IABR: |
| 995 | 1757 | case SPR603_HID2: |
| 996 | | ppc->spr[ppc->param0] = ppc->param1; |
| 1758 | m_core->spr[m_core->param0] = m_core->param1; |
| 997 | 1759 | return; |
| 998 | 1760 | |
| 999 | 1761 | /* timebase */ |
| 1000 | 1762 | case SPR603_TBL_W: |
| 1001 | | set_timebase(ppc, (get_timebase(ppc) & ~U64(0xffffffff00000000)) | ppc->param1); |
| 1763 | set_timebase((get_timebase() & ~U64(0xffffffff00000000)) | m_core->param1); |
| 1002 | 1764 | return; |
| 1003 | 1765 | case SPR603_TBU_W: |
| 1004 | | set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00000000ffffffff)) | ((UINT64)ppc->param1 << 32)); |
| 1766 | set_timebase((get_timebase() & ~U64(0x00000000ffffffff)) | ((UINT64)m_core->param1 << 32)); |
| 1005 | 1767 | return; |
| 1006 | 1768 | } |
| 1007 | 1769 | } |
| 1008 | 1770 | |
| 1009 | 1771 | /* handle 4XX SPRs */ |
| 1010 | | if (ppc->cap & PPCCAP_4XX) |
| 1772 | if (m_cap & PPCCAP_4XX) |
| 1011 | 1773 | { |
| 1012 | | UINT32 oldval = ppc->spr[ppc->param0]; |
| 1013 | | switch (ppc->param0) |
| 1774 | UINT32 oldval = m_core->spr[m_core->param0]; |
| 1775 | switch (m_core->param0) |
| 1014 | 1776 | { |
| 1015 | 1777 | /* write-through no-ops */ |
| 1016 | 1778 | case SPR4XX_EVPR: |
| r31142 | r31143 | |
| 1021 | 1783 | case SPR4XX_SRR1: |
| 1022 | 1784 | case SPR4XX_SRR2: |
| 1023 | 1785 | case SPR4XX_SRR3: |
| 1024 | | ppc->spr[ppc->param0] = ppc->param1; |
| 1786 | m_core->spr[m_core->param0] = m_core->param1; |
| 1025 | 1787 | return; |
| 1026 | 1788 | |
| 1027 | 1789 | /* registers that affect the memory map */ |
| r31142 | r31143 | |
| 1029 | 1791 | case SPR4XX_PBU1: |
| 1030 | 1792 | case SPR4XX_PBL2: |
| 1031 | 1793 | case SPR4XX_PBU2: |
| 1032 | | ppc->spr[ppc->param0] = ppc->param1; |
| 1033 | | ppccom_tlb_flush(ppc); |
| 1794 | m_core->spr[m_core->param0] = m_core->param1; |
| 1795 | ppccom_tlb_flush(); |
| 1034 | 1796 | return; |
| 1035 | 1797 | |
| 1036 | 1798 | /* timer control register */ |
| 1037 | 1799 | case SPR4XX_TCR: |
| 1038 | | ppc->spr[SPR4XX_TCR] = ppc->param1 | (oldval & PPC4XX_TCR_WRC_MASK); |
| 1039 | | if ((oldval ^ ppc->spr[SPR4XX_TCR]) & PPC4XX_TCR_FIE) |
| 1040 | | ppc4xx_fit_callback(ppc->device->machine(), ppc, FALSE); |
| 1041 | | if ((oldval ^ ppc->spr[SPR4XX_TCR]) & PPC4XX_TCR_PIE) |
| 1042 | | ppc4xx_pit_callback(ppc->device->machine(), ppc, FALSE); |
| 1800 | m_core->spr[SPR4XX_TCR] = m_core->param1 | (oldval & PPC4XX_TCR_WRC_MASK); |
| 1801 | if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_FIE) |
| 1802 | ppc4xx_fit_callback(NULL, FALSE); |
| 1803 | if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_PIE) |
| 1804 | ppc4xx_pit_callback(NULL, FALSE); |
| 1043 | 1805 | return; |
| 1044 | 1806 | |
| 1045 | 1807 | /* timer status register */ |
| 1046 | 1808 | case SPR4XX_TSR: |
| 1047 | | ppc->spr[SPR4XX_TSR] &= ~ppc->param1; |
| 1048 | | ppc4xx_set_irq_line(ppc, 0, 0); |
| 1809 | m_core->spr[SPR4XX_TSR] &= ~m_core->param1; |
| 1810 | ppc4xx_set_irq_line(0, 0); |
| 1049 | 1811 | return; |
| 1050 | 1812 | |
| 1051 | 1813 | /* PIT */ |
| 1052 | 1814 | case SPR4XX_PIT: |
| 1053 | | ppc->spr[SPR4XX_PIT] = ppc->param1; |
| 1054 | | ppc->pit_reload = ppc->param1; |
| 1055 | | ppc4xx_pit_callback(ppc->device->machine(), ppc, FALSE); |
| 1815 | m_core->spr[SPR4XX_PIT] = m_core->param1; |
| 1816 | m_pit_reload = m_core->param1; |
| 1817 | ppc4xx_pit_callback(NULL, FALSE); |
| 1056 | 1818 | return; |
| 1057 | 1819 | |
| 1058 | 1820 | /* timebase */ |
| 1059 | 1821 | case SPR4XX_TBLO: |
| 1060 | | set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00ffffff00000000)) | ppc->param1); |
| 1822 | set_timebase((get_timebase() & ~U64(0x00ffffff00000000)) | m_core->param1); |
| 1061 | 1823 | return; |
| 1062 | 1824 | case SPR4XX_TBHI: |
| 1063 | | set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00000000ffffffff)) | ((UINT64)(ppc->param1 & 0x00ffffff) << 32)); |
| 1825 | set_timebase((get_timebase() & ~U64(0x00000000ffffffff)) | ((UINT64)(m_core->param1 & 0x00ffffff) << 32)); |
| 1064 | 1826 | return; |
| 1065 | 1827 | } |
| 1066 | 1828 | } |
| 1067 | 1829 | |
| 1068 | 1830 | /* default handling */ |
| 1069 | | osd_printf_debug("SPR %03X write = %08X\n", ppc->param0, ppc->param1); |
| 1070 | | ppc->spr[ppc->param0] = ppc->param1; |
| 1831 | osd_printf_debug("SPR %03X write = %08X\n", m_core->param0, m_core->param1); |
| 1832 | m_core->spr[m_core->param0] = m_core->param1; |
| 1071 | 1833 | } |
| 1072 | 1834 | |
| 1073 | 1835 | |
| r31142 | r31143 | |
| 1076 | 1838 | instruction |
| 1077 | 1839 | -------------------------------------------------*/ |
| 1078 | 1840 | |
| 1079 | | void ppccom_execute_mfdcr(powerpc_state *ppc) |
| 1841 | void ppc_device::ppccom_execute_mfdcr() |
| 1080 | 1842 | { |
| 1081 | 1843 | /* handle various DCRs */ |
| 1082 | | switch (ppc->param0) |
| 1844 | switch (m_core->param0) |
| 1083 | 1845 | { |
| 1084 | 1846 | /* read-through no-ops */ |
| 1085 | 1847 | case DCR4XX_BR0: |
| r31142 | r31143 | |
| 1115 | 1877 | case DCR4XX_EXIER: |
| 1116 | 1878 | case DCR4XX_EXISR: |
| 1117 | 1879 | case DCR4XX_IOCR: |
| 1118 | | ppc->param1 = ppc->dcr[ppc->param0]; |
| 1880 | m_core->param1 = m_dcr[m_core->param0]; |
| 1119 | 1881 | return; |
| 1120 | 1882 | } |
| 1121 | 1883 | |
| 1122 | 1884 | /* default handling */ |
| 1123 | | if (ppc->dcr_read_func.isnull()) { |
| 1124 | | osd_printf_debug("DCR %03X read\n", ppc->param0); |
| 1125 | | if (ppc->param0 < ARRAY_LENGTH(ppc->dcr)) |
| 1126 | | ppc->param1 = ppc->dcr[ppc->param0]; |
| 1885 | if (m_dcr_read_func.isnull()) { |
| 1886 | osd_printf_debug("DCR %03X read\n", m_core->param0); |
| 1887 | if (m_core->param0 < ARRAY_LENGTH(m_dcr)) |
| 1888 | m_core->param1 = m_dcr[m_core->param0]; |
| 1127 | 1889 | else |
| 1128 | | ppc->param1 = 0; |
| 1890 | m_core->param1 = 0; |
| 1129 | 1891 | } else { |
| 1130 | | ppc->param1 = ppc->dcr_read_func(*ppc->program,ppc->param0,0xffffffff); |
| 1892 | m_core->param1 = m_dcr_read_func(*m_program,m_core->param0,0xffffffff); |
| 1131 | 1893 | } |
| 1132 | 1894 | } |
| 1133 | 1895 | |
| r31142 | r31143 | |
| 1137 | 1899 | instruction |
| 1138 | 1900 | -------------------------------------------------*/ |
| 1139 | 1901 | |
| 1140 | | void ppccom_execute_mtdcr(powerpc_state *ppc) |
| 1902 | void ppc_device::ppccom_execute_mtdcr() |
| 1141 | 1903 | { |
| 1142 | 1904 | UINT8 oldval; |
| 1143 | 1905 | |
| 1144 | 1906 | /* handle various DCRs */ |
| 1145 | | switch (ppc->param0) |
| 1907 | switch (m_core->param0) |
| 1146 | 1908 | { |
| 1147 | 1909 | /* write-through no-ops */ |
| 1148 | 1910 | case DCR4XX_BR0: |
| r31142 | r31143 | |
| 1170 | 1932 | case DCR4XX_DMADA3: |
| 1171 | 1933 | case DCR4XX_DMASA3: |
| 1172 | 1934 | case DCR4XX_DMACC3: |
| 1173 | | ppc->dcr[ppc->param0] = ppc->param1; |
| 1935 | m_dcr[m_core->param0] = m_core->param1; |
| 1174 | 1936 | return; |
| 1175 | 1937 | |
| 1176 | 1938 | /* DMA status */ |
| 1177 | 1939 | case DCR4XX_DMASR: |
| 1178 | | ppc->dcr[DCR4XX_DMASR] &= ~(ppc->param1 & 0xfff80070); |
| 1179 | | ppc4xx_dma_update_irq_states(ppc); |
| 1940 | m_dcr[DCR4XX_DMASR] &= ~(m_core->param1 & 0xfff80070); |
| 1941 | ppc4xx_dma_update_irq_states(); |
| 1180 | 1942 | return; |
| 1181 | 1943 | |
| 1182 | 1944 | /* interrupt enables */ |
| 1183 | 1945 | case DCR4XX_EXIER: |
| 1184 | | ppc->dcr[DCR4XX_EXIER] = ppc->param1; |
| 1185 | | ppc4xx_set_irq_line(ppc, 0, 0); |
| 1946 | m_dcr[DCR4XX_EXIER] = m_core->param1; |
| 1947 | ppc4xx_set_irq_line(0, 0); |
| 1186 | 1948 | return; |
| 1187 | 1949 | |
| 1188 | 1950 | /* interrupt clear */ |
| 1189 | 1951 | case DCR4XX_EXISR: |
| 1190 | | ppc->dcr[ppc->param0] &= ~ppc->param1; |
| 1191 | | ppc4xx_set_irq_line(ppc, 0, 0); |
| 1952 | m_dcr[m_core->param0] &= ~m_core->param1; |
| 1953 | ppc4xx_set_irq_line(0, 0); |
| 1192 | 1954 | return; |
| 1193 | 1955 | |
| 1194 | 1956 | /* DMA controls */ |
| r31142 | r31143 | |
| 1196 | 1958 | case DCR4XX_DMACR1: |
| 1197 | 1959 | case DCR4XX_DMACR2: |
| 1198 | 1960 | case DCR4XX_DMACR3: |
| 1199 | | ppc->dcr[ppc->param0] = ppc->param1; |
| 1200 | | if (ppc->param1 & PPC4XX_DMACR_CE) |
| 1201 | | ppc4xx_dma_exec(ppc, (ppc->param0 - DCR4XX_DMACR0) / 8); |
| 1202 | | ppc4xx_dma_update_irq_states(ppc); |
| 1961 | m_dcr[m_core->param0] = m_core->param1; |
| 1962 | if (m_core->param1 & PPC4XX_DMACR_CE) |
| 1963 | ppc4xx_dma_exec((m_core->param0 - DCR4XX_DMACR0) / 8); |
| 1964 | ppc4xx_dma_update_irq_states(); |
| 1203 | 1965 | return; |
| 1204 | 1966 | |
| 1205 | 1967 | /* I/O control */ |
| 1206 | 1968 | case DCR4XX_IOCR: |
| 1207 | | oldval = ppc->dcr[ppc->param0]; |
| 1208 | | ppc->dcr[ppc->param0] = ppc->param1; |
| 1209 | | if ((oldval ^ ppc->param1) & 0x02) |
| 1210 | | ppc4xx_spu_timer_reset(ppc); |
| 1969 | oldval = m_dcr[m_core->param0]; |
| 1970 | m_dcr[m_core->param0] = m_core->param1; |
| 1971 | if ((oldval ^ m_core->param1) & 0x02) |
| 1972 | ppc4xx_spu_timer_reset(); |
| 1211 | 1973 | return; |
| 1212 | 1974 | } |
| 1213 | 1975 | |
| 1214 | 1976 | /* default handling */ |
| 1215 | | if (ppc->dcr_write_func.isnull()) { |
| 1216 | | osd_printf_debug("DCR %03X write = %08X\n", ppc->param0, ppc->param1); |
| 1217 | | if (ppc->param0 < ARRAY_LENGTH(ppc->dcr)) |
| 1218 | | ppc->dcr[ppc->param0] = ppc->param1; |
| 1977 | if (m_dcr_write_func.isnull()) { |
| 1978 | osd_printf_debug("DCR %03X write = %08X\n", m_core->param0, m_core->param1); |
| 1979 | if (m_core->param0 < ARRAY_LENGTH(m_dcr)) |
| 1980 | m_dcr[m_core->param0] = m_core->param1; |
| 1219 | 1981 | } else { |
| 1220 | | ppc->dcr_write_func(*ppc->program,ppc->param0,ppc->param1,0xffffffff); |
| 1982 | m_dcr_write_func(*m_program,m_core->param0,m_core->param1,0xffffffff); |
| 1221 | 1983 | } |
| 1222 | 1984 | } |
| 1223 | 1985 | |
| r31142 | r31143 | |
| 1232 | 1994 | of the FPSCR register |
| 1233 | 1995 | -------------------------------------------------*/ |
| 1234 | 1996 | |
| 1235 | | void ppccom_update_fprf(powerpc_state *ppc) |
| 1997 | void ppc_device::ppccom_update_fprf() |
| 1236 | 1998 | { |
| 1237 | 1999 | UINT32 fprf; |
| 1238 | | double f = ppc->f[ppc->param0]; |
| 2000 | double f = m_core->f[m_core->param0]; |
| 1239 | 2001 | |
| 1240 | 2002 | if (is_qnan_double(f)) |
| 1241 | 2003 | { |
| r31142 | r31143 | |
| 1270 | 2032 | fprf = 0x02; |
| 1271 | 2033 | } |
| 1272 | 2034 | |
| 1273 | | ppc->fpscr &= ~0x0001f000; |
| 1274 | | ppc->fpscr |= fprf << 12; |
| 2035 | m_core->fpscr &= ~0x0001f000; |
| 2036 | m_core->fpscr |= fprf << 12; |
| 1275 | 2037 | } |
| 1276 | 2038 | |
| 1277 | 2039 | |
| 1278 | | |
| 1279 | 2040 | /*************************************************************************** |
| 1280 | | COMMON GET/SET INFO |
| 2041 | OEA HELPERS |
| 1281 | 2042 | ***************************************************************************/ |
| 1282 | 2043 | |
| 1283 | 2044 | /*------------------------------------------------- |
| 1284 | | ppccom_set_info - set information about |
| 1285 | | a PowerPC CPU |
| 2045 | decrementer_int_callback - callback that fires |
| 2046 | whenever a decrementer interrupt is generated |
| 1286 | 2047 | -------------------------------------------------*/ |
| 1287 | 2048 | |
| 1288 | | void ppccom_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) |
| 2049 | TIMER_CALLBACK_MEMBER( ppc_device::decrementer_int_callback ) |
| 1289 | 2050 | { |
| 1290 | | switch (state) |
| 1291 | | { |
| 1292 | | /* --- the following bits of info are set as 64-bit signed integers --- */ |
| 1293 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ: ppc->irq_pending = (ppc->irq_pending & ~1) | (info->i != CLEAR_LINE); break; |
| 2051 | UINT64 cycles_until_next; |
| 1294 | 2052 | |
| 1295 | | case CPUINFO_INT_PC: |
| 1296 | | case CPUINFO_INT_REGISTER + PPC_PC: ppc->pc = info->i; break; |
| 1297 | | case CPUINFO_INT_REGISTER + PPC_MSR: ppc->msr = info->i; break; |
| 1298 | | case CPUINFO_INT_REGISTER + PPC_CR: set_cr(ppc, info->i); break; |
| 1299 | | case CPUINFO_INT_REGISTER + PPC_LR: ppc->spr[SPR_LR] = info->i; break; |
| 1300 | | case CPUINFO_INT_REGISTER + PPC_CTR: ppc->spr[SPR_CTR] = info->i; break; |
| 1301 | | case CPUINFO_INT_REGISTER + PPC_XER: set_xer(ppc, info->i); break; |
| 1302 | | case CPUINFO_INT_REGISTER + PPC_SRR0: ppc->spr[SPROEA_SRR0] = info->i; break; |
| 1303 | | case CPUINFO_INT_REGISTER + PPC_SRR1: ppc->spr[SPROEA_SRR1] = info->i; break; |
| 1304 | | case CPUINFO_INT_REGISTER + PPC_SPRG0: ppc->spr[SPROEA_SPRG0] = info->i; break; |
| 1305 | | case CPUINFO_INT_REGISTER + PPC_SPRG1: ppc->spr[SPROEA_SPRG1] = info->i; break; |
| 1306 | | case CPUINFO_INT_REGISTER + PPC_SPRG2: ppc->spr[SPROEA_SPRG2] = info->i; break; |
| 1307 | | case CPUINFO_INT_REGISTER + PPC_SPRG3: ppc->spr[SPROEA_SPRG3] = info->i; break; |
| 1308 | | case CPUINFO_INT_REGISTER + PPC_SDR1: ppc->spr[SPROEA_SDR1] = info->i; break; |
| 1309 | | case CPUINFO_INT_REGISTER + PPC_EXIER: ppc->dcr[DCR4XX_EXIER] = info->i; break; |
| 1310 | | case CPUINFO_INT_REGISTER + PPC_EXISR: ppc->dcr[DCR4XX_EXISR] = info->i; break; |
| 1311 | | case CPUINFO_INT_REGISTER + PPC_EVPR: ppc->spr[SPR4XX_EVPR] = info->i; break; |
| 1312 | | case CPUINFO_INT_REGISTER + PPC_IOCR: ppc->dcr[DCR4XX_IOCR] = info->i; break; |
| 1313 | | case CPUINFO_INT_REGISTER + PPC_TBL: set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00ffffff00000000)) | info->i); break; |
| 1314 | | case CPUINFO_INT_REGISTER + PPC_TBH: set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00000000ffffffff)) | ((UINT64)(ppc->param1 & 0x00ffffff) << 32)); break; |
| 1315 | | case CPUINFO_INT_REGISTER + PPC_DEC: set_decrementer(ppc, info->i); break; |
| 2053 | /* set the decrementer IRQ state */ |
| 2054 | m_core->irq_pending |= 0x02; |
| 1316 | 2055 | |
| 1317 | | case CPUINFO_INT_REGISTER + PPC_SR0: ppc->sr[0] = info->i; break; |
| 1318 | | case CPUINFO_INT_REGISTER + PPC_SR1: ppc->sr[1] = info->i; break; |
| 1319 | | case CPUINFO_INT_REGISTER + PPC_SR2: ppc->sr[2] = info->i; break; |
| 1320 | | case CPUINFO_INT_REGISTER + PPC_SR3: ppc->sr[3] = info->i; break; |
| 1321 | | case CPUINFO_INT_REGISTER + PPC_SR4: ppc->sr[4] = info->i; break; |
| 1322 | | case CPUINFO_INT_REGISTER + PPC_SR5: ppc->sr[5] = info->i; break; |
| 1323 | | case CPUINFO_INT_REGISTER + PPC_SR6: ppc->sr[6] = info->i; break; |
| 1324 | | case CPUINFO_INT_REGISTER + PPC_SR7: ppc->sr[7] = info->i; break; |
| 1325 | | case CPUINFO_INT_REGISTER + PPC_SR8: ppc->sr[8] = info->i; break; |
| 1326 | | case CPUINFO_INT_REGISTER + PPC_SR9: ppc->sr[9] = info->i; break; |
| 1327 | | case CPUINFO_INT_REGISTER + PPC_SR10: ppc->sr[10] = info->i; break; |
| 1328 | | case CPUINFO_INT_REGISTER + PPC_SR11: ppc->sr[11] = info->i; break; |
| 1329 | | case CPUINFO_INT_REGISTER + PPC_SR12: ppc->sr[12] = info->i; break; |
| 1330 | | case CPUINFO_INT_REGISTER + PPC_SR13: ppc->sr[13] = info->i; break; |
| 1331 | | case CPUINFO_INT_REGISTER + PPC_SR14: ppc->sr[14] = info->i; break; |
| 1332 | | case CPUINFO_INT_REGISTER + PPC_SR15: ppc->sr[15] = info->i; break; |
| 1333 | | |
| 1334 | | case CPUINFO_INT_REGISTER + PPC_R0: ppc->r[0] = info->i; break; |
| 1335 | | case CPUINFO_INT_REGISTER + PPC_R1: ppc->r[1] = info->i; break; |
| 1336 | | case CPUINFO_INT_REGISTER + PPC_R2: ppc->r[2] = info->i; break; |
| 1337 | | case CPUINFO_INT_REGISTER + PPC_R3: ppc->r[3] = info->i; break; |
| 1338 | | case CPUINFO_INT_REGISTER + PPC_R4: ppc->r[4] = info->i; break; |
| 1339 | | case CPUINFO_INT_REGISTER + PPC_R5: ppc->r[5] = info->i; break; |
| 1340 | | case CPUINFO_INT_REGISTER + PPC_R6: ppc->r[6] = info->i; break; |
| 1341 | | case CPUINFO_INT_REGISTER + PPC_R7: ppc->r[7] = info->i; break; |
| 1342 | | case CPUINFO_INT_REGISTER + PPC_R8: ppc->r[8] = info->i; break; |
| 1343 | | case CPUINFO_INT_REGISTER + PPC_R9: ppc->r[9] = info->i; break; |
| 1344 | | case CPUINFO_INT_REGISTER + PPC_R10: ppc->r[10] = info->i; break; |
| 1345 | | case CPUINFO_INT_REGISTER + PPC_R11: ppc->r[11] = info->i; break; |
| 1346 | | case CPUINFO_INT_REGISTER + PPC_R12: ppc->r[12] = info->i; break; |
| 1347 | | case CPUINFO_INT_REGISTER + PPC_R13: ppc->r[13] = info->i; break; |
| 1348 | | case CPUINFO_INT_REGISTER + PPC_R14: ppc->r[14] = info->i; break; |
| 1349 | | case CPUINFO_INT_REGISTER + PPC_R15: ppc->r[15] = info->i; break; |
| 1350 | | case CPUINFO_INT_REGISTER + PPC_R16: ppc->r[16] = info->i; break; |
| 1351 | | case CPUINFO_INT_REGISTER + PPC_R17: ppc->r[17] = info->i; break; |
| 1352 | | case CPUINFO_INT_REGISTER + PPC_R18: ppc->r[18] = info->i; break; |
| 1353 | | case CPUINFO_INT_REGISTER + PPC_R19: ppc->r[19] = info->i; break; |
| 1354 | | case CPUINFO_INT_REGISTER + PPC_R20: ppc->r[20] = info->i; break; |
| 1355 | | case CPUINFO_INT_REGISTER + PPC_R21: ppc->r[21] = info->i; break; |
| 1356 | | case CPUINFO_INT_REGISTER + PPC_R22: ppc->r[22] = info->i; break; |
| 1357 | | case CPUINFO_INT_REGISTER + PPC_R23: ppc->r[23] = info->i; break; |
| 1358 | | case CPUINFO_INT_REGISTER + PPC_R24: ppc->r[24] = info->i; break; |
| 1359 | | case CPUINFO_INT_REGISTER + PPC_R25: ppc->r[25] = info->i; break; |
| 1360 | | case CPUINFO_INT_REGISTER + PPC_R26: ppc->r[26] = info->i; break; |
| 1361 | | case CPUINFO_INT_REGISTER + PPC_R27: ppc->r[27] = info->i; break; |
| 1362 | | case CPUINFO_INT_REGISTER + PPC_R28: ppc->r[28] = info->i; break; |
| 1363 | | case CPUINFO_INT_REGISTER + PPC_R29: ppc->r[29] = info->i; break; |
| 1364 | | case CPUINFO_INT_REGISTER + PPC_R30: ppc->r[30] = info->i; break; |
| 1365 | | case CPUINFO_INT_SP: |
| 1366 | | case CPUINFO_INT_REGISTER + PPC_R31: ppc->r[31] = info->i; break; |
| 1367 | | |
| 1368 | | case CPUINFO_INT_REGISTER + PPC_F0: ppc->f[0] = *(double *)&info->i; break; |
| 1369 | | case CPUINFO_INT_REGISTER + PPC_F1: ppc->f[1] = *(double *)&info->i; break; |
| 1370 | | case CPUINFO_INT_REGISTER + PPC_F2: ppc->f[2] = *(double *)&info->i; break; |
| 1371 | | case CPUINFO_INT_REGISTER + PPC_F3: ppc->f[3] = *(double *)&info->i; break; |
| 1372 | | case CPUINFO_INT_REGISTER + PPC_F4: ppc->f[4] = *(double *)&info->i; break; |
| 1373 | | case CPUINFO_INT_REGISTER + PPC_F5: ppc->f[5] = *(double *)&info->i; break; |
| 1374 | | case CPUINFO_INT_REGISTER + PPC_F6: ppc->f[6] = *(double *)&info->i; break; |
| 1375 | | case CPUINFO_INT_REGISTER + PPC_F7: ppc->f[7] = *(double *)&info->i; break; |
| 1376 | | case CPUINFO_INT_REGISTER + PPC_F8: ppc->f[8] = *(double *)&info->i; break; |
| 1377 | | case CPUINFO_INT_REGISTER + PPC_F9: ppc->f[9] = *(double *)&info->i; break; |
| 1378 | | case CPUINFO_INT_REGISTER + PPC_F10: ppc->f[10] = *(double *)&info->i; break; |
| 1379 | | case CPUINFO_INT_REGISTER + PPC_F11: ppc->f[11] = *(double *)&info->i; break; |
| 1380 | | case CPUINFO_INT_REGISTER + PPC_F12: ppc->f[12] = *(double *)&info->i; break; |
| 1381 | | case CPUINFO_INT_REGISTER + PPC_F13: ppc->f[13] = *(double *)&info->i; break; |
| 1382 | | case CPUINFO_INT_REGISTER + PPC_F14: ppc->f[14] = *(double *)&info->i; break; |
| 1383 | | case CPUINFO_INT_REGISTER + PPC_F15: ppc->f[15] = *(double *)&info->i; break; |
| 1384 | | case CPUINFO_INT_REGISTER + PPC_F16: ppc->f[16] = *(double *)&info->i; break; |
| 1385 | | case CPUINFO_INT_REGISTER + PPC_F17: ppc->f[17] = *(double *)&info->i; break; |
| 1386 | | case CPUINFO_INT_REGISTER + PPC_F18: ppc->f[18] = *(double *)&info->i; break; |
| 1387 | | case CPUINFO_INT_REGISTER + PPC_F19: ppc->f[19] = *(double *)&info->i; break; |
| 1388 | | case CPUINFO_INT_REGISTER + PPC_F20: ppc->f[20] = *(double *)&info->i; break; |
| 1389 | | case CPUINFO_INT_REGISTER + PPC_F21: ppc->f[21] = *(double *)&info->i; break; |
| 1390 | | case CPUINFO_INT_REGISTER + PPC_F22: ppc->f[22] = *(double *)&info->i; break; |
| 1391 | | case CPUINFO_INT_REGISTER + PPC_F23: ppc->f[23] = *(double *)&info->i; break; |
| 1392 | | case CPUINFO_INT_REGISTER + PPC_F24: ppc->f[24] = *(double *)&info->i; break; |
| 1393 | | case CPUINFO_INT_REGISTER + PPC_F25: ppc->f[25] = *(double *)&info->i; break; |
| 1394 | | case CPUINFO_INT_REGISTER + PPC_F26: ppc->f[26] = *(double *)&info->i; break; |
| 1395 | | case CPUINFO_INT_REGISTER + PPC_F27: ppc->f[27] = *(double *)&info->i; break; |
| 1396 | | case CPUINFO_INT_REGISTER + PPC_F28: ppc->f[28] = *(double *)&info->i; break; |
| 1397 | | case CPUINFO_INT_REGISTER + PPC_F29: ppc->f[29] = *(double *)&info->i; break; |
| 1398 | | case CPUINFO_INT_REGISTER + PPC_F30: ppc->f[30] = *(double *)&info->i; break; |
| 1399 | | case CPUINFO_INT_REGISTER + PPC_F31: ppc->f[31] = *(double *)&info->i; break; |
| 1400 | | case CPUINFO_INT_REGISTER + PPC_FPSCR: ppc->fpscr = info->i; break; |
| 1401 | | } |
| 2056 | /* advance by another full rev */ |
| 2057 | m_dec_zero_cycles += (UINT64)m_tb_divisor << 32; |
| 2058 | cycles_until_next = m_dec_zero_cycles - total_cycles(); |
| 2059 | m_decrementer_int_timer->adjust(cycles_to_attotime(cycles_until_next)); |
| 1402 | 2060 | } |
| 1403 | 2061 | |
| 1404 | | |
| 1405 | 2062 | /*------------------------------------------------- |
| 1406 | | ppccom_get_info - get information about |
| 1407 | | a PowerPC CPU |
| 2063 | ppc_set_dcstore_callback - installs a callback |
| 2064 | for detecting datacache stores with dcbst |
| 1408 | 2065 | -------------------------------------------------*/ |
| 1409 | 2066 | |
| 1410 | | void ppccom_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) |
| 2067 | void ppc_device::ppc_set_dcstore_callback(ppc_dcstore_handler handler) |
| 1411 | 2068 | { |
| 1412 | | switch (state) |
| 1413 | | { |
| 1414 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1415 | | case CPUINFO_INT_CONTEXT_SIZE: /* provided by core */ break; |
| 1416 | | case CPUINFO_INT_INPUT_LINES: info->i = 1; break; |
| 1417 | | case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; |
| 1418 | | case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; |
| 1419 | | case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; |
| 1420 | | case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; |
| 1421 | | case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; |
| 1422 | | case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; |
| 1423 | | case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; |
| 1424 | | case CPUINFO_INT_MAX_CYCLES: info->i = 40; break; |
| 2069 | m_dcstore_handler = handler; |
| 2070 | } |
| 1425 | 2071 | |
| 1426 | | case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 64; break; |
| 1427 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; |
| 1428 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; |
| 1429 | | case CPUINFO_INT_LOGADDR_WIDTH_PROGRAM: info->i = 32; break; |
| 1430 | | case CPUINFO_INT_PAGE_SHIFT_PROGRAM: info->i = POWERPC_MIN_PAGE_SHIFT;break; |
| 1431 | 2072 | |
| 1432 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ: info->i = ppc->irq_pending ? ASSERT_LINE : CLEAR_LINE; break; |
| 1433 | | |
| 1434 | | case CPUINFO_INT_PREVIOUSPC: /* optionally implemented */ break; |
| 1435 | | |
| 1436 | | case CPUINFO_INT_PC: |
| 1437 | | case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc->pc; break; |
| 1438 | | case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc->msr; break; |
| 1439 | | case CPUINFO_INT_REGISTER + PPC_CR: info->i = get_cr(ppc); break; |
| 1440 | | case CPUINFO_INT_REGISTER + PPC_LR: info->i = ppc->spr[SPR_LR]; break; |
| 1441 | | case CPUINFO_INT_REGISTER + PPC_CTR: info->i = ppc->spr[SPR_CTR]; break; |
| 1442 | | case CPUINFO_INT_REGISTER + PPC_XER: info->i = get_xer(ppc); break; |
| 1443 | | case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = ppc->spr[SPROEA_SRR0]; break; |
| 1444 | | case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = ppc->spr[SPROEA_SRR1]; break; |
| 1445 | | case CPUINFO_INT_REGISTER + PPC_SPRG0: info->i = ppc->spr[SPROEA_SPRG0]; break; |
| 1446 | | case CPUINFO_INT_REGISTER + PPC_SPRG1: info->i = ppc->spr[SPROEA_SPRG1]; break; |
| 1447 | | case CPUINFO_INT_REGISTER + PPC_SPRG2: info->i = ppc->spr[SPROEA_SPRG2]; break; |
| 1448 | | case CPUINFO_INT_REGISTER + PPC_SPRG3: info->i = ppc->spr[SPROEA_SPRG3]; break; |
| 1449 | | case CPUINFO_INT_REGISTER + PPC_SDR1: info->i = ppc->spr[SPROEA_SDR1]; break; |
| 1450 | | case CPUINFO_INT_REGISTER + PPC_EXIER: info->i = ppc->dcr[DCR4XX_EXIER]; break; |
| 1451 | | case CPUINFO_INT_REGISTER + PPC_EXISR: info->i = ppc->dcr[DCR4XX_EXISR]; break; |
| 1452 | | case CPUINFO_INT_REGISTER + PPC_EVPR: info->i = ppc->spr[SPR4XX_EVPR]; break; |
| 1453 | | case CPUINFO_INT_REGISTER + PPC_IOCR: info->i = ppc->dcr[DCR4XX_IOCR]; break; |
| 1454 | | case CPUINFO_INT_REGISTER + PPC_TBH: info->i = get_timebase(ppc) >> 32; break; |
| 1455 | | case CPUINFO_INT_REGISTER + PPC_TBL: info->i = (UINT32)get_timebase(ppc); break; |
| 1456 | | case CPUINFO_INT_REGISTER + PPC_DEC: info->i = get_decrementer(ppc); break; |
| 1457 | | |
| 1458 | | case CPUINFO_INT_REGISTER + PPC_SR0: info->i = ppc->sr[0]; break; |
| 1459 | | case CPUINFO_INT_REGISTER + PPC_SR1: info->i = ppc->sr[1]; break; |
| 1460 | | case CPUINFO_INT_REGISTER + PPC_SR2: info->i = ppc->sr[2]; break; |
| 1461 | | case CPUINFO_INT_REGISTER + PPC_SR3: info->i = ppc->sr[3]; break; |
| 1462 | | case CPUINFO_INT_REGISTER + PPC_SR4: info->i = ppc->sr[4]; break; |
| 1463 | | case CPUINFO_INT_REGISTER + PPC_SR5: info->i = ppc->sr[5]; break; |
| 1464 | | case CPUINFO_INT_REGISTER + PPC_SR6: info->i = ppc->sr[6]; break; |
| 1465 | | case CPUINFO_INT_REGISTER + PPC_SR7: info->i = ppc->sr[7]; break; |
| 1466 | | case CPUINFO_INT_REGISTER + PPC_SR8: info->i = ppc->sr[8]; break; |
| 1467 | | case CPUINFO_INT_REGISTER + PPC_SR9: info->i = ppc->sr[9]; break; |
| 1468 | | case CPUINFO_INT_REGISTER + PPC_SR10: info->i = ppc->sr[10]; break; |
| 1469 | | case CPUINFO_INT_REGISTER + PPC_SR11: info->i = ppc->sr[11]; break; |
| 1470 | | case CPUINFO_INT_REGISTER + PPC_SR12: info->i = ppc->sr[12]; break; |
| 1471 | | case CPUINFO_INT_REGISTER + PPC_SR13: info->i = ppc->sr[13]; break; |
| 1472 | | case CPUINFO_INT_REGISTER + PPC_SR14: info->i = ppc->sr[14]; break; |
| 1473 | | case CPUINFO_INT_REGISTER + PPC_SR15: info->i = ppc->sr[15]; break; |
| 1474 | | |
| 1475 | | case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc->r[0]; break; |
| 1476 | | case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc->r[1]; break; |
| 1477 | | case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc->r[2]; break; |
| 1478 | | case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc->r[3]; break; |
| 1479 | | case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc->r[4]; break; |
| 1480 | | case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc->r[5]; break; |
| 1481 | | case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc->r[6]; break; |
| 1482 | | case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc->r[7]; break; |
| 1483 | | case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc->r[8]; break; |
| 1484 | | case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc->r[9]; break; |
| 1485 | | case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc->r[10]; break; |
| 1486 | | case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc->r[11]; break; |
| 1487 | | case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc->r[12]; break; |
| 1488 | | case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc->r[13]; break; |
| 1489 | | case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc->r[14]; break; |
| 1490 | | case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc->r[15]; break; |
| 1491 | | case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc->r[16]; break; |
| 1492 | | case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc->r[17]; break; |
| 1493 | | case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc->r[18]; break; |
| 1494 | | case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc->r[19]; break; |
| 1495 | | case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc->r[20]; break; |
| 1496 | | case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc->r[21]; break; |
| 1497 | | case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc->r[22]; break; |
| 1498 | | case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc->r[23]; break; |
| 1499 | | case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc->r[24]; break; |
| 1500 | | case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc->r[25]; break; |
| 1501 | | case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc->r[26]; break; |
| 1502 | | case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc->r[27]; break; |
| 1503 | | case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc->r[28]; break; |
| 1504 | | case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc->r[29]; break; |
| 1505 | | case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc->r[30]; break; |
| 1506 | | case CPUINFO_INT_SP: |
| 1507 | | case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc->r[31]; break; |
| 1508 | | |
| 1509 | | case CPUINFO_INT_REGISTER + PPC_F0: info->i = *(UINT64 *)&ppc->f[0]; break; |
| 1510 | | case CPUINFO_INT_REGISTER + PPC_F1: info->i = *(UINT64 *)&ppc->f[1]; break; |
| 1511 | | case CPUINFO_INT_REGISTER + PPC_F2: info->i = *(UINT64 *)&ppc->f[2]; break; |
| 1512 | | case CPUINFO_INT_REGISTER + PPC_F3: info->i = *(UINT64 *)&ppc->f[3]; break; |
| 1513 | | case CPUINFO_INT_REGISTER + PPC_F4: info->i = *(UINT64 *)&ppc->f[4]; break; |
| 1514 | | case CPUINFO_INT_REGISTER + PPC_F5: info->i = *(UINT64 *)&ppc->f[5]; break; |
| 1515 | | case CPUINFO_INT_REGISTER + PPC_F6: info->i = *(UINT64 *)&ppc->f[6]; break; |
| 1516 | | case CPUINFO_INT_REGISTER + PPC_F7: info->i = *(UINT64 *)&ppc->f[7]; break; |
| 1517 | | case CPUINFO_INT_REGISTER + PPC_F8: info->i = *(UINT64 *)&ppc->f[8]; break; |
| 1518 | | case CPUINFO_INT_REGISTER + PPC_F9: info->i = *(UINT64 *)&ppc->f[9]; break; |
| 1519 | | case CPUINFO_INT_REGISTER + PPC_F10: info->i = *(UINT64 *)&ppc->f[10]; break; |
| 1520 | | case CPUINFO_INT_REGISTER + PPC_F11: info->i = *(UINT64 *)&ppc->f[11]; break; |
| 1521 | | case CPUINFO_INT_REGISTER + PPC_F12: info->i = *(UINT64 *)&ppc->f[12]; break; |
| 1522 | | case CPUINFO_INT_REGISTER + PPC_F13: info->i = *(UINT64 *)&ppc->f[13]; break; |
| 1523 | | case CPUINFO_INT_REGISTER + PPC_F14: info->i = *(UINT64 *)&ppc->f[14]; break; |
| 1524 | | case CPUINFO_INT_REGISTER + PPC_F15: info->i = *(UINT64 *)&ppc->f[15]; break; |
| 1525 | | case CPUINFO_INT_REGISTER + PPC_F16: info->i = *(UINT64 *)&ppc->f[16]; break; |
| 1526 | | case CPUINFO_INT_REGISTER + PPC_F17: info->i = *(UINT64 *)&ppc->f[17]; break; |
| 1527 | | case CPUINFO_INT_REGISTER + PPC_F18: info->i = *(UINT64 *)&ppc->f[18]; break; |
| 1528 | | case CPUINFO_INT_REGISTER + PPC_F19: info->i = *(UINT64 *)&ppc->f[19]; break; |
| 1529 | | case CPUINFO_INT_REGISTER + PPC_F20: info->i = *(UINT64 *)&ppc->f[20]; break; |
| 1530 | | case CPUINFO_INT_REGISTER + PPC_F21: info->i = *(UINT64 *)&ppc->f[21]; break; |
| 1531 | | case CPUINFO_INT_REGISTER + PPC_F22: info->i = *(UINT64 *)&ppc->f[22]; break; |
| 1532 | | case CPUINFO_INT_REGISTER + PPC_F23: info->i = *(UINT64 *)&ppc->f[23]; break; |
| 1533 | | case CPUINFO_INT_REGISTER + PPC_F24: info->i = *(UINT64 *)&ppc->f[24]; break; |
| 1534 | | case CPUINFO_INT_REGISTER + PPC_F25: info->i = *(UINT64 *)&ppc->f[25]; break; |
| 1535 | | case CPUINFO_INT_REGISTER + PPC_F26: info->i = *(UINT64 *)&ppc->f[26]; break; |
| 1536 | | case CPUINFO_INT_REGISTER + PPC_F27: info->i = *(UINT64 *)&ppc->f[27]; break; |
| 1537 | | case CPUINFO_INT_REGISTER + PPC_F28: info->i = *(UINT64 *)&ppc->f[28]; break; |
| 1538 | | case CPUINFO_INT_REGISTER + PPC_F29: info->i = *(UINT64 *)&ppc->f[29]; break; |
| 1539 | | case CPUINFO_INT_REGISTER + PPC_F30: info->i = *(UINT64 *)&ppc->f[30]; break; |
| 1540 | | case CPUINFO_INT_REGISTER + PPC_F31: info->i = *(UINT64 *)&ppc->f[31]; break; |
| 1541 | | case CPUINFO_INT_REGISTER + PPC_FPSCR: info->i = ppc->fpscr; break; |
| 1542 | | |
| 1543 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1544 | | case CPUINFO_FCT_SET_INFO: /* provided by core */ break; |
| 1545 | | case CPUINFO_FCT_INIT: /* provided by core */ break; |
| 1546 | | case CPUINFO_FCT_RESET: /* provided by core */ break; |
| 1547 | | case CPUINFO_FCT_EXIT: /* provided by core */ break; |
| 1548 | | case CPUINFO_FCT_EXECUTE: /* provided by core */ break; |
| 1549 | | case CPUINFO_FCT_TRANSLATE: /* provided by core */ break; |
| 1550 | | case CPUINFO_FCT_DISASSEMBLE: /* provided by core */ break; |
| 1551 | | case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc->icount; break; |
| 1552 | | |
| 1553 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1554 | | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC"); break; |
| 1555 | | case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc"); break; |
| 1556 | | case CPUINFO_STR_FAMILY: strcpy(info->s, "PowerPC"); break; |
| 1557 | | case CPUINFO_STR_VERSION: strcpy(info->s, "2.0"); break; |
| 1558 | | case CPUINFO_STR_SOURCE_FILE: /* provided by core */ break; |
| 1559 | | case CPUINFO_STR_CREDITS: strcpy(info->s, "Copyright Aaron Giles"); break; |
| 1560 | | |
| 1561 | | case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; |
| 1562 | | |
| 1563 | | case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc->pc); break; |
| 1564 | | case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR:%08X", ppc->msr); break; |
| 1565 | | case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", get_cr(ppc)); break; |
| 1566 | | case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", ppc->spr[SPR_LR]); break; |
| 1567 | | case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR:%08X", ppc->spr[SPR_CTR]); break; |
| 1568 | | case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER:%08X", get_xer(ppc)); break; |
| 1569 | | case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", ppc->spr[SPROEA_SRR0]); break; |
| 1570 | | case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", ppc->spr[SPROEA_SRR1]); break; |
| 1571 | | case CPUINFO_STR_REGISTER + PPC_SPRG0: sprintf(info->s, "SPRG0: %08X", ppc->spr[SPROEA_SPRG0]); break; |
| 1572 | | case CPUINFO_STR_REGISTER + PPC_SPRG1: sprintf(info->s, "SPRG1: %08X", ppc->spr[SPROEA_SPRG1]); break; |
| 1573 | | case CPUINFO_STR_REGISTER + PPC_SPRG2: sprintf(info->s, "SPRG2: %08X", ppc->spr[SPROEA_SPRG2]); break; |
| 1574 | | case CPUINFO_STR_REGISTER + PPC_SPRG3: sprintf(info->s, "SPRG3: %08X", ppc->spr[SPROEA_SPRG3]); break; |
| 1575 | | case CPUINFO_STR_REGISTER + PPC_SDR1: sprintf(info->s, "SDR1: %08X", ppc->spr[SPROEA_SDR1]); break; |
| 1576 | | case CPUINFO_STR_REGISTER + PPC_EXIER: sprintf(info->s, "EXIER: %08X", ppc->dcr[DCR4XX_EXIER]); break; |
| 1577 | | case CPUINFO_STR_REGISTER + PPC_EXISR: sprintf(info->s, "EXISR: %08X", ppc->dcr[DCR4XX_EXISR]); break; |
| 1578 | | case CPUINFO_STR_REGISTER + PPC_EVPR: sprintf(info->s, "EVPR: %08X", ppc->spr[SPR4XX_EVPR]); break; |
| 1579 | | case CPUINFO_STR_REGISTER + PPC_IOCR: sprintf(info->s, "IOCR: %08X", ppc->dcr[DCR4XX_EXISR]); break; |
| 1580 | | case CPUINFO_STR_REGISTER + PPC_TBH: sprintf(info->s, "TBH: %08X", (UINT32)(get_timebase(ppc) >> 32)); break; |
| 1581 | | case CPUINFO_STR_REGISTER + PPC_TBL: sprintf(info->s, "TBL: %08X", (UINT32)get_timebase(ppc)); break; |
| 1582 | | case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", get_decrementer(ppc)); break; |
| 1583 | | |
| 1584 | | case CPUINFO_STR_REGISTER + PPC_SR0: sprintf(info->s, "SR0: %08X", ppc->sr[0]); break; |
| 1585 | | case CPUINFO_STR_REGISTER + PPC_SR1: sprintf(info->s, "SR1: %08X", ppc->sr[1]); break; |
| 1586 | | case CPUINFO_STR_REGISTER + PPC_SR2: sprintf(info->s, "SR2: %08X", ppc->sr[2]); break; |
| 1587 | | case CPUINFO_STR_REGISTER + PPC_SR3: sprintf(info->s, "SR3: %08X", ppc->sr[3]); break; |
| 1588 | | case CPUINFO_STR_REGISTER + PPC_SR4: sprintf(info->s, "SR4: %08X", ppc->sr[4]); break; |
| 1589 | | case CPUINFO_STR_REGISTER + PPC_SR5: sprintf(info->s, "SR5: %08X", ppc->sr[5]); break; |
| 1590 | | case CPUINFO_STR_REGISTER + PPC_SR6: sprintf(info->s, "SR6: %08X", ppc->sr[6]); break; |
| 1591 | | case CPUINFO_STR_REGISTER + PPC_SR7: sprintf(info->s, "SR7: %08X", ppc->sr[7]); break; |
| 1592 | | case CPUINFO_STR_REGISTER + PPC_SR8: sprintf(info->s, "SR8: %08X", ppc->sr[8]); break; |
| 1593 | | case CPUINFO_STR_REGISTER + PPC_SR9: sprintf(info->s, "SR9: %08X", ppc->sr[9]); break; |
| 1594 | | case CPUINFO_STR_REGISTER + PPC_SR10: sprintf(info->s, "SR10: %08X", ppc->sr[10]); break; |
| 1595 | | case CPUINFO_STR_REGISTER + PPC_SR11: sprintf(info->s, "SR11: %08X", ppc->sr[11]); break; |
| 1596 | | case CPUINFO_STR_REGISTER + PPC_SR12: sprintf(info->s, "SR12: %08X", ppc->sr[12]); break; |
| 1597 | | case CPUINFO_STR_REGISTER + PPC_SR13: sprintf(info->s, "SR13: %08X", ppc->sr[13]); break; |
| 1598 | | case CPUINFO_STR_REGISTER + PPC_SR14: sprintf(info->s, "SR14: %08X", ppc->sr[14]); break; |
| 1599 | | case CPUINFO_STR_REGISTER + PPC_SR15: sprintf(info->s, "SR15: %08X", ppc->sr[15]); break; |
| 1600 | | |
| 1601 | | case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc->r[0]); break; |
| 1602 | | case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc->r[1]); break; |
| 1603 | | case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc->r[2]); break; |
| 1604 | | case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc->r[3]); break; |
| 1605 | | case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc->r[4]); break; |
| 1606 | | case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc->r[5]); break; |
| 1607 | | case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc->r[6]); break; |
| 1608 | | case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc->r[7]); break; |
| 1609 | | case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc->r[8]); break; |
| 1610 | | case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc->r[9]); break; |
| 1611 | | case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10:%08X", ppc->r[10]); break; |
| 1612 | | case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11:%08X", ppc->r[11]); break; |
| 1613 | | case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12:%08X", ppc->r[12]); break; |
| 1614 | | case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13:%08X", ppc->r[13]); break; |
| 1615 | | case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14:%08X", ppc->r[14]); break; |
| 1616 | | case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15:%08X", ppc->r[15]); break; |
| 1617 | | case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16:%08X", ppc->r[16]); break; |
| 1618 | | case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17:%08X", ppc->r[17]); break; |
| 1619 | | case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18:%08X", ppc->r[18]); break; |
| 1620 | | case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19:%08X", ppc->r[19]); break; |
| 1621 | | case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20:%08X", ppc->r[20]); break; |
| 1622 | | case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21:%08X", ppc->r[21]); break; |
| 1623 | | case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22:%08X", ppc->r[22]); break; |
| 1624 | | case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23:%08X", ppc->r[23]); break; |
| 1625 | | case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24:%08X", ppc->r[24]); break; |
| 1626 | | case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25:%08X", ppc->r[25]); break; |
| 1627 | | case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26:%08X", ppc->r[26]); break; |
| 1628 | | case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27:%08X", ppc->r[27]); break; |
| 1629 | | case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28:%08X", ppc->r[28]); break; |
| 1630 | | case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29:%08X", ppc->r[29]); break; |
| 1631 | | case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30:%08X", ppc->r[30]); break; |
| 1632 | | case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31:%08X", ppc->r[31]); break; |
| 1633 | | |
| 1634 | | case CPUINFO_STR_REGISTER + PPC_F0: sprintf(info->s, "F0: %12f", ppc->f[0]); break; |
| 1635 | | case CPUINFO_STR_REGISTER + PPC_F1: sprintf(info->s, "F1: %12f", ppc->f[1]); break; |
| 1636 | | case CPUINFO_STR_REGISTER + PPC_F2: sprintf(info->s, "F2: %12f", ppc->f[2]); break; |
| 1637 | | case CPUINFO_STR_REGISTER + PPC_F3: sprintf(info->s, "F3: %12f", ppc->f[3]); break; |
| 1638 | | case CPUINFO_STR_REGISTER + PPC_F4: sprintf(info->s, "F4: %12f", ppc->f[4]); break; |
| 1639 | | case CPUINFO_STR_REGISTER + PPC_F5: sprintf(info->s, "F5: %12f", ppc->f[5]); break; |
| 1640 | | case CPUINFO_STR_REGISTER + PPC_F6: sprintf(info->s, "F6: %12f", ppc->f[6]); break; |
| 1641 | | case CPUINFO_STR_REGISTER + PPC_F7: sprintf(info->s, "F7: %12f", ppc->f[7]); break; |
| 1642 | | case CPUINFO_STR_REGISTER + PPC_F8: sprintf(info->s, "F8: %12f", ppc->f[8]); break; |
| 1643 | | case CPUINFO_STR_REGISTER + PPC_F9: sprintf(info->s, "F9: %12f", ppc->f[9]); break; |
| 1644 | | case CPUINFO_STR_REGISTER + PPC_F10: sprintf(info->s, "F10:%12f", ppc->f[10]); break; |
| 1645 | | case CPUINFO_STR_REGISTER + PPC_F11: sprintf(info->s, "F11:%12f", ppc->f[11]); break; |
| 1646 | | case CPUINFO_STR_REGISTER + PPC_F12: sprintf(info->s, "F12:%12f", ppc->f[12]); break; |
| 1647 | | case CPUINFO_STR_REGISTER + PPC_F13: sprintf(info->s, "F13:%12f", ppc->f[13]); break; |
| 1648 | | case CPUINFO_STR_REGISTER + PPC_F14: sprintf(info->s, "F14:%12f", ppc->f[14]); break; |
| 1649 | | case CPUINFO_STR_REGISTER + PPC_F15: sprintf(info->s, "F15:%12f", ppc->f[15]); break; |
| 1650 | | case CPUINFO_STR_REGISTER + PPC_F16: sprintf(info->s, "F16:%12f", ppc->f[16]); break; |
| 1651 | | case CPUINFO_STR_REGISTER + PPC_F17: sprintf(info->s, "F17:%12f", ppc->f[17]); break; |
| 1652 | | case CPUINFO_STR_REGISTER + PPC_F18: sprintf(info->s, "F18:%12f", ppc->f[18]); break; |
| 1653 | | case CPUINFO_STR_REGISTER + PPC_F19: sprintf(info->s, "F19:%12f", ppc->f[19]); break; |
| 1654 | | case CPUINFO_STR_REGISTER + PPC_F20: sprintf(info->s, "F20:%12f", ppc->f[20]); break; |
| 1655 | | case CPUINFO_STR_REGISTER + PPC_F21: sprintf(info->s, "F21:%12f", ppc->f[21]); break; |
| 1656 | | case CPUINFO_STR_REGISTER + PPC_F22: sprintf(info->s, "F22:%12f", ppc->f[22]); break; |
| 1657 | | case CPUINFO_STR_REGISTER + PPC_F23: sprintf(info->s, "F23:%12f", ppc->f[23]); break; |
| 1658 | | case CPUINFO_STR_REGISTER + PPC_F24: sprintf(info->s, "F24:%12f", ppc->f[24]); break; |
| 1659 | | case CPUINFO_STR_REGISTER + PPC_F25: sprintf(info->s, "F25:%12f", ppc->f[25]); break; |
| 1660 | | case CPUINFO_STR_REGISTER + PPC_F26: sprintf(info->s, "F26:%12f", ppc->f[26]); break; |
| 1661 | | case CPUINFO_STR_REGISTER + PPC_F27: sprintf(info->s, "F27:%12f", ppc->f[27]); break; |
| 1662 | | case CPUINFO_STR_REGISTER + PPC_F28: sprintf(info->s, "F28:%12f", ppc->f[28]); break; |
| 1663 | | case CPUINFO_STR_REGISTER + PPC_F29: sprintf(info->s, "F29:%12f", ppc->f[29]); break; |
| 1664 | | case CPUINFO_STR_REGISTER + PPC_F30: sprintf(info->s, "F30:%12f", ppc->f[30]); break; |
| 1665 | | case CPUINFO_STR_REGISTER + PPC_F31: sprintf(info->s, "F31:%12f", ppc->f[31]); break; |
| 1666 | | case CPUINFO_STR_REGISTER + PPC_FPSCR: sprintf(info->s, "FPSCR:%08X", ppc->fpscr); break; |
| 2073 | void ppc_device::execute_set_input(int inputnum, int state) |
| 2074 | { |
| 2075 | switch (inputnum) |
| 2076 | { |
| 2077 | case PPC_IRQ: |
| 2078 | m_core->irq_pending = (m_core->irq_pending & ~1) | ((state != CLEAR_LINE) ? 1 : 0); |
| 2079 | break; |
| 1667 | 2080 | } |
| 1668 | 2081 | } |
| 1669 | 2082 | |
| 1670 | 2083 | |
| 1671 | | |
| 1672 | | /*************************************************************************** |
| 1673 | | OEA HELPERS |
| 1674 | | ***************************************************************************/ |
| 1675 | | |
| 1676 | | /*------------------------------------------------- |
| 1677 | | decrementer_int_callback - callback that fires |
| 1678 | | whenever a decrementer interrupt is generated |
| 1679 | | -------------------------------------------------*/ |
| 1680 | | |
| 1681 | | static TIMER_CALLBACK( decrementer_int_callback ) |
| 2084 | void ppc4xx_device::execute_set_input(int inputnum, int state) |
| 1682 | 2085 | { |
| 1683 | | powerpc_state *ppc = (powerpc_state *)ptr; |
| 1684 | | UINT64 cycles_until_next; |
| 2086 | switch (inputnum) |
| 2087 | { |
| 2088 | case PPC_IRQ_LINE_0: |
| 2089 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT0, state); |
| 2090 | break; |
| 1685 | 2091 | |
| 1686 | | /* set the decrementer IRQ state */ |
| 1687 | | ppc->irq_pending |= 0x02; |
| 2092 | case PPC_IRQ_LINE_1: |
| 2093 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT1, state); |
| 2094 | break; |
| 1688 | 2095 | |
| 1689 | | /* advance by another full rev */ |
| 1690 | | ppc->dec_zero_cycles += (UINT64)ppc->tb_divisor << 32; |
| 1691 | | cycles_until_next = ppc->dec_zero_cycles - ppc->device->total_cycles(); |
| 1692 | | ppc->decrementer_int_timer->adjust(ppc->device->cycles_to_attotime(cycles_until_next)); |
| 1693 | | } |
| 2096 | case PPC_IRQ_LINE_2: |
| 2097 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT2, state); |
| 2098 | break; |
| 1694 | 2099 | |
| 1695 | | /*------------------------------------------------- |
| 1696 | | ppc_set_dcstore_callback - installs a callback |
| 1697 | | for detecting datacache stores with dcbst |
| 1698 | | -------------------------------------------------*/ |
| 2100 | case PPC_IRQ_LINE_3: |
| 2101 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT3, state); |
| 2102 | break; |
| 1699 | 2103 | |
| 1700 | | void ppc_set_dcstore_callback(device_t *device, ppc_dcstore_handler handler) |
| 1701 | | { |
| 1702 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 1703 | | ppc->dcstore_handler = handler; |
| 2104 | case PPC_IRQ_LINE_4: |
| 2105 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT4, state); |
| 2106 | break; |
| 2107 | } |
| 1704 | 2108 | } |
| 1705 | 2109 | |
| 1706 | 2110 | |
| r31142 | r31143 | |
| 1713 | 2117 | IRQ line management |
| 1714 | 2118 | -------------------------------------------------*/ |
| 1715 | 2119 | |
| 1716 | | static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state) |
| 2120 | void ppc_device::ppc4xx_set_irq_line(UINT32 bitmask, int state) |
| 1717 | 2121 | { |
| 1718 | | UINT32 oldstate = ppc->irqstate; |
| 2122 | UINT32 oldstate = m_irqstate; |
| 1719 | 2123 | UINT32 levelmask; |
| 1720 | 2124 | |
| 1721 | 2125 | /* set or clear the appropriate bit */ |
| 1722 | 2126 | if (state != CLEAR_LINE) |
| 1723 | | ppc->irqstate |= bitmask; |
| 2127 | m_irqstate |= bitmask; |
| 1724 | 2128 | else |
| 1725 | | ppc->irqstate &= ~bitmask; |
| 2129 | m_irqstate &= ~bitmask; |
| 1726 | 2130 | |
| 1727 | 2131 | /* if the state changed to on, edge trigger the interrupt */ |
| 1728 | | if (((ppc->irqstate ^ oldstate) & bitmask) && (ppc->irqstate & bitmask)) |
| 1729 | | ppc->dcr[DCR4XX_EXISR] |= bitmask; |
| 2132 | if (((m_irqstate ^ oldstate) & bitmask) && (m_irqstate & bitmask)) |
| 2133 | m_dcr[DCR4XX_EXISR] |= bitmask; |
| 1730 | 2134 | |
| 1731 | 2135 | /* pass through all level-triggered interrupts */ |
| 1732 | 2136 | levelmask = PPC4XX_IRQ_BIT_CRITICAL | PPC4XX_IRQ_BIT_SPUR | PPC4XX_IRQ_BIT_SPUT; |
| 1733 | 2137 | levelmask |= PPC4XX_IRQ_BIT_JTAGR | PPC4XX_IRQ_BIT_JTAGT; |
| 1734 | 2138 | levelmask |= PPC4XX_IRQ_BIT_DMA0 | PPC4XX_IRQ_BIT_DMA1 | PPC4XX_IRQ_BIT_DMA2 | PPC4XX_IRQ_BIT_DMA3; |
| 1735 | | if (!(ppc->dcr[DCR4XX_IOCR] & 0x80000000)) levelmask |= PPC4XX_IRQ_BIT_EXT0; |
| 1736 | | if (!(ppc->dcr[DCR4XX_IOCR] & 0x20000000)) levelmask |= PPC4XX_IRQ_BIT_EXT1; |
| 1737 | | if (!(ppc->dcr[DCR4XX_IOCR] & 0x08000000)) levelmask |= PPC4XX_IRQ_BIT_EXT2; |
| 1738 | | if (!(ppc->dcr[DCR4XX_IOCR] & 0x02000000)) levelmask |= PPC4XX_IRQ_BIT_EXT3; |
| 1739 | | if (!(ppc->dcr[DCR4XX_IOCR] & 0x00800000)) levelmask |= PPC4XX_IRQ_BIT_EXT4; |
| 1740 | | ppc->dcr[DCR4XX_EXISR] = (ppc->dcr[DCR4XX_EXISR] & ~levelmask) | (ppc->irqstate & levelmask); |
| 2139 | if (!(m_dcr[DCR4XX_IOCR] & 0x80000000)) levelmask |= PPC4XX_IRQ_BIT_EXT0; |
| 2140 | if (!(m_dcr[DCR4XX_IOCR] & 0x20000000)) levelmask |= PPC4XX_IRQ_BIT_EXT1; |
| 2141 | if (!(m_dcr[DCR4XX_IOCR] & 0x08000000)) levelmask |= PPC4XX_IRQ_BIT_EXT2; |
| 2142 | if (!(m_dcr[DCR4XX_IOCR] & 0x02000000)) levelmask |= PPC4XX_IRQ_BIT_EXT3; |
| 2143 | if (!(m_dcr[DCR4XX_IOCR] & 0x00800000)) levelmask |= PPC4XX_IRQ_BIT_EXT4; |
| 2144 | m_dcr[DCR4XX_EXISR] = (m_dcr[DCR4XX_EXISR] & ~levelmask) | (m_irqstate & levelmask); |
| 1741 | 2145 | |
| 1742 | 2146 | /* update the IRQ status */ |
| 1743 | | ppc->irq_pending = ((ppc->dcr[DCR4XX_EXISR] & ppc->dcr[DCR4XX_EXIER]) != 0); |
| 1744 | | if ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) && (ppc->spr[SPR4XX_TSR] & PPC4XX_TSR_FIS)) |
| 1745 | | ppc->irq_pending = TRUE; |
| 1746 | | if ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && (ppc->spr[SPR4XX_TSR] & PPC4XX_TSR_PIS)) |
| 1747 | | ppc->irq_pending = TRUE; |
| 2147 | m_core->irq_pending = ((m_dcr[DCR4XX_EXISR] & m_dcr[DCR4XX_EXIER]) != 0); |
| 2148 | if ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) && (m_core->spr[SPR4XX_TSR] & PPC4XX_TSR_FIS)) |
| 2149 | m_core->irq_pending = TRUE; |
| 2150 | if ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && (m_core->spr[SPR4XX_TSR] & PPC4XX_TSR_PIS)) |
| 2151 | m_core->irq_pending = TRUE; |
| 1748 | 2152 | } |
| 1749 | 2153 | |
| 1750 | 2154 | |
| r31142 | r31143 | |
| 1753 | 2157 | IRQ line state getter |
| 1754 | 2158 | -------------------------------------------------*/ |
| 1755 | 2159 | |
| 1756 | | static int ppc4xx_get_irq_line(powerpc_state *ppc, UINT32 bitmask) |
| 2160 | int ppc_device::ppc4xx_get_irq_line(UINT32 bitmask) |
| 1757 | 2161 | { |
| 1758 | | return (ppc->irqstate & bitmask) ? ASSERT_LINE : CLEAR_LINE; |
| 2162 | return (m_irqstate & bitmask) ? ASSERT_LINE : CLEAR_LINE; |
| 1759 | 2163 | } |
| 1760 | 2164 | |
| 1761 | 2165 | |
| r31142 | r31143 | |
| 1764 | 2168 | state for each DMA channel |
| 1765 | 2169 | -------------------------------------------------*/ |
| 1766 | 2170 | |
| 1767 | | static void ppc4xx_dma_update_irq_states(powerpc_state *ppc) |
| 2171 | void ppc_device::ppc4xx_dma_update_irq_states() |
| 1768 | 2172 | { |
| 1769 | 2173 | /* update the IRQ state for each DMA channel */ |
| 1770 | 2174 | for (int dmachan = 0; dmachan < 4; dmachan++) |
| r31142 | r31143 | |
| 1772 | 2176 | bool irq_pending = false; |
| 1773 | 2177 | |
| 1774 | 2178 | // Channel interrupt enabled? |
| 1775 | | if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE)) |
| 2179 | if ((m_dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE)) |
| 1776 | 2180 | { |
| 1777 | 2181 | // Terminal count and end-of-transfer status bits |
| 1778 | 2182 | int bitmask = 0x11 << (27 - dmachan); |
| r31142 | r31143 | |
| 1791 | 2195 | break; |
| 1792 | 2196 | } |
| 1793 | 2197 | |
| 1794 | | irq_pending = (ppc->dcr[DCR4XX_DMASR] & bitmask) != 0; |
| 2198 | irq_pending = (m_dcr[DCR4XX_DMASR] & bitmask) != 0; |
| 1795 | 2199 | } |
| 1796 | 2200 | |
| 1797 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), irq_pending ? ASSERT_LINE : CLEAR_LINE); |
| 2201 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_DMA(dmachan), irq_pending ? ASSERT_LINE : CLEAR_LINE); |
| 1798 | 2202 | } |
| 1799 | 2203 | } |
| 1800 | 2204 | |
| r31142 | r31143 | |
| 1805 | 2209 | to do so |
| 1806 | 2210 | -------------------------------------------------*/ |
| 1807 | 2211 | |
| 1808 | | static int ppc4xx_dma_decrement_count(powerpc_state *ppc, int dmachan) |
| 2212 | int ppc_device::ppc4xx_dma_decrement_count(int dmachan) |
| 1809 | 2213 | { |
| 1810 | | UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; |
| 2214 | UINT32 *dmaregs = &m_dcr[8 * dmachan]; |
| 1811 | 2215 | |
| 1812 | 2216 | /* decrement the counter */ |
| 1813 | 2217 | dmaregs[DCR4XX_DMACT0]--; |
| r31142 | r31143 | |
| 1826 | 2230 | switch (dmachan) |
| 1827 | 2231 | { |
| 1828 | 2232 | case 0: |
| 1829 | | ppc->dcr[DCR4XX_DMASR] |= 0x00080000; |
| 2233 | m_dcr[DCR4XX_DMASR] |= 0x00080000; |
| 1830 | 2234 | break; |
| 1831 | 2235 | |
| 1832 | 2236 | case 1: |
| 1833 | 2237 | case 2: |
| 1834 | 2238 | case 3: |
| 1835 | | ppc->dcr[DCR4XX_DMASR] |= 1 << (7 - dmachan); |
| 2239 | m_dcr[DCR4XX_DMASR] |= 1 << (7 - dmachan); |
| 1836 | 2240 | break; |
| 1837 | 2241 | } |
| 1838 | 2242 | |
| 1839 | | ppc4xx_dma_update_irq_states(ppc); |
| 2243 | ppc4xx_dma_update_irq_states(); |
| 1840 | 2244 | |
| 1841 | 2245 | INT64 numdata = dmaregs[DCR4XX_DMACT0]; |
| 1842 | 2246 | if (numdata == 0) |
| 1843 | 2247 | numdata = 65536; |
| 1844 | 2248 | |
| 1845 | | INT64 time = (numdata * 1000000) / ppc->buffered_dma_rate[dmachan]; |
| 2249 | INT64 time = (numdata * 1000000) / m_buffered_dma_rate[dmachan]; |
| 1846 | 2250 | |
| 1847 | | ppc->buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); |
| 2251 | m_buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); |
| 1848 | 2252 | } |
| 1849 | 2253 | else |
| 1850 | 2254 | { |
| 1851 | 2255 | /* set the complete bit and handle interrupts */ |
| 1852 | | ppc->dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan); |
| 1853 | | // ppc->dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan); |
| 1854 | | ppc4xx_dma_update_irq_states(ppc); |
| 2256 | m_dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan); |
| 2257 | // m_dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan); |
| 2258 | ppc4xx_dma_update_irq_states(); |
| 1855 | 2259 | |
| 1856 | | ppc->buffered_dma_timer[dmachan]->adjust(attotime::never, FALSE); |
| 2260 | m_buffered_dma_timer[dmachan]->adjust(attotime::never, FALSE); |
| 1857 | 2261 | } |
| 1858 | 2262 | return TRUE; |
| 1859 | 2263 | } |
| r31142 | r31143 | |
| 1864 | 2268 | when buffered DMA transfer is ready |
| 1865 | 2269 | -------------------------------------------------*/ |
| 1866 | 2270 | |
| 1867 | | static TIMER_CALLBACK( ppc4xx_buffered_dma_callback ) |
| 2271 | TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) |
| 1868 | 2272 | { |
| 1869 | | powerpc_state *ppc = (powerpc_state *)ptr; |
| 1870 | 2273 | int dmachan = param; |
| 1871 | 2274 | |
| 1872 | 2275 | static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 }; |
| 1873 | | UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; |
| 2276 | UINT32 *dmaregs = &m_dcr[8 * dmachan]; |
| 1874 | 2277 | INT32 destinc; |
| 1875 | 2278 | UINT8 width; |
| 1876 | 2279 | |
| r31142 | r31143 | |
| 1888 | 2291 | do |
| 1889 | 2292 | { |
| 1890 | 2293 | UINT8 data = 0; |
| 1891 | | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
| 1892 | | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 1); |
| 1893 | | ppc->program->write_byte(dmaregs[DCR4XX_DMADA0], data); |
| 2294 | if (m_ext_dma_read_handler[dmachan] != NULL) |
| 2295 | data = (*m_ext_dma_read_handler[dmachan])(this, 1); |
| 2296 | m_program->write_byte(dmaregs[DCR4XX_DMADA0], data); |
| 1894 | 2297 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1895 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2298 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 1896 | 2299 | break; |
| 1897 | 2300 | |
| 1898 | 2301 | /* word transfer */ |
| r31142 | r31143 | |
| 1900 | 2303 | do |
| 1901 | 2304 | { |
| 1902 | 2305 | UINT16 data = 0; |
| 1903 | | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
| 1904 | | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 2); |
| 1905 | | ppc->program->write_word(dmaregs[DCR4XX_DMADA0], data); |
| 2306 | if (m_ext_dma_read_handler[dmachan] != NULL) |
| 2307 | data = (*m_ext_dma_read_handler[dmachan])(this, 2); |
| 2308 | m_program->write_word(dmaregs[DCR4XX_DMADA0], data); |
| 1906 | 2309 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1907 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2310 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 1908 | 2311 | break; |
| 1909 | 2312 | |
| 1910 | 2313 | /* dword transfer */ |
| r31142 | r31143 | |
| 1912 | 2315 | do |
| 1913 | 2316 | { |
| 1914 | 2317 | UINT32 data = 0; |
| 1915 | | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
| 1916 | | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 4); |
| 1917 | | ppc->program->write_dword(dmaregs[DCR4XX_DMADA0], data); |
| 2318 | if (m_ext_dma_read_handler[dmachan] != NULL) |
| 2319 | data = (*m_ext_dma_read_handler[dmachan])(this, 4); |
| 2320 | m_program->write_dword(dmaregs[DCR4XX_DMADA0], data); |
| 1918 | 2321 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1919 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2322 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 1920 | 2323 | break; |
| 1921 | 2324 | } |
| 1922 | 2325 | } |
| r31142 | r31143 | |
| 1931 | 2334 | case 1: |
| 1932 | 2335 | do |
| 1933 | 2336 | { |
| 1934 | | UINT8 data = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]); |
| 1935 | | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
| 1936 | | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 1, data); |
| 2337 | UINT8 data = m_program->read_byte(dmaregs[DCR4XX_DMADA0]); |
| 2338 | if (m_ext_dma_write_handler[dmachan] != NULL) |
| 2339 | (*m_ext_dma_write_handler[dmachan])(this, 1, data); |
| 1937 | 2340 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1938 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2341 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 1939 | 2342 | break; |
| 1940 | 2343 | |
| 1941 | 2344 | /* word transfer */ |
| 1942 | 2345 | case 2: |
| 1943 | 2346 | do |
| 1944 | 2347 | { |
| 1945 | | UINT16 data = ppc->program->read_word(dmaregs[DCR4XX_DMADA0]); |
| 1946 | | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
| 1947 | | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 2, data); |
| 2348 | UINT16 data = m_program->read_word(dmaregs[DCR4XX_DMADA0]); |
| 2349 | if (m_ext_dma_write_handler[dmachan] != NULL) |
| 2350 | (*m_ext_dma_write_handler[dmachan])(this, 2, data); |
| 1948 | 2351 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1949 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2352 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 1950 | 2353 | break; |
| 1951 | 2354 | |
| 1952 | 2355 | /* dword transfer */ |
| 1953 | 2356 | case 4: |
| 1954 | 2357 | do |
| 1955 | 2358 | { |
| 1956 | | UINT32 data = ppc->program->read_dword(dmaregs[DCR4XX_DMADA0]); |
| 1957 | | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
| 1958 | | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 4, data); |
| 2359 | UINT32 data = m_program->read_dword(dmaregs[DCR4XX_DMADA0]); |
| 2360 | if (m_ext_dma_write_handler[dmachan] != NULL) |
| 2361 | (*m_ext_dma_write_handler[dmachan])(this, 4, data); |
| 1959 | 2362 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1960 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2363 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 1961 | 2364 | break; |
| 1962 | 2365 | } |
| 1963 | 2366 | } |
| r31142 | r31143 | |
| 1969 | 2372 | to send to a peripheral |
| 1970 | 2373 | -------------------------------------------------*/ |
| 1971 | 2374 | |
| 1972 | | static int ppc4xx_dma_fetch_transmit_byte(powerpc_state *ppc, int dmachan, UINT8 *byte) |
| 2375 | int ppc_device::ppc4xx_dma_fetch_transmit_byte(int dmachan, UINT8 *byte) |
| 1973 | 2376 | { |
| 1974 | | UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; |
| 2377 | UINT32 *dmaregs = &m_dcr[8 * dmachan]; |
| 1975 | 2378 | |
| 1976 | 2379 | /* if the channel is not enabled, fail */ |
| 1977 | 2380 | if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) |
| r31142 | r31143 | |
| 1982 | 2385 | return FALSE; |
| 1983 | 2386 | |
| 1984 | 2387 | /* fetch the data */ |
| 1985 | | *byte = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]++); |
| 1986 | | ppc4xx_dma_decrement_count(ppc, dmachan); |
| 2388 | *byte = m_program->read_byte(dmaregs[DCR4XX_DMADA0]++); |
| 2389 | ppc4xx_dma_decrement_count(dmachan); |
| 1987 | 2390 | return TRUE; |
| 1988 | 2391 | } |
| 1989 | 2392 | |
| r31142 | r31143 | |
| 1993 | 2396 | transmitted by a peripheral |
| 1994 | 2397 | -------------------------------------------------*/ |
| 1995 | 2398 | |
| 1996 | | static int ppc4xx_dma_handle_receive_byte(powerpc_state *ppc, int dmachan, UINT8 byte) |
| 2399 | int ppc_device::ppc4xx_dma_handle_receive_byte(int dmachan, UINT8 byte) |
| 1997 | 2400 | { |
| 1998 | | UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; |
| 2401 | UINT32 *dmaregs = &m_dcr[8 * dmachan]; |
| 1999 | 2402 | |
| 2000 | 2403 | /* if the channel is not enabled, fail */ |
| 2001 | 2404 | if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) |
| r31142 | r31143 | |
| 2006 | 2409 | return FALSE; |
| 2007 | 2410 | |
| 2008 | 2411 | /* store the data */ |
| 2009 | | ppc->program->write_byte(dmaregs[DCR4XX_DMADA0]++, byte); |
| 2010 | | ppc4xx_dma_decrement_count(ppc, dmachan); |
| 2412 | m_program->write_byte(dmaregs[DCR4XX_DMADA0]++, byte); |
| 2413 | ppc4xx_dma_decrement_count(dmachan); |
| 2011 | 2414 | return TRUE; |
| 2012 | 2415 | } |
| 2013 | 2416 | |
| r31142 | r31143 | |
| 2017 | 2420 | if one is pending |
| 2018 | 2421 | -------------------------------------------------*/ |
| 2019 | 2422 | |
| 2020 | | static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan) |
| 2423 | void ppc_device::ppc4xx_dma_exec(int dmachan) |
| 2021 | 2424 | { |
| 2022 | 2425 | static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 }; |
| 2023 | | UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; |
| 2426 | UINT32 *dmaregs = &m_dcr[8 * dmachan]; |
| 2024 | 2427 | INT32 destinc, srcinc; |
| 2025 | 2428 | UINT8 width; |
| 2026 | 2429 | |
| r31142 | r31143 | |
| 2048 | 2451 | INT64 time; |
| 2049 | 2452 | if (numdata > 100) |
| 2050 | 2453 | { |
| 2051 | | time = (numdata * 1000000) / ppc->buffered_dma_rate[dmachan]; |
| 2454 | time = (numdata * 1000000) / m_buffered_dma_rate[dmachan]; |
| 2052 | 2455 | } |
| 2053 | 2456 | else |
| 2054 | 2457 | { |
| 2055 | 2458 | time = 0; // let very short transfers occur instantly |
| 2056 | 2459 | } |
| 2057 | 2460 | |
| 2058 | | ppc->buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); |
| 2461 | m_buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); |
| 2059 | 2462 | } |
| 2060 | 2463 | else /* buffered DMA with internal peripheral (SPU) */ |
| 2061 | 2464 | { |
| r31142 | r31143 | |
| 2080 | 2483 | case 1: |
| 2081 | 2484 | do |
| 2082 | 2485 | { |
| 2083 | | ppc->program->write_byte(dmaregs[DCR4XX_DMADA0], ppc->program->read_byte(dmaregs[DCR4XX_DMASA0])); |
| 2486 | m_program->write_byte(dmaregs[DCR4XX_DMADA0], m_program->read_byte(dmaregs[DCR4XX_DMASA0])); |
| 2084 | 2487 | dmaregs[DCR4XX_DMASA0] += srcinc; |
| 2085 | 2488 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 2086 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2489 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 2087 | 2490 | break; |
| 2088 | 2491 | |
| 2089 | 2492 | /* word transfer */ |
| 2090 | 2493 | case 2: |
| 2091 | 2494 | do |
| 2092 | 2495 | { |
| 2093 | | ppc->program->write_word(dmaregs[DCR4XX_DMADA0], ppc->program->read_word(dmaregs[DCR4XX_DMASA0])); |
| 2496 | m_program->write_word(dmaregs[DCR4XX_DMADA0], m_program->read_word(dmaregs[DCR4XX_DMASA0])); |
| 2094 | 2497 | dmaregs[DCR4XX_DMASA0] += srcinc; |
| 2095 | 2498 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 2096 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2499 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 2097 | 2500 | break; |
| 2098 | 2501 | |
| 2099 | 2502 | /* dword transfer */ |
| 2100 | 2503 | case 4: |
| 2101 | 2504 | do |
| 2102 | 2505 | { |
| 2103 | | ppc->program->write_dword(dmaregs[DCR4XX_DMADA0], ppc->program->read_dword(dmaregs[DCR4XX_DMASA0])); |
| 2506 | m_program->write_dword(dmaregs[DCR4XX_DMADA0], m_program->read_dword(dmaregs[DCR4XX_DMASA0])); |
| 2104 | 2507 | dmaregs[DCR4XX_DMASA0] += srcinc; |
| 2105 | 2508 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 2106 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2509 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 2107 | 2510 | break; |
| 2108 | 2511 | |
| 2109 | 2512 | /* 16-byte transfer */ |
| 2110 | 2513 | case 16: |
| 2111 | 2514 | do |
| 2112 | 2515 | { |
| 2113 | | ppc->program->write_qword(dmaregs[DCR4XX_DMADA0], ppc->program->read_qword(dmaregs[DCR4XX_DMASA0])); |
| 2114 | | ppc->program->write_qword(dmaregs[DCR4XX_DMADA0] + 8, ppc->program->read_qword(dmaregs[DCR4XX_DMASA0] + 8)); |
| 2516 | m_program->write_qword(dmaregs[DCR4XX_DMADA0], m_program->read_qword(dmaregs[DCR4XX_DMASA0])); |
| 2517 | m_program->write_qword(dmaregs[DCR4XX_DMADA0] + 8, m_program->read_qword(dmaregs[DCR4XX_DMASA0] + 8)); |
| 2115 | 2518 | dmaregs[DCR4XX_DMASA0] += srcinc; |
| 2116 | 2519 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 2117 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 2520 | } while (!ppc4xx_dma_decrement_count(dmachan)); |
| 2118 | 2521 | break; |
| 2119 | 2522 | } |
| 2120 | 2523 | break; |
| r31142 | r31143 | |
| 2131 | 2534 | ppc4xx_fit_callback - FIT timer callback |
| 2132 | 2535 | -------------------------------------------------*/ |
| 2133 | 2536 | |
| 2134 | | static TIMER_CALLBACK( ppc4xx_fit_callback ) |
| 2537 | TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_fit_callback ) |
| 2135 | 2538 | { |
| 2136 | | powerpc_state *ppc = (powerpc_state *)ptr; |
| 2137 | | |
| 2138 | 2539 | /* if this is a real callback and we are enabled, signal an interrupt */ |
| 2139 | 2540 | if (param) |
| 2140 | 2541 | { |
| 2141 | | ppc->spr[SPR4XX_TSR] |= PPC4XX_TSR_FIS; |
| 2142 | | ppc4xx_set_irq_line(ppc, 0, 0); |
| 2542 | m_core->spr[SPR4XX_TSR] |= PPC4XX_TSR_FIS; |
| 2543 | ppc4xx_set_irq_line(0, 0); |
| 2143 | 2544 | } |
| 2144 | 2545 | |
| 2145 | 2546 | /* update ourself for the next interval if we are enabled */ |
| 2146 | | if (ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) |
| 2547 | if (m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) |
| 2147 | 2548 | { |
| 2148 | | UINT32 timebase = get_timebase(ppc); |
| 2149 | | UINT32 interval = 0x200 << (4 * ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_FP_MASK) >> 24)); |
| 2549 | UINT32 timebase = get_timebase(); |
| 2550 | UINT32 interval = 0x200 << (4 * ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_FP_MASK) >> 24)); |
| 2150 | 2551 | UINT32 target = (timebase + interval) & ~(interval - 1); |
| 2151 | | ppc->fit_timer->adjust(ppc->device->cycles_to_attotime((target + 1 - timebase) / ppc->tb_divisor), TRUE); |
| 2552 | m_fit_timer->adjust(cycles_to_attotime((target + 1 - timebase) / m_tb_divisor), TRUE); |
| 2152 | 2553 | } |
| 2153 | 2554 | |
| 2154 | 2555 | /* otherwise, turn ourself off */ |
| 2155 | 2556 | else |
| 2156 | | ppc->fit_timer->adjust(attotime::never, FALSE); |
| 2557 | m_fit_timer->adjust(attotime::never, FALSE); |
| 2157 | 2558 | } |
| 2158 | 2559 | |
| 2159 | 2560 | |
| r31142 | r31143 | |
| 2161 | 2562 | ppc4xx_pit_callback - PIT timer callback |
| 2162 | 2563 | -------------------------------------------------*/ |
| 2163 | 2564 | |
| 2164 | | static TIMER_CALLBACK( ppc4xx_pit_callback ) |
| 2565 | TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_pit_callback ) |
| 2165 | 2566 | { |
| 2166 | | powerpc_state *ppc = (powerpc_state *)ptr; |
| 2167 | | |
| 2168 | 2567 | /* if this is a real callback and we are enabled, signal an interrupt */ |
| 2169 | 2568 | if (param) |
| 2170 | 2569 | { |
| 2171 | | ppc->spr[SPR4XX_TSR] |= PPC4XX_TSR_PIS; |
| 2172 | | ppc4xx_set_irq_line(ppc, 0, 0); |
| 2570 | m_core->spr[SPR4XX_TSR] |= PPC4XX_TSR_PIS; |
| 2571 | ppc4xx_set_irq_line(0, 0); |
| 2173 | 2572 | } |
| 2174 | 2573 | |
| 2175 | 2574 | /* update ourself for the next interval if we are enabled and we are either being |
| 2176 | 2575 | forced to update, or we are in auto-reload mode */ |
| 2177 | | if ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && ppc->pit_reload != 0 && (!param || (ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_ARE))) |
| 2576 | if ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && m_pit_reload != 0 && (!param || (m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_ARE))) |
| 2178 | 2577 | { |
| 2179 | | UINT32 timebase = get_timebase(ppc); |
| 2180 | | UINT32 interval = ppc->pit_reload; |
| 2578 | UINT32 timebase = get_timebase(); |
| 2579 | UINT32 interval = m_pit_reload; |
| 2181 | 2580 | UINT32 target = timebase + interval; |
| 2182 | | ppc->pit_timer->adjust(ppc->device->cycles_to_attotime((target + 1 - timebase) / ppc->tb_divisor), TRUE); |
| 2581 | m_pit_timer->adjust(cycles_to_attotime((target + 1 - timebase) / m_tb_divisor), TRUE); |
| 2183 | 2582 | } |
| 2184 | 2583 | |
| 2185 | 2584 | /* otherwise, turn ourself off */ |
| 2186 | 2585 | else |
| 2187 | | ppc->pit_timer->adjust(attotime::never, FALSE); |
| 2586 | m_pit_timer->adjust(attotime::never, FALSE); |
| 2188 | 2587 | } |
| 2189 | 2588 | |
| 2190 | 2589 | |
| r31142 | r31143 | |
| 2193 | 2592 | state for the SPU |
| 2194 | 2593 | -------------------------------------------------*/ |
| 2195 | 2594 | |
| 2196 | | static void ppc4xx_spu_update_irq_states(powerpc_state *ppc) |
| 2595 | void ppc_device::ppc4xx_spu_update_irq_states() |
| 2197 | 2596 | { |
| 2198 | 2597 | /* check for receive buffer full interrupt */ |
| 2199 | | if ((ppc->spu.regs[SPU4XX_RX_COMMAND] & 0x60) == 0x20 && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x80)) |
| 2200 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); |
| 2598 | if ((m_spu.regs[SPU4XX_RX_COMMAND] & 0x60) == 0x20 && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x80)) |
| 2599 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); |
| 2201 | 2600 | |
| 2202 | 2601 | /* check for receive error interrupt */ |
| 2203 | | else if ((ppc->spu.regs[SPU4XX_RX_COMMAND] & 0x10) && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x78)) |
| 2204 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); |
| 2602 | else if ((m_spu.regs[SPU4XX_RX_COMMAND] & 0x10) && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x78)) |
| 2603 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); |
| 2205 | 2604 | |
| 2206 | 2605 | /* clear otherwise */ |
| 2207 | 2606 | else |
| 2208 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUR, CLEAR_LINE); |
| 2607 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUR, CLEAR_LINE); |
| 2209 | 2608 | |
| 2210 | 2609 | /* check for transmit buffer empty interrupt */ |
| 2211 | | if ((ppc->spu.regs[SPU4XX_TX_COMMAND] & 0x60) == 0x20 && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x04)) |
| 2212 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); |
| 2610 | if ((m_spu.regs[SPU4XX_TX_COMMAND] & 0x60) == 0x20 && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x04)) |
| 2611 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); |
| 2213 | 2612 | |
| 2214 | 2613 | /* check for shift register empty interrupt */ |
| 2215 | | else if ((ppc->spu.regs[SPU4XX_TX_COMMAND] & 0x10) && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x02)) |
| 2216 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); |
| 2614 | else if ((m_spu.regs[SPU4XX_TX_COMMAND] & 0x10) && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x02)) |
| 2615 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); |
| 2217 | 2616 | |
| 2218 | 2617 | /* clear otherwise */ |
| 2219 | 2618 | else |
| 2220 | | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUT, CLEAR_LINE); |
| 2619 | ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUT, CLEAR_LINE); |
| 2221 | 2620 | } |
| 2222 | 2621 | |
| 2223 | 2622 | |
| r31142 | r31143 | |
| 2225 | 2624 | ppc4xx_spu_rx_data - serial port data receive |
| 2226 | 2625 | -------------------------------------------------*/ |
| 2227 | 2626 | |
| 2228 | | static void ppc4xx_spu_rx_data(powerpc_state *ppc, UINT8 data) |
| 2627 | void ppc_device::ppc4xx_spu_rx_data(UINT8 data) |
| 2229 | 2628 | { |
| 2230 | 2629 | UINT32 new_rxin; |
| 2231 | 2630 | |
| 2232 | 2631 | /* fail if we are going to overflow */ |
| 2233 | | new_rxin = (ppc->spu.rxin + 1) % ARRAY_LENGTH(ppc->spu.rxbuffer); |
| 2234 | | if (new_rxin == ppc->spu.rxout) |
| 2632 | new_rxin = (m_spu.rxin + 1) % ARRAY_LENGTH(m_spu.rxbuffer); |
| 2633 | if (new_rxin == m_spu.rxout) |
| 2235 | 2634 | fatalerror("ppc4xx_spu_rx_data: buffer overrun!\n"); |
| 2236 | 2635 | |
| 2237 | 2636 | /* store the data and accept the new in index */ |
| 2238 | | ppc->spu.rxbuffer[ppc->spu.rxin] = data; |
| 2239 | | ppc->spu.rxin = new_rxin; |
| 2637 | m_spu.rxbuffer[m_spu.rxin] = data; |
| 2638 | m_spu.rxin = new_rxin; |
| 2240 | 2639 | } |
| 2241 | 2640 | |
| 2242 | 2641 | |
| r31142 | r31143 | |
| 2245 | 2644 | the transmit/receive timer |
| 2246 | 2645 | -------------------------------------------------*/ |
| 2247 | 2646 | |
| 2248 | | static void ppc4xx_spu_timer_reset(powerpc_state *ppc) |
| 2647 | void ppc_device::ppc4xx_spu_timer_reset() |
| 2249 | 2648 | { |
| 2250 | | UINT8 enabled = (ppc->spu.regs[SPU4XX_RX_COMMAND] | ppc->spu.regs[SPU4XX_TX_COMMAND]) & 0x80; |
| 2649 | UINT8 enabled = (m_spu.regs[SPU4XX_RX_COMMAND] | m_spu.regs[SPU4XX_TX_COMMAND]) & 0x80; |
| 2251 | 2650 | |
| 2252 | 2651 | /* if we're enabled, reset at the current baud rate */ |
| 2253 | 2652 | if (enabled) |
| 2254 | 2653 | { |
| 2255 | | attotime clockperiod = attotime::from_hz((ppc->dcr[DCR4XX_IOCR] & 0x02) ? 3686400 : 33333333); |
| 2256 | | int divisor = ((ppc->spu.regs[SPU4XX_BAUD_DIVISOR_H] * 256 + ppc->spu.regs[SPU4XX_BAUD_DIVISOR_L]) & 0xfff) + 1; |
| 2257 | | int bpc = 7 + ((ppc->spu.regs[SPU4XX_CONTROL] & 8) >> 3) + 1 + (ppc->spu.regs[SPU4XX_CONTROL] & 1); |
| 2654 | attotime clockperiod = attotime::from_hz((m_dcr[DCR4XX_IOCR] & 0x02) ? 3686400 : 33333333); |
| 2655 | int divisor = ((m_spu.regs[SPU4XX_BAUD_DIVISOR_H] * 256 + m_spu.regs[SPU4XX_BAUD_DIVISOR_L]) & 0xfff) + 1; |
| 2656 | int bpc = 7 + ((m_spu.regs[SPU4XX_CONTROL] & 8) >> 3) + 1 + (m_spu.regs[SPU4XX_CONTROL] & 1); |
| 2258 | 2657 | attotime charperiod = clockperiod * (divisor * 16 * bpc); |
| 2259 | | ppc->spu.timer->adjust(charperiod, 0, charperiod); |
| 2658 | m_spu.timer->adjust(charperiod, 0, charperiod); |
| 2260 | 2659 | if (PRINTF_SPU) |
| 2261 | 2660 | printf("ppc4xx_spu_timer_reset: baud rate = %.0f\n", ATTOSECONDS_TO_HZ(charperiod.attoseconds) * bpc); |
| 2262 | 2661 | } |
| 2263 | 2662 | |
| 2264 | 2663 | /* otherwise, disable the timer */ |
| 2265 | 2664 | else |
| 2266 | | ppc->spu.timer->adjust(attotime::never); |
| 2665 | m_spu.timer->adjust(attotime::never); |
| 2267 | 2666 | } |
| 2268 | 2667 | |
| 2269 | 2668 | |
| r31142 | r31143 | |
| 2272 | 2671 | timer |
| 2273 | 2672 | -------------------------------------------------*/ |
| 2274 | 2673 | |
| 2275 | | static TIMER_CALLBACK( ppc4xx_spu_callback ) |
| 2674 | TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_spu_callback ) |
| 2276 | 2675 | { |
| 2277 | | powerpc_state *ppc = (powerpc_state *)ptr; |
| 2278 | | |
| 2279 | 2676 | /* transmit enabled? */ |
| 2280 | | if (ppc->spu.regs[SPU4XX_TX_COMMAND] & 0x80) |
| 2677 | if (m_spu.regs[SPU4XX_TX_COMMAND] & 0x80) |
| 2281 | 2678 | { |
| 2282 | | int operation = (ppc->spu.regs[SPU4XX_TX_COMMAND] >> 5) & 3; |
| 2679 | int operation = (m_spu.regs[SPU4XX_TX_COMMAND] >> 5) & 3; |
| 2283 | 2680 | |
| 2284 | 2681 | /* if we have data to transmit, do it now */ |
| 2285 | | if (!(ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x04)) |
| 2682 | if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x04)) |
| 2286 | 2683 | { |
| 2287 | 2684 | /* if we have a transmit handler, send it that way */ |
| 2288 | | if (ppc->spu.tx_handler != NULL) |
| 2289 | | (*ppc->spu.tx_handler)(ppc->device, ppc->spu.txbuf); |
| 2685 | if (m_spu.tx_handler != NULL) |
| 2686 | (*m_spu.tx_handler)(this, m_spu.txbuf); |
| 2290 | 2687 | |
| 2291 | 2688 | /* indicate that we have moved it to the shift register */ |
| 2292 | | ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x04; |
| 2293 | | ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x02; |
| 2689 | m_spu.regs[SPU4XX_LINE_STATUS] |= 0x04; |
| 2690 | m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x02; |
| 2294 | 2691 | } |
| 2295 | 2692 | |
| 2296 | 2693 | /* otherwise, clear the shift register */ |
| 2297 | | else if (!(ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x02)) |
| 2298 | | ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x02; |
| 2694 | else if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x02)) |
| 2695 | m_spu.regs[SPU4XX_LINE_STATUS] |= 0x02; |
| 2299 | 2696 | |
| 2300 | 2697 | /* handle DMA */ |
| 2301 | | if (operation >= 2 && ppc4xx_dma_fetch_transmit_byte(ppc, operation, &ppc->spu.txbuf)) |
| 2302 | | ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; |
| 2698 | if (operation >= 2 && ppc4xx_dma_fetch_transmit_byte(operation, &m_spu.txbuf)) |
| 2699 | m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; |
| 2303 | 2700 | } |
| 2304 | 2701 | |
| 2305 | 2702 | /* receive enabled? */ |
| 2306 | | if (ppc->spu.regs[SPU4XX_RX_COMMAND] & 0x80) |
| 2307 | | if (ppc->spu.rxout != ppc->spu.rxin) |
| 2703 | if (m_spu.regs[SPU4XX_RX_COMMAND] & 0x80) |
| 2704 | if (m_spu.rxout != m_spu.rxin) |
| 2308 | 2705 | { |
| 2309 | | int operation = (ppc->spu.regs[SPU4XX_RX_COMMAND] >> 5) & 3; |
| 2706 | int operation = (m_spu.regs[SPU4XX_RX_COMMAND] >> 5) & 3; |
| 2310 | 2707 | UINT8 rxbyte; |
| 2311 | 2708 | |
| 2312 | 2709 | /* consume the byte and advance the out pointer */ |
| 2313 | | rxbyte = ppc->spu.rxbuffer[ppc->spu.rxout]; |
| 2314 | | ppc->spu.rxout = (ppc->spu.rxout + 1) % ARRAY_LENGTH(ppc->spu.rxbuffer); |
| 2710 | rxbyte = m_spu.rxbuffer[m_spu.rxout]; |
| 2711 | m_spu.rxout = (m_spu.rxout + 1) % ARRAY_LENGTH(m_spu.rxbuffer); |
| 2315 | 2712 | |
| 2316 | 2713 | /* if we're not full, copy data to the buffer and update the line status */ |
| 2317 | | if (!(ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x80)) |
| 2714 | if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x80)) |
| 2318 | 2715 | { |
| 2319 | | ppc->spu.rxbuf = rxbyte; |
| 2320 | | ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x80; |
| 2716 | m_spu.rxbuf = rxbyte; |
| 2717 | m_spu.regs[SPU4XX_LINE_STATUS] |= 0x80; |
| 2321 | 2718 | } |
| 2322 | 2719 | |
| 2323 | 2720 | /* otherwise signal an overrun */ |
| 2324 | 2721 | else |
| 2325 | 2722 | { |
| 2326 | | ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x20; |
| 2723 | m_spu.regs[SPU4XX_LINE_STATUS] |= 0x20; |
| 2327 | 2724 | goto updateirq; |
| 2328 | 2725 | } |
| 2329 | 2726 | |
| 2330 | 2727 | /* handle DMA */ |
| 2331 | | if (operation >= 2 && ppc4xx_dma_handle_receive_byte(ppc, operation, ppc->spu.rxbuf)) |
| 2332 | | ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; |
| 2728 | if (operation >= 2 && ppc4xx_dma_handle_receive_byte(operation, m_spu.rxbuf)) |
| 2729 | m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; |
| 2333 | 2730 | } |
| 2334 | 2731 | |
| 2335 | 2732 | /* update the final IRQ states */ |
| 2336 | 2733 | updateirq: |
| 2337 | | ppc4xx_spu_update_irq_states(ppc); |
| 2734 | ppc4xx_spu_update_irq_states(); |
| 2338 | 2735 | } |
| 2339 | 2736 | |
| 2340 | 2737 | |
| r31142 | r31143 | |
| 2344 | 2741 | |
| 2345 | 2742 | READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) |
| 2346 | 2743 | { |
| 2347 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(this)->token(); |
| 2348 | 2744 | UINT8 result = 0xff; |
| 2349 | 2745 | |
| 2350 | 2746 | switch (offset) |
| 2351 | 2747 | { |
| 2352 | 2748 | case SPU4XX_BUFFER: |
| 2353 | | result = ppc->spu.rxbuf; |
| 2354 | | ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; |
| 2749 | result = m_spu.rxbuf; |
| 2750 | m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; |
| 2355 | 2751 | break; |
| 2356 | 2752 | |
| 2357 | 2753 | default: |
| 2358 | | if (offset < ARRAY_LENGTH(ppc->spu.regs)) |
| 2359 | | result = ppc->spu.regs[offset]; |
| 2754 | if (offset < ARRAY_LENGTH(m_spu.regs)) |
| 2755 | result = m_spu.regs[offset]; |
| 2360 | 2756 | break; |
| 2361 | 2757 | } |
| 2362 | 2758 | if (PRINTF_SPU) |
| r31142 | r31143 | |
| 2371 | 2767 | |
| 2372 | 2768 | WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) |
| 2373 | 2769 | { |
| 2374 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(this)->token(); |
| 2375 | 2770 | UINT8 oldstate, newstate; |
| 2376 | 2771 | |
| 2377 | 2772 | if (PRINTF_SPU) |
| r31142 | r31143 | |
| 2380 | 2775 | { |
| 2381 | 2776 | /* clear error bits */ |
| 2382 | 2777 | case SPU4XX_LINE_STATUS: |
| 2383 | | ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~(data & 0xf8); |
| 2384 | | ppc4xx_spu_update_irq_states(ppc); |
| 2778 | m_spu.regs[SPU4XX_LINE_STATUS] &= ~(data & 0xf8); |
| 2779 | ppc4xx_spu_update_irq_states(); |
| 2385 | 2780 | break; |
| 2386 | 2781 | |
| 2387 | 2782 | /* enable/disable the timer if one of these is enabled */ |
| 2388 | 2783 | case SPU4XX_RX_COMMAND: |
| 2389 | 2784 | case SPU4XX_TX_COMMAND: |
| 2390 | | oldstate = ppc->spu.regs[SPU4XX_RX_COMMAND] | ppc->spu.regs[SPU4XX_TX_COMMAND]; |
| 2391 | | ppc->spu.regs[offset] = data; |
| 2392 | | newstate = ppc->spu.regs[SPU4XX_RX_COMMAND] | ppc->spu.regs[SPU4XX_TX_COMMAND]; |
| 2785 | oldstate = m_spu.regs[SPU4XX_RX_COMMAND] | m_spu.regs[SPU4XX_TX_COMMAND]; |
| 2786 | m_spu.regs[offset] = data; |
| 2787 | newstate = m_spu.regs[SPU4XX_RX_COMMAND] | m_spu.regs[SPU4XX_TX_COMMAND]; |
| 2393 | 2788 | if ((oldstate ^ newstate) & 0x80) |
| 2394 | | ppc4xx_spu_timer_reset(ppc); |
| 2395 | | ppc4xx_spu_update_irq_states(ppc); |
| 2789 | ppc4xx_spu_timer_reset(); |
| 2790 | ppc4xx_spu_update_irq_states(); |
| 2396 | 2791 | break; |
| 2397 | 2792 | |
| 2398 | 2793 | /* if the divisor changes, we need to update the timer */ |
| 2399 | 2794 | case SPU4XX_BAUD_DIVISOR_H: |
| 2400 | 2795 | case SPU4XX_BAUD_DIVISOR_L: |
| 2401 | | if (data != ppc->spu.regs[offset]) |
| 2796 | if (data != m_spu.regs[offset]) |
| 2402 | 2797 | { |
| 2403 | | ppc->spu.regs[offset] = data; |
| 2404 | | ppc4xx_spu_timer_reset(ppc); |
| 2798 | m_spu.regs[offset] = data; |
| 2799 | ppc4xx_spu_timer_reset(); |
| 2405 | 2800 | } |
| 2406 | 2801 | break; |
| 2407 | 2802 | |
| 2408 | 2803 | /* if the number of data bits or stop bits changes, we need to update the timer */ |
| 2409 | 2804 | case SPU4XX_CONTROL: |
| 2410 | | oldstate = ppc->spu.regs[offset]; |
| 2411 | | ppc->spu.regs[offset] = data; |
| 2805 | oldstate = m_spu.regs[offset]; |
| 2806 | m_spu.regs[offset] = data; |
| 2412 | 2807 | if ((oldstate ^ data) & 0x09) |
| 2413 | | ppc4xx_spu_timer_reset(ppc); |
| 2808 | ppc4xx_spu_timer_reset(); |
| 2414 | 2809 | break; |
| 2415 | 2810 | |
| 2416 | 2811 | break; |
| 2417 | 2812 | |
| 2418 | 2813 | case SPU4XX_BUFFER: |
| 2419 | 2814 | /* write to the transmit buffer and mark it full */ |
| 2420 | | ppc->spu.txbuf = data; |
| 2421 | | ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; |
| 2815 | m_spu.txbuf = data; |
| 2816 | m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; |
| 2422 | 2817 | break; |
| 2423 | 2818 | |
| 2424 | 2819 | default: |
| 2425 | | if (offset < ARRAY_LENGTH(ppc->spu.regs)) |
| 2426 | | ppc->spu.regs[offset] = data; |
| 2820 | if (offset < ARRAY_LENGTH(m_spu.regs)) |
| 2821 | m_spu.regs[offset] = data; |
| 2427 | 2822 | break; |
| 2428 | 2823 | } |
| 2429 | 2824 | } |
| r31142 | r31143 | |
| 2431 | 2826 | |
| 2432 | 2827 | |
| 2433 | 2828 | /*------------------------------------------------- |
| 2434 | | internal_ppc4xx - internal address map for |
| 2435 | | the 4XX |
| 2436 | | -------------------------------------------------*/ |
| 2437 | | |
| 2438 | | static ADDRESS_MAP_START( internal_ppc4xx, AS_PROGRAM, 32, ppc4xx_device ) |
| 2439 | | AM_RANGE(0x40000000, 0x4000000f) AM_READWRITE8(ppc4xx_spu_r, ppc4xx_spu_w, 0xffffffff) |
| 2440 | | ADDRESS_MAP_END |
| 2441 | | |
| 2442 | | |
| 2443 | | |
| 2444 | | /*------------------------------------------------- |
| 2445 | 2829 | ppc4xx_spu_set_tx_handler - PowerPC 4XX- |
| 2446 | 2830 | specific TX handler configuration |
| 2447 | 2831 | -------------------------------------------------*/ |
| 2448 | 2832 | |
| 2449 | | void ppc4xx_spu_set_tx_handler(device_t *device, ppc4xx_spu_tx_handler handler) |
| 2833 | void ppc4xx_device::ppc4xx_spu_set_tx_handler(ppc4xx_spu_tx_handler handler) |
| 2450 | 2834 | { |
| 2451 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 2452 | | ppc->spu.tx_handler = handler; |
| 2835 | m_spu.tx_handler = handler; |
| 2453 | 2836 | } |
| 2454 | 2837 | |
| 2455 | 2838 | |
| r31142 | r31143 | |
| 2458 | 2841 | specific serial byte receive |
| 2459 | 2842 | -------------------------------------------------*/ |
| 2460 | 2843 | |
| 2461 | | void ppc4xx_spu_receive_byte(device_t *device, UINT8 byteval) |
| 2844 | void ppc4xx_device::ppc4xx_spu_receive_byte(UINT8 byteval) |
| 2462 | 2845 | { |
| 2463 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 2464 | | ppc4xx_spu_rx_data(ppc, byteval); |
| 2846 | ppc4xx_spu_rx_data(byteval); |
| 2465 | 2847 | } |
| 2466 | 2848 | |
| 2467 | 2849 | /*------------------------------------------------- |
| r31142 | r31143 | |
| 2469 | 2851 | specific external DMA read handler configuration |
| 2470 | 2852 | -------------------------------------------------*/ |
| 2471 | 2853 | |
| 2472 | | void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler, int rate) |
| 2854 | void ppc4xx_device::ppc4xx_set_dma_read_handler(int channel, ppc4xx_dma_read_handler handler, int rate) |
| 2473 | 2855 | { |
| 2474 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 2475 | | ppc->ext_dma_read_handler[channel] = handler; |
| 2476 | | ppc->buffered_dma_rate[channel] = rate; |
| 2856 | m_ext_dma_read_handler[channel] = handler; |
| 2857 | m_buffered_dma_rate[channel] = rate; |
| 2477 | 2858 | } |
| 2478 | 2859 | |
| 2479 | 2860 | /*------------------------------------------------- |
| r31142 | r31143 | |
| 2481 | 2862 | specific external DMA write handler configuration |
| 2482 | 2863 | -------------------------------------------------*/ |
| 2483 | 2864 | |
| 2484 | | void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler, int rate) |
| 2865 | void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, ppc4xx_dma_write_handler handler, int rate) |
| 2485 | 2866 | { |
| 2486 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 2487 | | ppc->ext_dma_write_handler[channel] = handler; |
| 2488 | | ppc->buffered_dma_rate[channel] = rate; |
| 2867 | m_ext_dma_write_handler[channel] = handler; |
| 2868 | m_buffered_dma_rate[channel] = rate; |
| 2489 | 2869 | } |
| 2490 | 2870 | |
| 2491 | 2871 | /*------------------------------------------------- |
| 2492 | 2872 | ppc4xx_set_dcr_read_handler |
| 2493 | 2873 | -------------------------------------------------*/ |
| 2494 | 2874 | |
| 2495 | | void ppc4xx_set_dcr_read_handler(device_t *device, read32_delegate dcr_read_func) |
| 2875 | void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func) |
| 2496 | 2876 | { |
| 2497 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 2498 | | ppc->dcr_read_func = dcr_read_func; |
| 2877 | m_dcr_read_func = dcr_read_func; |
| 2499 | 2878 | |
| 2500 | 2879 | } |
| 2501 | 2880 | |
| r31142 | r31143 | |
| 2503 | 2882 | ppc4xx_set_dcr_write_handler |
| 2504 | 2883 | -------------------------------------------------*/ |
| 2505 | 2884 | |
| 2506 | | void ppc4xx_set_dcr_write_handler(device_t *device, write32_delegate dcr_write_func) |
| 2885 | void ppc4xx_device::ppc4xx_set_dcr_write_handler(write32_delegate dcr_write_func) |
| 2507 | 2886 | { |
| 2508 | | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
| 2509 | | ppc->dcr_write_func = dcr_write_func; |
| 2887 | m_dcr_write_func = dcr_write_func; |
| 2510 | 2888 | } |
| 2511 | 2889 | |
| 2512 | | /*------------------------------------------------- |
| 2513 | | ppc4xx_set_info - PowerPC 4XX-specific |
| 2514 | | information setter |
| 2515 | | -------------------------------------------------*/ |
| 2516 | | |
| 2517 | | void ppc4xx_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) |
| 2518 | | { |
| 2519 | | switch (state) |
| 2520 | | { |
| 2521 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2522 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_0: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT0, info->i); break; |
| 2523 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_1: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT1, info->i); break; |
| 2524 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_2: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT2, info->i); break; |
| 2525 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_3: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT3, info->i); break; |
| 2526 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_4: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT4, info->i); break; |
| 2527 | | |
| 2528 | | /* --- everything else is handled generically --- */ |
| 2529 | | default: ppccom_set_info(ppc, state, info); break; |
| 2530 | | } |
| 2531 | | } |
| 2532 | | |
| 2533 | | |
| 2534 | | /*------------------------------------------------- |
| 2535 | | ppc4xx_get_info - PowerPC 4XX-specific |
| 2536 | | information getter |
| 2537 | | -------------------------------------------------*/ |
| 2538 | | |
| 2539 | | void ppc4xx_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) |
| 2540 | | { |
| 2541 | | switch (state) |
| 2542 | | { |
| 2543 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2544 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2545 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_0: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT0); break; |
| 2546 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_1: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT1); break; |
| 2547 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_2: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT2); break; |
| 2548 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_3: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT3); break; |
| 2549 | | case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_4: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT4); break; |
| 2550 | | |
| 2551 | | case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 32; break; |
| 2552 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 31; break; |
| 2553 | | case CPUINFO_INT_LOGADDR_WIDTH_PROGRAM: info->i = 32; break; |
| 2554 | | case CPUINFO_INT_PAGE_SHIFT_PROGRAM: info->i = POWERPC_MIN_PAGE_SHIFT;break; |
| 2555 | | |
| 2556 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2557 | | case CPUINFO_FCT_INIT: /* provided per-CPU */ break; |
| 2558 | | case CPUINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map32 = ADDRESS_MAP_NAME(internal_ppc4xx); break; |
| 2559 | | |
| 2560 | | /* --- everything else is handled generically --- */ |
| 2561 | | default: ppccom_get_info(ppc, state, info); break; |
| 2562 | | } |
| 2563 | | } |