src/emu/cpu/drcbex64.c
| r2821 | r2822 | |
| 18 | 18 | |
| 19 | 19 | * Identify common pairs and optimize output |
| 20 | 20 | |
| 21 | * Convert AND 0xff/0xffff to movzx |
| 22 | |
| 21 | 23 | **************************************************************************** |
| 22 | 24 | |
| 23 | 25 | ------------------------- |
| r2821 | r2822 | |
| 396 | 398 | static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 397 | 399 | static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 398 | 400 | static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 401 | static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 399 | 402 | static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 400 | 403 | static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 401 | 404 | |
| 402 | | static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 403 | | static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 404 | | static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 405 | | static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 406 | | static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 407 | | static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 408 | | static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 409 | | static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 410 | | static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 411 | | static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 412 | | static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 413 | | static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 414 | | static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 415 | | static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 416 | | static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 417 | | static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 418 | | static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 419 | | static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 420 | | static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 421 | | static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 422 | | static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 423 | | static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 424 | | static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 425 | | static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 426 | | static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 427 | | static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 428 | | static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 429 | | static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 430 | | static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 431 | | static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 405 | static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 406 | static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 407 | static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 408 | static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 409 | static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 410 | static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 411 | static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 412 | static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 413 | static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 432 | 414 | static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 433 | | static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 434 | | static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 435 | | static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 436 | | static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 437 | | static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 438 | | static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 439 | | static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 440 | | static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 415 | static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 416 | static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 417 | static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 441 | 418 | static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 442 | 419 | static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 443 | 420 | static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| r2821 | r2822 | |
| 466 | 443 | static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 467 | 444 | static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 468 | 445 | static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 469 | | static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 470 | | static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 471 | | static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 472 | | static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 473 | | static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 474 | | static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 475 | | static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 476 | | static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 477 | | static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 478 | | static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 479 | | static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 480 | | static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 481 | | static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 482 | | static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 446 | static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 447 | static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 448 | static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 449 | static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 483 | 450 | static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 484 | 451 | static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 485 | 452 | static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| r2821 | r2822 | |
| 514 | 481 | /* Internal Register Operations */ |
| 515 | 482 | { DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */ |
| 516 | 483 | { DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */ |
| 517 | | { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */ |
| 518 | | { DRCUML_OP_SAVE, op_save }, /* SAVE dst,index */ |
| 519 | | { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst,index */ |
| 484 | { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst */ |
| 485 | { DRCUML_OP_GETFLGS, op_getflgs }, /* GETFLGS dst[,f] */ |
| 486 | { DRCUML_OP_SAVE, op_save }, /* SAVE dst */ |
| 487 | { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst */ |
| 520 | 488 | |
| 521 | 489 | /* Integer Operations */ |
| 522 | | { DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */ |
| 523 | | { DRCUML_OP_LOAD1S, op_load1s }, /* LOAD1S dst,base,index */ |
| 524 | | { DRCUML_OP_LOAD2U, op_load2u }, /* LOAD2U dst,base,index */ |
| 525 | | { DRCUML_OP_LOAD2S, op_load2s }, /* LOAD2S dst,base,index */ |
| 526 | | { DRCUML_OP_LOAD4U, op_load4u }, /* LOAD4U dst,base,index */ |
| 527 | | { DRCUML_OP_LOAD4S, op_load4s }, /* LOAD4S dst,base,index */ |
| 528 | | { DRCUML_OP_LOAD8U, op_load8u }, /* LOAD8U dst,base,index */ |
| 529 | | { DRCUML_OP_STORE1, op_store1 }, /* STORE1 base,index,src */ |
| 530 | | { DRCUML_OP_STORE2, op_store2 }, /* STORE2 base,index,src */ |
| 531 | | { DRCUML_OP_STORE4, op_store4 }, /* STORE4 base,index,src */ |
| 532 | | { DRCUML_OP_STORE8, op_store8 }, /* STORE8 base,index,src */ |
| 533 | | { DRCUML_OP_READ1U, op_read1u }, /* READ1U dst,space,src1 */ |
| 534 | | { DRCUML_OP_READ1S, op_read1s }, /* READ1S dst,space,src1 */ |
| 535 | | { DRCUML_OP_READ2U, op_read2u }, /* READ2U dst,space,src1 */ |
| 536 | | { DRCUML_OP_READ2S, op_read2s }, /* READ2S dst,space,src1 */ |
| 537 | | { DRCUML_OP_READ2M, op_read2m }, /* READ2M dst,space,src1,mask */ |
| 538 | | { DRCUML_OP_READ4U, op_read4u }, /* READ4U dst,space,src1 */ |
| 539 | | { DRCUML_OP_READ4S, op_read4s }, /* READ4S dst,space,src1 */ |
| 540 | | { DRCUML_OP_READ4M, op_read4m }, /* READ4M dst,space,src1,mask */ |
| 541 | | { DRCUML_OP_READ8U, op_read8u }, /* READ8U dst,space,src1 */ |
| 542 | | { DRCUML_OP_READ8M, op_read8m }, /* READ8M dst,space,src1,mask */ |
| 543 | | { DRCUML_OP_WRITE1, op_write1 }, /* WRITE1 space,dst,src1 */ |
| 544 | | { DRCUML_OP_WRITE2, op_write2 }, /* WRITE2 space,dst,src1 */ |
| 545 | | { DRCUML_OP_WRIT2M, op_writ2m }, /* WRIT2M space,dst,src1 */ |
| 546 | | { DRCUML_OP_WRITE4, op_write4 }, /* WRITE4 space,dst,src1 */ |
| 547 | | { DRCUML_OP_WRIT4M, op_writ4m }, /* WRIT4M space,dst,mask,src1 */ |
| 548 | | { DRCUML_OP_WRITE8, op_write8 }, /* WRITE8 space,dst,src1 */ |
| 549 | | { DRCUML_OP_WRIT8M, op_writ8m }, /* WRIT8M space,dst,mask,src1 */ |
| 550 | | { DRCUML_OP_FLAGS, op_flags }, /* FLAGS dst,mask,table */ |
| 551 | | { DRCUML_OP_SETC, op_setc }, /* FLAGS src,bitnum */ |
| 490 | { DRCUML_OP_LOAD, op_load }, /* LOAD dst,base,index,size */ |
| 491 | { DRCUML_OP_LOADS, op_loads }, /* LOADS dst,base,index,size */ |
| 492 | { DRCUML_OP_STORE, op_store }, /* STORE base,index,src,size */ |
| 493 | { DRCUML_OP_READ, op_read }, /* READ dst,src1,spacesize */ |
| 494 | { DRCUML_OP_READM, op_readm }, /* READM dst,src1,mask,spacesize */ |
| 495 | { DRCUML_OP_WRITE, op_write }, /* WRITE dst,src1,spacesize */ |
| 496 | { DRCUML_OP_WRITEM, op_writem }, /* WRITEM dst,src1,spacesize */ |
| 497 | { DRCUML_OP_CARRY, op_carry }, /* CARRY src,bitnum */ |
| 498 | { DRCUML_OP_SET, op_set }, /* SET dst,c */ |
| 552 | 499 | { DRCUML_OP_MOV, op_mov }, /* MOV dst,src[,c] */ |
| 553 | | { DRCUML_OP_ZEXT1, op_zext1 }, /* ZEXT1 dst,src */ |
| 554 | | { DRCUML_OP_ZEXT2, op_zext2 }, /* ZEXT2 dst,src */ |
| 555 | | { DRCUML_OP_ZEXT4, op_zext4 }, /* ZEXT4 dst,src */ |
| 556 | | { DRCUML_OP_SEXT1, op_sext1 }, /* SEXT1 dst,src */ |
| 557 | | { DRCUML_OP_SEXT2, op_sext2 }, /* SEXT2 dst,src */ |
| 558 | | { DRCUML_OP_SEXT4, op_sext4 }, /* SEXT4 dst,src */ |
| 559 | | { DRCUML_OP_XTRACT, op_xtract }, /* XTRACT dst,src1,src2,src3 */ |
| 560 | | { DRCUML_OP_INSERT, op_insert }, /* INSERT dst,src1,src2,src3 */ |
| 500 | { DRCUML_OP_SEXT, op_sext }, /* SEXT dst,src */ |
| 501 | { DRCUML_OP_ROLAND, op_roland }, /* ROLAND dst,src1,src2,src3 */ |
| 502 | { DRCUML_OP_ROLINS, op_rolins }, /* ROLINS dst,src1,src2,src3 */ |
| 561 | 503 | { DRCUML_OP_ADD, op_add }, /* ADD dst,src1,src2[,f] */ |
| 562 | 504 | { DRCUML_OP_ADDC, op_addc }, /* ADDC dst,src1,src2[,f] */ |
| 563 | 505 | { DRCUML_OP_SUB, op_sub }, /* SUB dst,src1,src2[,f] */ |
| r2821 | r2822 | |
| 587 | 529 | { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,space,src1 */ |
| 588 | 530 | { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE space,dst,src1 */ |
| 589 | 531 | { DRCUML_OP_FMOV, op_fmov }, /* FMOV dst,src1[,c] */ |
| 590 | | { DRCUML_OP_FTOI4, op_ftoi4 }, /* FTOI4 dst,src1 */ |
| 591 | | { DRCUML_OP_FTOI4T, op_ftoi4t }, /* FTOI4T dst,src1 */ |
| 592 | | { DRCUML_OP_FTOI4R, op_ftoi4r }, /* FTOI4R dst,src1 */ |
| 593 | | { DRCUML_OP_FTOI4F, op_ftoi4f }, /* FTOI4F dst,src1 */ |
| 594 | | { DRCUML_OP_FTOI4C, op_ftoi4c }, /* FTOI4C dst,src1 */ |
| 595 | | { DRCUML_OP_FTOI8, op_ftoi8 }, /* FTOI8 dst,src1 */ |
| 596 | | { DRCUML_OP_FTOI8T, op_ftoi8t }, /* FTOI8T dst,src1 */ |
| 597 | | { DRCUML_OP_FTOI8R, op_ftoi8r }, /* FTOI8R dst,src1 */ |
| 598 | | { DRCUML_OP_FTOI8F, op_ftoi8f }, /* FTOI8F dst,src1 */ |
| 599 | | { DRCUML_OP_FTOI8C, op_ftoi8c }, /* FTOI8C dst,src1 */ |
| 600 | | { DRCUML_OP_FFRFS, op_ffrfs }, /* FFRFS dst,src1 */ |
| 601 | | { DRCUML_OP_FFRFD, op_ffrfd }, /* FFRFD dst,src1 */ |
| 602 | | { DRCUML_OP_FFRI4, op_ffri4 }, /* FFRI4 dst,src1 */ |
| 603 | | { DRCUML_OP_FFRI8, op_ffri8 }, /* FFRI8 dst,src1 */ |
| 532 | { DRCUML_OP_FTOINT, op_ftoint }, /* FTOINT dst,src1,size,round */ |
| 533 | { DRCUML_OP_FFRINT, op_ffrint }, /* FFRINT dst,src1,size */ |
| 534 | { DRCUML_OP_FFRFLT, op_ffrflt }, /* FFRFLT dst,src1,size */ |
| 535 | { DRCUML_OP_FRNDS, op_frnds }, /* FRNDS dst,src1 */ |
| 604 | 536 | { DRCUML_OP_FADD, op_fadd }, /* FADD dst,src1,src2 */ |
| 605 | 537 | { DRCUML_OP_FSUB, op_fsub }, /* FSUB dst,src1,src2 */ |
| 606 | 538 | { DRCUML_OP_FCMP, op_fcmp }, /* FCMP src1,src2 */ |
| r2821 | r2822 | |
| 3553 | 3485 | |
| 3554 | 3486 | |
| 3555 | 3487 | /*------------------------------------------------- |
| 3488 | op_getflgs - process a GETFLGS opcode |
| 3489 | -------------------------------------------------*/ |
| 3490 | |
| 3491 | static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3492 | { |
| 3493 | drcuml_parameter dstp; |
| 3494 | int dstreg; |
| 3495 | |
| 3496 | /* validate instruction */ |
| 3497 | assert(inst->size == 4); |
| 3498 | assert(inst->condflags != DRCUML_COND_ALWAYS); |
| 3499 | |
| 3500 | /* normalize parameters */ |
| 3501 | param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); |
| 3502 | |
| 3503 | /* pick a target register for the general case */ |
| 3504 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3505 | |
| 3506 | switch (inst->condflags) |
| 3507 | { |
| 3508 | /* single flags only */ |
| 3509 | case DRCUML_FLAG_C: |
| 3510 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3511 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3512 | break; |
| 3513 | |
| 3514 | case DRCUML_FLAG_V: |
| 3515 | emit_setcc_r8(&dst, COND_O, REG_AL); // seto al |
| 3516 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3517 | emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 |
| 3518 | break; |
| 3519 | |
| 3520 | case DRCUML_FLAG_Z: |
| 3521 | emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al |
| 3522 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3523 | emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 |
| 3524 | break; |
| 3525 | |
| 3526 | case DRCUML_FLAG_S: |
| 3527 | emit_setcc_r8(&dst, COND_S, REG_AL); // sets al |
| 3528 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3529 | emit_shl_r32_imm(&dst, dstreg, 3); // shl dstreg,3 |
| 3530 | break; |
| 3531 | |
| 3532 | case DRCUML_FLAG_U: |
| 3533 | emit_setcc_r8(&dst, COND_P, REG_AL); // setp al |
| 3534 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3535 | emit_shl_r32_imm(&dst, dstreg, 4); // shl dstreg,4 |
| 3536 | break; |
| 3537 | |
| 3538 | /* carry plus another flag */ |
| 3539 | case DRCUML_FLAG_C | DRCUML_FLAG_V: |
| 3540 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3541 | emit_setcc_r8(&dst, COND_O, REG_CL); // seto cl |
| 3542 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3543 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3544 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] |
| 3545 | break; |
| 3546 | |
| 3547 | case DRCUML_FLAG_C | DRCUML_FLAG_Z: |
| 3548 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3549 | emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl |
| 3550 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3551 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3552 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] |
| 3553 | break; |
| 3554 | |
| 3555 | case DRCUML_FLAG_C | DRCUML_FLAG_S: |
| 3556 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3557 | emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl |
| 3558 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3559 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3560 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 8, 0)); // lea dstreg,[eax+ecx*8] |
| 3561 | break; |
| 3562 | |
| 3563 | /* overflow plus another flag */ |
| 3564 | case DRCUML_FLAG_V | DRCUML_FLAG_Z: |
| 3565 | emit_setcc_r8(&dst, COND_O, REG_AL); // seto al |
| 3566 | emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl |
| 3567 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3568 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3569 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] |
| 3570 | emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 |
| 3571 | break; |
| 3572 | |
| 3573 | case DRCUML_FLAG_V | DRCUML_FLAG_S: |
| 3574 | emit_setcc_r8(&dst, COND_O, REG_AL); // seto al |
| 3575 | emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl |
| 3576 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3577 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3578 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] |
| 3579 | emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 |
| 3580 | break; |
| 3581 | |
| 3582 | /* zero plus another flag */ |
| 3583 | case DRCUML_FLAG_Z | DRCUML_FLAG_S: |
| 3584 | emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al |
| 3585 | emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl |
| 3586 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3587 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3588 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] |
| 3589 | emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 |
| 3590 | break; |
| 3591 | |
| 3592 | /* default cases */ |
| 3593 | default: |
| 3594 | emit_pushf(&dst); // pushf |
| 3595 | emit_pop_r64(&dst, REG_EAX); // pop eax |
| 3596 | emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 |
| 3597 | emit_movzx_r32_m8(&dst, dstreg, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsmap[0]))); |
| 3598 | // movzx dstreg,[flags_map] |
| 3599 | break; |
| 3600 | } |
| 3601 | |
| 3602 | /* 32-bit form */ |
| 3603 | if (inst->size == 4) |
| 3604 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3605 | |
| 3606 | /* 64-bit form */ |
| 3607 | else if (inst->size == 8) |
| 3608 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3609 | |
| 3610 | return dst; |
| 3611 | } |
| 3612 | |
| 3613 | |
| 3614 | /*------------------------------------------------- |
| 3556 | 3615 | op_save - process a SAVE opcode |
| 3557 | 3616 | -------------------------------------------------*/ |
| 3558 | 3617 | |
| r2821 | r2822 | |
| 3680 | 3739 | ***************************************************************************/ |
| 3681 | 3740 | |
| 3682 | 3741 | /*------------------------------------------------- |
| 3683 | | op_load1u - process a LOAD1U opcode |
| 3742 | op_load - process a LOAD opcode |
| 3684 | 3743 | -------------------------------------------------*/ |
| 3685 | 3744 | |
| 3686 | | static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3745 | static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3687 | 3746 | { |
| 3688 | | drcuml_parameter dstp, basep, indp; |
| 3747 | drcuml_parameter dstp, basep, indp, sizep; |
| 3689 | 3748 | int basereg, dstreg; |
| 3690 | 3749 | INT32 baseoffs; |
| 3691 | 3750 | |
| r2821 | r2822 | |
| 3694 | 3753 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3695 | 3754 | |
| 3696 | 3755 | /* normalize parameters */ |
| 3697 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3756 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); |
| 3698 | 3757 | |
| 3699 | | /* pick a target register for the general case */ |
| 3700 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3701 | | |
| 3702 | 3758 | /* determine the pointer base */ |
| 3703 | 3759 | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 3704 | 3760 | |
| 3761 | /* pick a target register for the general case */ |
| 3762 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3763 | |
| 3705 | 3764 | /* immediate index */ |
| 3706 | 3765 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3707 | | emit_movzx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp] |
| 3766 | { |
| 3767 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3768 | emit_movzx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp] |
| 3769 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3770 | emit_movzx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movzx dstreg,[basep + 2*indp] |
| 3771 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3772 | emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3773 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3774 | emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp] |
| 3775 | } |
| 3708 | 3776 | |
| 3709 | 3777 | /* other index */ |
| 3710 | 3778 | else |
| 3711 | 3779 | { |
| 3712 | 3780 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3713 | 3781 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3714 | | emit_movzx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movzx dstreg,[basep + 1*indp] |
| 3782 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3783 | emit_movzx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movzx dstreg,[basep + 1*indp] |
| 3784 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3785 | emit_movzx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movzx dstreg,[basep + 2*indp] |
| 3786 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3787 | emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp] |
| 3788 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3789 | emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp] |
| 3715 | 3790 | } |
| 3716 | 3791 | |
| 3717 | | /* store to appropriate target size */ |
| 3792 | /* store result */ |
| 3718 | 3793 | if (inst->size == 4) |
| 3719 | 3794 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3720 | | else if (inst->size == 8) |
| 3795 | else |
| 3721 | 3796 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3722 | 3797 | |
| 3723 | 3798 | return dst; |
| r2821 | r2822 | |
| 3725 | 3800 | |
| 3726 | 3801 | |
| 3727 | 3802 | /*------------------------------------------------- |
| 3728 | | op_load1s - process a LOAD1S opcode |
| 3803 | op_loads - process a LOADS opcode |
| 3729 | 3804 | -------------------------------------------------*/ |
| 3730 | 3805 | |
| 3731 | | static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3806 | static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3732 | 3807 | { |
| 3733 | | drcuml_parameter dstp, basep, indp; |
| 3808 | drcuml_parameter dstp, basep, indp, sizep; |
| 3734 | 3809 | int basereg, dstreg; |
| 3735 | 3810 | INT32 baseoffs; |
| 3736 | 3811 | |
| r2821 | r2822 | |
| 3739 | 3814 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3740 | 3815 | |
| 3741 | 3816 | /* normalize parameters */ |
| 3742 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3817 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); |
| 3743 | 3818 | |
| 3744 | | /* pick a target register for the general case */ |
| 3745 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3746 | | |
| 3747 | 3819 | /* determine the pointer base */ |
| 3748 | 3820 | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 3749 | 3821 | |
| 3750 | | /* 32-bit form */ |
| 3751 | | if (inst->size == 4) |
| 3752 | | { |
| 3753 | | /* immediate index */ |
| 3754 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3755 | | emit_movsx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx eax,[basep + 1*indp] |
| 3756 | | |
| 3757 | | /* other index */ |
| 3758 | | else |
| 3759 | | { |
| 3760 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3761 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3762 | | emit_movsx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx eax,[basep + 1*indp] |
| 3763 | | } |
| 3764 | | |
| 3765 | | /* general case */ |
| 3766 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3767 | | } |
| 3768 | | |
| 3769 | | /* 64-bit form */ |
| 3770 | | else |
| 3771 | | { |
| 3772 | | /* immediate index */ |
| 3773 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3774 | | emit_movsx_r64_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx rax,[basep + 1*indp] |
| 3775 | | |
| 3776 | | /* other index */ |
| 3777 | | else |
| 3778 | | { |
| 3779 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3780 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3781 | | emit_movsx_r64_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx rax,[basep + 1*indp] |
| 3782 | | } |
| 3783 | | |
| 3784 | | /* general case */ |
| 3785 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3786 | | } |
| 3787 | | return dst; |
| 3788 | | } |
| 3789 | | |
| 3790 | | |
| 3791 | | /*------------------------------------------------- |
| 3792 | | op_load2u - process a LOAD2U opcode |
| 3793 | | -------------------------------------------------*/ |
| 3794 | | |
| 3795 | | static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3796 | | { |
| 3797 | | drcuml_parameter dstp, basep, indp; |
| 3798 | | int basereg, dstreg; |
| 3799 | | INT32 baseoffs; |
| 3800 | | |
| 3801 | | /* validate instruction */ |
| 3802 | | assert(inst->size == 4 || inst->size == 8); |
| 3803 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3804 | | |
| 3805 | | /* normalize parameters */ |
| 3806 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3807 | | |
| 3808 | 3822 | /* pick a target register for the general case */ |
| 3809 | 3823 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3810 | 3824 | |
| 3811 | | /* determine the pointer base */ |
| 3812 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 3813 | | |
| 3814 | 3825 | /* immediate index */ |
| 3815 | 3826 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3816 | | emit_movzx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movzx dstreg,[basep + 2*indp] |
| 3817 | | |
| 3818 | | /* other index */ |
| 3819 | | else |
| 3820 | 3827 | { |
| 3821 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3822 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3823 | | emit_movzx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movzx dstreg,[basep + 2*indp] |
| 3824 | | } |
| 3825 | | |
| 3826 | | /* store to appropriate target size */ |
| 3827 | | if (inst->size == 4) |
| 3828 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3829 | | else if (inst->size == 8) |
| 3830 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3831 | | |
| 3832 | | return dst; |
| 3833 | | } |
| 3834 | | |
| 3835 | | |
| 3836 | | /*------------------------------------------------- |
| 3837 | | op_load2s - process a LOAD2S opcode |
| 3838 | | -------------------------------------------------*/ |
| 3839 | | |
| 3840 | | static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3841 | | { |
| 3842 | | drcuml_parameter dstp, basep, indp; |
| 3843 | | int basereg, dstreg; |
| 3844 | | INT32 baseoffs; |
| 3845 | | |
| 3846 | | /* validate instruction */ |
| 3847 | | assert(inst->size == 4 || inst->size == 8); |
| 3848 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3849 | | |
| 3850 | | /* normalize parameters */ |
| 3851 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3852 | | |
| 3853 | | /* pick a target register for the general case */ |
| 3854 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3855 | | |
| 3856 | | /* determine the pointer base */ |
| 3857 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 3858 | | |
| 3859 | | /* 32-bit form */ |
| 3860 | | if (inst->size == 4) |
| 3861 | | { |
| 3862 | | /* immediate index */ |
| 3863 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3864 | | emit_movsx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movsx eax,[basep + 2*indp] |
| 3865 | | |
| 3866 | | /* other index */ |
| 3867 | | else |
| 3828 | if (inst->size == 4) |
| 3868 | 3829 | { |
| 3869 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3870 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3871 | | emit_movsx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx eax,[basep + 2*indp] |
| 3830 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3831 | emit_movsx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx dstreg,[basep + 1*indp] |
| 3832 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3833 | emit_movsx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value));// movsx dstreg,[basep + 2*indp] |
| 3834 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3835 | emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3872 | 3836 | } |
| 3873 | | |
| 3874 | | /* general case */ |
| 3875 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3876 | | } |
| 3877 | | |
| 3878 | | /* 64-bit form */ |
| 3879 | | else |
| 3880 | | { |
| 3881 | | /* immediate index */ |
| 3882 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3883 | | emit_movsx_r64_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movsx rax,[basep + 2*indp] |
| 3884 | | |
| 3885 | | /* other index */ |
| 3886 | | else |
| 3837 | else if (inst->size == 8) |
| 3887 | 3838 | { |
| 3888 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3889 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3890 | | emit_movsx_r64_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx rax,[basep + 2*indp] |
| 3839 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3840 | emit_movsx_r64_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp] |
| 3841 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3842 | emit_movsx_r64_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value));// movzx dstreg,[basep + 2*indp] |
| 3843 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3844 | emit_movsxd_r64_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value));// movsxd dstreg,[basep + 4*indp] |
| 3845 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3846 | emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp] |
| 3891 | 3847 | } |
| 3892 | | |
| 3893 | | /* general case */ |
| 3894 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3895 | 3848 | } |
| 3896 | | return dst; |
| 3897 | | } |
| 3898 | 3849 | |
| 3899 | | |
| 3900 | | /*------------------------------------------------- |
| 3901 | | op_load4u - process a LOAD4U opcode |
| 3902 | | -------------------------------------------------*/ |
| 3903 | | |
| 3904 | | static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3905 | | { |
| 3906 | | drcuml_parameter dstp, basep, indp; |
| 3907 | | int basereg, dstreg; |
| 3908 | | INT32 baseoffs; |
| 3909 | | |
| 3910 | | /* validate instruction */ |
| 3911 | | assert(inst->size == 4 || inst->size == 8); |
| 3912 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3913 | | |
| 3914 | | /* normalize parameters */ |
| 3915 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3916 | | |
| 3917 | | /* pick a target register for the general case */ |
| 3918 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3919 | | |
| 3920 | | /* determine the pointer base */ |
| 3921 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 3922 | | |
| 3923 | | /* immediate index */ |
| 3924 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3925 | | emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3926 | | |
| 3927 | 3850 | /* other index */ |
| 3928 | 3851 | else |
| 3929 | 3852 | { |
| 3930 | 3853 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3931 | 3854 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3932 | | emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp] |
| 3855 | if (inst->size == 4) |
| 3856 | { |
| 3857 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3858 | emit_movsx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx dstreg,[basep + 1*indp] |
| 3859 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3860 | emit_movsx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx dstreg,[basep + 2*indp] |
| 3861 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3862 | emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp] |
| 3863 | } |
| 3864 | else if (inst->size == 8) |
| 3865 | { |
| 3866 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3867 | emit_movsx_r64_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx dstreg,[basep + 1*indp] |
| 3868 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3869 | emit_movsx_r64_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx dstreg,[basep + 2*indp] |
| 3870 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3871 | emit_movsxd_r64_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // movsxd dstreg,[basep + 4*indp] |
| 3872 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3873 | emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp] |
| 3874 | } |
| 3933 | 3875 | } |
| 3934 | 3876 | |
| 3935 | | /* store to appropriate target size */ |
| 3877 | /* store result */ |
| 3936 | 3878 | if (inst->size == 4) |
| 3937 | 3879 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3938 | | else if (inst->size == 8) |
| 3880 | else |
| 3939 | 3881 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3940 | 3882 | |
| 3941 | 3883 | return dst; |
| r2821 | r2822 | |
| 3943 | 3885 | |
| 3944 | 3886 | |
| 3945 | 3887 | /*------------------------------------------------- |
| 3946 | | op_load4s - process a LOAD4S opcode |
| 3888 | op_store - process a STORE opcode |
| 3947 | 3889 | -------------------------------------------------*/ |
| 3948 | 3890 | |
| 3949 | | static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3891 | static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3950 | 3892 | { |
| 3951 | | drcuml_parameter dstp, basep, indp; |
| 3952 | | int basereg, dstreg; |
| 3893 | drcuml_parameter srcp, basep, indp, sizep; |
| 3894 | int srcreg, basereg; |
| 3953 | 3895 | INT32 baseoffs; |
| 3954 | 3896 | |
| 3955 | 3897 | /* validate instruction */ |
| 3956 | | assert(inst->size == 8); |
| 3898 | assert(inst->size == 4 || inst->size == 8); |
| 3957 | 3899 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3958 | 3900 | |
| 3959 | 3901 | /* normalize parameters */ |
| 3960 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3902 | param_normalize_4(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI, &sizep, PTYPE_I); |
| 3961 | 3903 | |
| 3962 | | /* pick a target register for the general case */ |
| 3963 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3964 | | |
| 3965 | 3904 | /* determine the pointer base */ |
| 3966 | 3905 | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 3967 | 3906 | |
| 3968 | | /* immediate index */ |
| 3969 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3970 | | emit_movsxd_r64_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3971 | | |
| 3972 | | /* other index */ |
| 3973 | | else |
| 3974 | | { |
| 3975 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3976 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3977 | | emit_movsxd_r64_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // movsx dstreg,[basep + 4*indp] |
| 3978 | | } |
| 3979 | | |
| 3980 | | /* general case */ |
| 3981 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3982 | | |
| 3983 | | return dst; |
| 3984 | | } |
| 3985 | | |
| 3986 | | |
| 3987 | | /*------------------------------------------------- |
| 3988 | | op_load8u - process a LOAD8U opcode |
| 3989 | | -------------------------------------------------*/ |
| 3990 | | |
| 3991 | | static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3992 | | { |
| 3993 | | drcuml_parameter dstp, basep, indp; |
| 3994 | | int basereg, dstreg; |
| 3995 | | INT32 baseoffs; |
| 3996 | | |
| 3997 | | /* validate instruction */ |
| 3998 | | assert(inst->size == 8); |
| 3999 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4000 | | |
| 4001 | | /* normalize parameters */ |
| 4002 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 4003 | | |
| 4004 | | /* pick a target register for the general case */ |
| 4005 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4006 | | |
| 4007 | | /* determine the pointer base */ |
| 4008 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 4009 | | |
| 4010 | | /* immediate index */ |
| 4011 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4012 | | emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp] |
| 4013 | | |
| 4014 | | /* other index */ |
| 4015 | | else |
| 4016 | | { |
| 4017 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4018 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 4019 | | emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp] |
| 4020 | | } |
| 4021 | | |
| 4022 | | /* general case */ |
| 4023 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,edx:dstreg |
| 4024 | | |
| 4025 | | return dst; |
| 4026 | | } |
| 4027 | | |
| 4028 | | |
| 4029 | | /*------------------------------------------------- |
| 4030 | | op_store1 - process a STORE1 opcode |
| 4031 | | -------------------------------------------------*/ |
| 4032 | | |
| 4033 | | static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4034 | | { |
| 4035 | | drcuml_parameter srcp, basep, indp; |
| 4036 | | int basereg, srcreg; |
| 4037 | | INT32 baseoffs; |
| 4038 | | |
| 4039 | | /* validate instruction */ |
| 4040 | | assert(inst->size == 4 || inst->size == 8); |
| 4041 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4042 | | |
| 4043 | | /* normalize parameters */ |
| 4044 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4045 | | |
| 4046 | 3907 | /* pick a source register for the general case */ |
| 4047 | 3908 | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4048 | 3909 | |
| 4049 | | /* determine the pointer base */ |
| 4050 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 4051 | | |
| 4052 | 3910 | /* degenerate case: constant index */ |
| 4053 | 3911 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4054 | 3912 | { |
| 3913 | /* immediate source */ |
| 4055 | 3914 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4056 | | emit_mov_m8_imm(&dst, MBD(basereg, baseoffs + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp |
| 4057 | | else |
| 4058 | 3915 | { |
| 4059 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4060 | | emit_mov_m8_r8(&dst, MBD(basereg, baseoffs + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg |
| 3916 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3917 | emit_mov_m8_imm(&dst, MBD(basereg, baseoffs + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp |
| 3918 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3919 | emit_mov_m16_imm(&dst, MBD(basereg, baseoffs + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp |
| 3920 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3921 | emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp |
| 3922 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3923 | { |
| 3924 | if (short_immediate(srcp.value)) |
| 3925 | emit_mov_m64_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value);// mov [basep + 8*indp],srcp |
| 3926 | else |
| 3927 | { |
| 3928 | emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value);// mov [basep + 8*indp],srcp |
| 3929 | emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 8*indp.value + 4), srcp.value >> 32); |
| 3930 | // mov [basep + 8*indp + 4],srcp >> 32 |
| 3931 | } |
| 3932 | } |
| 4061 | 3933 | } |
| 4062 | | } |
| 4063 | 3934 | |
| 4064 | | /* normal case: variable index */ |
| 4065 | | else |
| 4066 | | { |
| 4067 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4068 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4069 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4070 | | emit_mov_m8_imm(&dst, MBISD(basereg, indreg, 1, baseoffs), srcp.value); // mov [basep + 1*ecx],srcp |
| 3935 | /* variable source */ |
| 4071 | 3936 | else |
| 4072 | 3937 | { |
| 4073 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4074 | | emit_mov_m8_r8(&dst, MBISD(basereg, indreg, 1, baseoffs), srcreg); // mov [basep + 1*ecx],srcreg |
| 3938 | if (sizep.value != DRCUML_SIZE_QWORD) |
| 3939 | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 3940 | else |
| 3941 | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 3942 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3943 | emit_mov_m8_r8(&dst, MBD(basereg, baseoffs + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg |
| 3944 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3945 | emit_mov_m16_r16(&dst, MBD(basereg, baseoffs + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg |
| 3946 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3947 | emit_mov_m32_r32(&dst, MBD(basereg, baseoffs + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg |
| 3948 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3949 | emit_mov_m64_r64(&dst, MBD(basereg, baseoffs + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg |
| 4075 | 3950 | } |
| 4076 | 3951 | } |
| 4077 | | return dst; |
| 4078 | | } |
| 4079 | 3952 | |
| 4080 | | |
| 4081 | | /*------------------------------------------------- |
| 4082 | | op_store2 - process a STORE2 opcode |
| 4083 | | -------------------------------------------------*/ |
| 4084 | | |
| 4085 | | static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4086 | | { |
| 4087 | | drcuml_parameter srcp, basep, indp; |
| 4088 | | int basereg, srcreg; |
| 4089 | | INT32 baseoffs; |
| 4090 | | |
| 4091 | | /* validate instruction */ |
| 4092 | | assert(inst->size == 4 || inst->size == 8); |
| 4093 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4094 | | |
| 4095 | | /* normalize parameters */ |
| 4096 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4097 | | |
| 4098 | | /* pick a source register for the general case */ |
| 4099 | | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4100 | | |
| 4101 | | /* determine the pointer base */ |
| 4102 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 4103 | | |
| 4104 | | /* degenerate case: constant index */ |
| 4105 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4106 | | { |
| 4107 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4108 | | emit_mov_m16_imm(&dst, MBD(basereg, baseoffs + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp |
| 4109 | | else |
| 4110 | | { |
| 4111 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4112 | | emit_mov_m16_r16(&dst, MBD(basereg, baseoffs + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg |
| 4113 | | } |
| 4114 | | } |
| 4115 | | |
| 4116 | 3953 | /* normal case: variable index */ |
| 4117 | 3954 | else |
| 4118 | 3955 | { |
| 4119 | 3956 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4120 | 3957 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4121 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4122 | | emit_mov_m16_imm(&dst, MBISD(basereg, indreg, 2, baseoffs), srcp.value); // mov [basep + 2*ecx],srcp |
| 4123 | | else |
| 4124 | | { |
| 4125 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4126 | | emit_mov_m16_r16(&dst, MBISD(basereg, indreg, 2, baseoffs), srcreg); // mov [basep + 2*ecx],srcreg |
| 4127 | | } |
| 4128 | | } |
| 4129 | | return dst; |
| 4130 | | } |
| 4131 | 3958 | |
| 4132 | | |
| 4133 | | /*------------------------------------------------- |
| 4134 | | op_store4 - process a STORE4 opcode |
| 4135 | | -------------------------------------------------*/ |
| 4136 | | |
| 4137 | | static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4138 | | { |
| 4139 | | drcuml_parameter srcp, basep, indp; |
| 4140 | | int basereg, srcreg; |
| 4141 | | INT32 baseoffs; |
| 4142 | | |
| 4143 | | /* validate instruction */ |
| 4144 | | assert(inst->size == 4 || inst->size == 8); |
| 4145 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4146 | | |
| 4147 | | /* normalize parameters */ |
| 4148 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4149 | | |
| 4150 | | /* pick a source register for the general case */ |
| 4151 | | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4152 | | |
| 4153 | | /* determine the pointer base */ |
| 4154 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 4155 | | |
| 4156 | | /* degenerate case: constant index */ |
| 4157 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4158 | | { |
| 3959 | /* immediate source */ |
| 4159 | 3960 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4160 | | emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp |
| 4161 | | else |
| 4162 | 3961 | { |
| 4163 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4164 | | emit_mov_m32_r32(&dst, MBD(basereg, baseoffs + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg |
| 3962 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3963 | emit_mov_m8_imm(&dst, MBISD(basereg, indreg, 1, baseoffs), srcp.value); // mov [basep + 1*ecx],srcp |
| 3964 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3965 | emit_mov_m16_imm(&dst, MBISD(basereg, indreg, 2, baseoffs), srcp.value);// mov [basep + 2*ecx],srcp |
| 3966 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3967 | emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 4, baseoffs), srcp.value);// mov [basep + 4*ecx],srcp |
| 3968 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3969 | { |
| 3970 | if (short_immediate(srcp.value)) |
| 3971 | emit_mov_m64_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value);// mov [basep + 8*indp],srcp |
| 3972 | else |
| 3973 | { |
| 3974 | emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value);// mov [basep + 8*ecx],srcp |
| 3975 | emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 8, baseoffs + 4), srcp.value >> 32); |
| 3976 | // mov [basep + 8*ecx + 4],srcp >> 32 |
| 3977 | } |
| 3978 | } |
| 4165 | 3979 | } |
| 4166 | | } |
| 4167 | 3980 | |
| 4168 | | /* normal case: variable index */ |
| 4169 | | else |
| 4170 | | { |
| 4171 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4172 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4173 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4174 | | emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 4, baseoffs), srcp.value); // mov [basep + 4*ecx],srcp |
| 3981 | /* variable source */ |
| 4175 | 3982 | else |
| 4176 | 3983 | { |
| 4177 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4178 | | emit_mov_m32_r32(&dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // mov [basep + 4*ecx],srcreg |
| 3984 | if (sizep.value != DRCUML_SIZE_QWORD) |
| 3985 | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 3986 | else |
| 3987 | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov edx:srcreg,srcp |
| 3988 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3989 | emit_mov_m8_r8(&dst, MBISD(basereg, indreg, 1, baseoffs), srcreg); // mov [basep + 1*ecx],srcreg |
| 3990 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3991 | emit_mov_m16_r16(&dst, MBISD(basereg, indreg, 2, baseoffs), srcreg); // mov [basep + 2*ecx],srcreg |
| 3992 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3993 | emit_mov_m32_r32(&dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // mov [basep + 4*ecx],srcreg |
| 3994 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3995 | emit_mov_m64_r64(&dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // mov [basep + 8*ecx],srcreg |
| 4179 | 3996 | } |
| 4180 | 3997 | } |
| 4181 | 3998 | return dst; |
| r2821 | r2822 | |
| 4183 | 4000 | |
| 4184 | 4001 | |
| 4185 | 4002 | /*------------------------------------------------- |
| 4186 | | op_store8 - process a STORE8 opcode |
| 4003 | op_read - process a READ opcode |
| 4187 | 4004 | -------------------------------------------------*/ |
| 4188 | 4005 | |
| 4189 | | static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4006 | static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4190 | 4007 | { |
| 4191 | | drcuml_parameter srcp, basep, indp; |
| 4192 | | int basereg, srcreg; |
| 4193 | | INT32 baseoffs; |
| 4194 | | |
| 4195 | | /* validate instruction */ |
| 4196 | | assert(inst->size == 8); |
| 4197 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4198 | | |
| 4199 | | /* normalize parameters */ |
| 4200 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4201 | | |
| 4202 | | /* pick a source register for the general case */ |
| 4203 | | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4204 | | |
| 4205 | | /* determine the pointer base */ |
| 4206 | | basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); |
| 4207 | | |
| 4208 | | /* degenerate case: constant index */ |
| 4209 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4210 | | { |
| 4211 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value)) |
| 4212 | | emit_mov_m64_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp |
| 4213 | | else |
| 4214 | | { |
| 4215 | | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4216 | | emit_mov_m64_r64(&dst, MBD(basereg, baseoffs + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg |
| 4217 | | } |
| 4218 | | } |
| 4219 | | |
| 4220 | | /* normal case: variable index */ |
| 4221 | | else |
| 4222 | | { |
| 4223 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4224 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4225 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value)) |
| 4226 | | emit_mov_m64_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value); // mov [basep + 8*ecx],srcp |
| 4227 | | else |
| 4228 | | { |
| 4229 | | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4230 | | emit_mov_m64_r64(&dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // mov [basep + 8*ecx],srcreg |
| 4231 | | } |
| 4232 | | } |
| 4233 | | return dst; |
| 4234 | | } |
| 4235 | | |
| 4236 | | |
| 4237 | | /*------------------------------------------------- |
| 4238 | | op_read1u - process a READ1U opcode |
| 4239 | | -------------------------------------------------*/ |
| 4240 | | |
| 4241 | | static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4242 | | { |
| 4243 | | drcuml_parameter dstp, spacep, addrp; |
| 4008 | drcuml_parameter dstp, addrp, spacesizep; |
| 4244 | 4009 | int dstreg; |
| 4245 | 4010 | |
| 4246 | 4011 | /* validate instruction */ |
| r2821 | r2822 | |
| 4248 | 4013 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4249 | 4014 | |
| 4250 | 4015 | /* normalize parameters */ |
| 4251 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4016 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4252 | 4017 | |
| 4253 | 4018 | /* pick a target register for the general case */ |
| 4254 | 4019 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4255 | 4020 | |
| 4256 | 4021 | /* set up a call to the read byte handler */ |
| 4257 | 4022 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4258 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_byte);// call read_byte |
| 4259 | | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 4260 | | |
| 4261 | | /* store to appropriate target size */ |
| 4262 | | if (inst->size == 4) |
| 4263 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4264 | | else if (inst->size == 8) |
| 4265 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4266 | | |
| 4267 | | return dst; |
| 4268 | | } |
| 4269 | | |
| 4270 | | |
| 4271 | | /*------------------------------------------------- |
| 4272 | | op_read1s - process a READ1S opcode |
| 4273 | | -------------------------------------------------*/ |
| 4274 | | |
| 4275 | | static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4276 | | { |
| 4277 | | drcuml_parameter dstp, spacep, addrp; |
| 4278 | | int dstreg; |
| 4279 | | |
| 4280 | | /* validate instruction */ |
| 4281 | | assert(inst->size == 4 || inst->size == 8); |
| 4282 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4283 | | |
| 4284 | | /* normalize parameters */ |
| 4285 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4286 | | |
| 4287 | | /* pick a target register for the general case */ |
| 4288 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4289 | | |
| 4290 | | /* set up a call to the read byte handler */ |
| 4291 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4292 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_byte);// call read_byte |
| 4293 | | |
| 4294 | | /* 32-bit form */ |
| 4295 | | if (inst->size == 4) |
| 4023 | if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) |
| 4296 | 4024 | { |
| 4297 | | /* general case */ |
| 4298 | | emit_movsx_r32_r8(&dst, dstreg, REG_AL); // movsx dstreg,al |
| 4299 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4025 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_byte); |
| 4026 | // call read_byte |
| 4027 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 4300 | 4028 | } |
| 4301 | | |
| 4302 | | /* 64-bit form */ |
| 4303 | | else |
| 4029 | else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4304 | 4030 | { |
| 4305 | | /* general case */ |
| 4306 | | emit_movsx_r64_r8(&dst, dstreg, REG_AL); // movsx dstreg,al |
| 4307 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4031 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_word); |
| 4032 | // call read_word |
| 4033 | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4308 | 4034 | } |
| 4309 | | return dst; |
| 4310 | | } |
| 4035 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4036 | { |
| 4037 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_dword); |
| 4038 | // call read_dword |
| 4039 | if (dstreg != REG_EAX || inst->size == 8) |
| 4040 | emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax |
| 4041 | } |
| 4042 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4043 | { |
| 4044 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_qword); |
| 4045 | // call read_qword |
| 4046 | if (dstreg != REG_RAX) |
| 4047 | emit_mov_r64_r64(&dst, dstreg, REG_RAX); // mov dstreg,rax |
| 4048 | } |
| 4311 | 4049 | |
| 4312 | | |
| 4313 | | /*------------------------------------------------- |
| 4314 | | op_read2u - process a READ2U opcode |
| 4315 | | -------------------------------------------------*/ |
| 4316 | | |
| 4317 | | static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4318 | | { |
| 4319 | | drcuml_parameter dstp, spacep, addrp; |
| 4320 | | int dstreg; |
| 4321 | | |
| 4322 | | /* validate instruction */ |
| 4323 | | assert(inst->size == 4 || inst->size == 8); |
| 4324 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4325 | | |
| 4326 | | /* normalize parameters */ |
| 4327 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4328 | | |
| 4329 | | /* pick a target register for the general case */ |
| 4330 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4331 | | |
| 4332 | | /* set up a call to the read word handler */ |
| 4333 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4334 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word);// call read_word |
| 4335 | | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4336 | | |
| 4337 | | /* store to appropriate target size */ |
| 4050 | /* store result */ |
| 4338 | 4051 | if (inst->size == 4) |
| 4339 | 4052 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4340 | | else if (inst->size == 8) |
| 4053 | else |
| 4341 | 4054 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4342 | 4055 | |
| 4343 | 4056 | return dst; |
| r2821 | r2822 | |
| 4345 | 4058 | |
| 4346 | 4059 | |
| 4347 | 4060 | /*------------------------------------------------- |
| 4348 | | op_read2s - process a READ2S opcode |
| 4061 | op_readm - process a READM opcode |
| 4349 | 4062 | -------------------------------------------------*/ |
| 4350 | 4063 | |
| 4351 | | static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4064 | static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4352 | 4065 | { |
| 4353 | | drcuml_parameter dstp, spacep, addrp; |
| 4066 | drcuml_parameter dstp, addrp, maskp, spacesizep; |
| 4354 | 4067 | int dstreg; |
| 4355 | 4068 | |
| 4356 | 4069 | /* validate instruction */ |
| r2821 | r2822 | |
| 4358 | 4071 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4359 | 4072 | |
| 4360 | 4073 | /* normalize parameters */ |
| 4361 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4074 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4362 | 4075 | |
| 4363 | 4076 | /* pick a target register for the general case */ |
| 4364 | 4077 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4365 | 4078 | |
| 4366 | | /* set up a call to the read word handler */ |
| 4079 | /* set up a call to the read byte handler */ |
| 4367 | 4080 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4368 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word);// call read_word |
| 4369 | | |
| 4370 | | /* 32-bit form */ |
| 4371 | | if (inst->size == 4) |
| 4081 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4082 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp |
| 4083 | else |
| 4084 | emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp |
| 4085 | if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4372 | 4086 | { |
| 4373 | | /* general case */ |
| 4374 | | emit_movsx_r32_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax |
| 4375 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4087 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_word_masked); |
| 4088 | // call read_word_masked |
| 4089 | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4376 | 4090 | } |
| 4377 | | |
| 4378 | | /* 64-bit form */ |
| 4379 | | else |
| 4091 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4380 | 4092 | { |
| 4381 | | /* general case */ |
| 4382 | | emit_movsx_r64_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax |
| 4383 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4093 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_dword_masked); |
| 4094 | // call read_dword_masked |
| 4095 | if (dstreg != REG_EAX || inst->size == 8) |
| 4096 | emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax |
| 4384 | 4097 | } |
| 4385 | | return dst; |
| 4386 | | } |
| 4098 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4099 | { |
| 4100 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_qword_masked); |
| 4101 | // call read_qword_masked |
| 4102 | if (dstreg != REG_RAX) |
| 4103 | emit_mov_r64_r64(&dst, dstreg, REG_RAX); // mov dstreg,rax |
| 4104 | } |
| 4387 | 4105 | |
| 4388 | | |
| 4389 | | /*------------------------------------------------- |
| 4390 | | op_read2m - process a READ2M opcode |
| 4391 | | -------------------------------------------------*/ |
| 4392 | | |
| 4393 | | static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4394 | | { |
| 4395 | | drcuml_parameter dstp, spacep, addrp, maskp; |
| 4396 | | int dstreg; |
| 4397 | | |
| 4398 | | /* validate instruction */ |
| 4399 | | assert(inst->size == 4 || inst->size == 8); |
| 4400 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4401 | | |
| 4402 | | /* normalize parameters */ |
| 4403 | | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); |
| 4404 | | |
| 4405 | | /* pick a target register for the general case */ |
| 4406 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4407 | | |
| 4408 | | /* set up a call to the read dword masked handler */ |
| 4409 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4410 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param1,maskp |
| 4411 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word_masked);// call read_word_masked |
| 4412 | | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4413 | | |
| 4414 | | /* store to appropriate target size */ |
| 4106 | /* store result */ |
| 4415 | 4107 | if (inst->size == 4) |
| 4416 | 4108 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4417 | | else if (inst->size == 8) |
| 4109 | else |
| 4418 | 4110 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4419 | 4111 | |
| 4420 | 4112 | return dst; |
| r2821 | r2822 | |
| 4422 | 4114 | |
| 4423 | 4115 | |
| 4424 | 4116 | /*------------------------------------------------- |
| 4425 | | op_read4u - process a READ4U opcode |
| 4117 | op_write - process a WRITE opcode |
| 4426 | 4118 | -------------------------------------------------*/ |
| 4427 | 4119 | |
| 4428 | | static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4120 | static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4429 | 4121 | { |
| 4430 | | drcuml_parameter dstp, spacep, addrp; |
| 4122 | drcuml_parameter addrp, srcp, spacesizep; |
| 4431 | 4123 | |
| 4432 | 4124 | /* validate instruction */ |
| 4433 | 4125 | assert(inst->size == 4 || inst->size == 8); |
| 4434 | 4126 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4435 | 4127 | |
| 4436 | 4128 | /* normalize parameters */ |
| 4437 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4129 | param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4438 | 4130 | |
| 4439 | | /* set up a call to the read dword handler */ |
| 4131 | /* set up a call to the write byte handler */ |
| 4440 | 4132 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4441 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword |
| 4442 | | |
| 4443 | | /* store to appropriate target size */ |
| 4444 | | if (inst->size == 4) |
| 4445 | | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 4446 | | else if (inst->size == 8) |
| 4447 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax |
| 4448 | | |
| 4133 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4134 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param1,srcp |
| 4135 | else |
| 4136 | emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param1,srcp |
| 4137 | if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) |
| 4138 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_byte); |
| 4139 | // call write_byte |
| 4140 | else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4141 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_word); |
| 4142 | // call write_word |
| 4143 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4144 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_dword); |
| 4145 | // call write_dword |
| 4146 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4147 | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_qword); |
| 4148 | // call write_qword |
| 4449 | 4149 | return dst; |
| 4450 | 4150 | } |
| 4451 | 4151 | |
| 4452 | 4152 | |
| 4453 | 4153 | /*------------------------------------------------- |
| 4454 | | op_read4s - process a READ4S opcode |
| 4154 | op_writem - process a WRITEM opcode |
| 4455 | 4155 | -------------------------------------------------*/ |
| 4456 | 4156 | |
| 4457 | | static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4157 | static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4458 | 4158 | { |
| 4459 | | drcuml_parameter dstp, spacep, addrp; |
| 4460 | | int dstreg; |
| 4159 | drcuml_parameter addrp, srcp, maskp, spacesizep; |
| 4461 | 4160 | |
| 4462 | 4161 | /* validate instruction */ |
| 4463 | | assert(inst->size == 8); |
| 4464 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4465 | | |
| 4466 | | /* normalize parameters */ |
| 4467 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4468 | | |
| 4469 | | /* pick a target register for the general case */ |
| 4470 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4471 | | |
| 4472 | | /* set up a call to the read dword handler */ |
| 4473 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4474 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword |
| 4475 | | |
| 4476 | | /* 64-bit form */ |
| 4477 | | emit_movsxd_r64_r32(&dst, dstreg, REG_EAX); // movsxd dstreg,eax |
| 4478 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4479 | | |
| 4480 | | return dst; |
| 4481 | | } |
| 4482 | | |
| 4483 | | |
| 4484 | | /*------------------------------------------------- |
| 4485 | | op_read4m - process a READ4M opcode |
| 4486 | | -------------------------------------------------*/ |
| 4487 | | |
| 4488 | | static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4489 | | { |
| 4490 | | drcuml_parameter dstp, spacep, addrp, maskp; |
| 4491 | | |
| 4492 | | /* validate instruction */ |
| 4493 | 4162 | assert(inst->size == 4 || inst->size == 8); |
| 4494 | 4163 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4495 | 4164 | |
| 4496 | 4165 | /* normalize parameters */ |
| 4497 | | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); |
| 4166 | param_normalize_4(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4498 | 4167 | |
| 4499 | | /* set up a call to the read dword masked handler */ |
| 4500 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4501 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp |
| 4502 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword_masked);// call read_dword_masked |
| 4503 | | |
| 4504 | | /* store to appropriate target size */ |
| 4505 | | if (inst->size == 4) |
| 4506 | | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 4507 | | else if (inst->size == 8) |
| 4508 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax |
| 4509 | | |
| 4510 | | return dst; |
| 4511 | | } |
| 4512 | | |
| 4513 | | |
| 4514 | | /*------------------------------------------------- |
| 4515 | | op_read8u - process a READ8U opcode |
| 4516 | | -------------------------------------------------*/ |
| 4517 | | |
| 4518 | | static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4519 | | { |
| 4520 | | drcuml_parameter dstp, spacep, addrp; |
| 4521 | | |
| 4522 | | /* validate instruction */ |
| 4523 | | assert(inst->size == 8); |
| 4524 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4525 | | |
| 4526 | | /* normalize parameters */ |
| 4527 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4528 | | |
| 4529 | | /* set up a call to the read qword handler */ |
| 4530 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4531 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword);// call read_qword |
| 4532 | | |
| 4533 | | /* 64-bit form */ |
| 4534 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax |
| 4535 | | |
| 4536 | | return dst; |
| 4537 | | } |
| 4538 | | |
| 4539 | | |
| 4540 | | /*------------------------------------------------- |
| 4541 | | op_read8m - process a READ8M opcode |
| 4542 | | -------------------------------------------------*/ |
| 4543 | | |
| 4544 | | static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4545 | | { |
| 4546 | | drcuml_parameter dstp, spacep, addrp, maskp; |
| 4547 | | |
| 4548 | | /* validate instruction */ |
| 4549 | | assert(inst->size == 8); |
| 4550 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4551 | | |
| 4552 | | /* normalize parameters */ |
| 4553 | | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); |
| 4554 | | |
| 4555 | | /* set up a call to the read qword masked handler */ |
| 4556 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4557 | | emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp |
| 4558 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword_masked);// call read_qword_masked |
| 4559 | | |
| 4560 | | /* 64-bit form */ |
| 4561 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax |
| 4562 | | |
| 4563 | | return dst; |
| 4564 | | } |
| 4565 | | |
| 4566 | | |
| 4567 | | /*------------------------------------------------- |
| 4568 | | op_write1 - process a WRITE1 opcode |
| 4569 | | -------------------------------------------------*/ |
| 4570 | | |
| 4571 | | static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4572 | | { |
| 4573 | | drcuml_parameter spacep, addrp, srcp; |
| 4574 | | |
| 4575 | | /* validate instruction */ |
| 4576 | | assert(inst->size == 4 || inst->size == 8); |
| 4577 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4578 | | |
| 4579 | | /* normalize parameters */ |
| 4580 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4581 | | |
| 4582 | 4168 | /* set up a call to the write byte handler */ |
| 4583 | 4169 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4584 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4585 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_byte);// call write_byte |
| 4586 | | |
| 4587 | | return dst; |
| 4588 | | } |
| 4589 | | |
| 4590 | | |
| 4591 | | /*------------------------------------------------- |
| 4592 | | op_write2 - process a WRITE2 opcode |
| 4593 | | -------------------------------------------------*/ |
| 4594 | | |
| 4595 | | static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4596 | | { |
| 4597 | | drcuml_parameter spacep, addrp, srcp; |
| 4598 | | |
| 4599 | | /* validate instruction */ |
| 4600 | | assert(inst->size == 4 || inst->size == 8); |
| 4601 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4602 | | |
| 4603 | | /* normalize parameters */ |
| 4604 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4605 | | |
| 4606 | | /* set up a call to the write word handler */ |
| 4607 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4608 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4609 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_word);// call write_word |
| 4610 | | |
| 4611 | | return dst; |
| 4612 | | } |
| 4613 | | |
| 4614 | | |
| 4615 | | /*------------------------------------------------- |
| 4616 | | op_writ2m - process a WRIT2M opcode |
| 4617 | | -------------------------------------------------*/ |
| 4618 | | |
| 4619 | | static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4620 | | { |
| 4621 | | drcuml_parameter spacep, addrp, maskp, srcp; |
| 4622 | | |
| 4623 | | /* validate instruction */ |
| 4624 | | assert(inst->size == 4 || inst->size == 8); |
| 4625 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4626 | | |
| 4627 | | /* normalize parameters */ |
| 4628 | | param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4629 | | |
| 4630 | | /* set up a call to the write word handler */ |
| 4631 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4632 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4633 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp |
| 4634 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_word_masked);// call write_word_masked |
| 4635 | | return dst; |
| 4636 | | } |
| 4637 | | |
| 4638 | | |
| 4639 | | /*------------------------------------------------- |
| 4640 | | op_write4 - process a WRITE4 opcode |
| 4641 | | -------------------------------------------------*/ |
| 4642 | | |
| 4643 | | static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4644 | | { |
| 4645 | | drcuml_parameter spacep, addrp, srcp; |
| 4646 | | |
| 4647 | | /* validate instruction */ |
| 4648 | | assert(inst->size == 4 || inst->size == 8); |
| 4649 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4650 | | |
| 4651 | | /* normalize parameters */ |
| 4652 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4653 | | |
| 4654 | | /* set up a call to the write dword handler */ |
| 4655 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4656 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4657 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword);// call write_dword |
| 4658 | | |
| 4659 | | return dst; |
| 4660 | | } |
| 4661 | | |
| 4662 | | |
| 4663 | | /*------------------------------------------------- |
| 4664 | | op_writ4m - process a WRIT4M opcode |
| 4665 | | -------------------------------------------------*/ |
| 4666 | | |
| 4667 | | static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4668 | | { |
| 4669 | | drcuml_parameter spacep, addrp, maskp, srcp; |
| 4670 | | |
| 4671 | | /* validate instruction */ |
| 4672 | | assert(inst->size == 4 || inst->size == 8); |
| 4673 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4674 | | |
| 4675 | | /* normalize parameters */ |
| 4676 | | param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4677 | | |
| 4678 | | /* set up a call to the write word handler */ |
| 4679 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4680 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4681 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp |
| 4682 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword_masked);// call write_dword_masked |
| 4683 | | return dst; |
| 4684 | | } |
| 4685 | | |
| 4686 | | |
| 4687 | | /*------------------------------------------------- |
| 4688 | | op_write8 - process a WRITE8 opcode |
| 4689 | | -------------------------------------------------*/ |
| 4690 | | |
| 4691 | | static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4692 | | { |
| 4693 | | drcuml_parameter spacep, addrp, srcp; |
| 4694 | | |
| 4695 | | /* validate instruction */ |
| 4696 | | assert(inst->size == 8); |
| 4697 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4698 | | |
| 4699 | | /* normalize parameters */ |
| 4700 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4701 | | |
| 4702 | | /* set up a call to the write qword handler */ |
| 4703 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4704 | | emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4705 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword);// call write_qword |
| 4706 | | |
| 4707 | | return dst; |
| 4708 | | } |
| 4709 | | |
| 4710 | | |
| 4711 | | /*------------------------------------------------- |
| 4712 | | op_writ8m - process a WRIT8M opcode |
| 4713 | | -------------------------------------------------*/ |
| 4714 | | |
| 4715 | | static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4716 | | { |
| 4717 | | drcuml_parameter spacep, addrp, maskp, srcp; |
| 4718 | | |
| 4719 | | /* validate instruction */ |
| 4720 | | assert(inst->size == 8); |
| 4721 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4722 | | |
| 4723 | | /* normalize parameters */ |
| 4724 | | param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4725 | | |
| 4726 | | /* set up a call to the write word handler */ |
| 4727 | | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| 4728 | | emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4729 | | emit_mov_r64_p64(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp |
| 4730 | | emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword_masked);// call write_qword_masked |
| 4731 | | return dst; |
| 4732 | | } |
| 4733 | | |
| 4734 | | |
| 4735 | | /*------------------------------------------------- |
| 4736 | | op_flags - process a FLAGS opcode |
| 4737 | | -------------------------------------------------*/ |
| 4738 | | |
| 4739 | | static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4740 | | { |
| 4741 | | drcuml_parameter dstp, maskp, tablep; |
| 4742 | | int dstreg; |
| 4743 | | |
| 4744 | | /* validate instruction */ |
| 4745 | | assert(inst->size == 4 || inst->size == 8); |
| 4746 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4747 | | |
| 4748 | | /* normalize parameters */ |
| 4749 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &maskp, PTYPE_I, &tablep, PTYPE_M); |
| 4750 | | |
| 4751 | | /* pick a target register for the general case */ |
| 4752 | | dstreg = param_select_register(REG_ECX, &dstp, NULL); |
| 4753 | | |
| 4754 | | /* translate live flags into UML flags */ |
| 4755 | | emit_pushf(&dst); // pushf |
| 4756 | | emit_pop_r64(&dst, REG_RAX); // pop rax |
| 4757 | | emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 |
| 4758 | | emit_movzx_r32_m8(&dst, REG_EAX, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsmap[0]))); |
| 4759 | | // movzx eax,[flags_map] |
| 4760 | | |
| 4761 | | /* 32-bit form */ |
| 4762 | | if (inst->size == 4) |
| 4170 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4763 | 4171 | { |
| 4764 | | /* no masking */ |
| 4765 | | if (maskp.value == 0xffffffff) |
| 4766 | | { |
| 4767 | | emit_mov_r32_m32(&dst, dstreg, MBISD(REG_RBP, REG_EAX, 4, offset_from_rbp(drcbe, tablep.value))); |
| 4768 | | // mov dstreg,[eax*4+table] |
| 4769 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4770 | | } |
| 4771 | | |
| 4772 | | /* general case */ |
| 4773 | | else |
| 4774 | | { |
| 4775 | | emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp |
| 4776 | | emit_mov_r32_m32(&dst, REG_EDX, MBISD(REG_RBP, REG_EAX, 4, offset_from_rbp(drcbe, tablep.value))); |
| 4777 | | // mov edx,[eax*4+table] |
| 4778 | | emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask |
| 4779 | | emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask |
| 4780 | | emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx |
| 4781 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4782 | | } |
| 4172 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4173 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp |
| 4783 | 4174 | } |
| 4784 | | |
| 4785 | | /* 64-bit form */ |
| 4786 | 4175 | else |
| 4787 | 4176 | { |
| 4788 | | /* no masking */ |
| 4789 | | if (maskp.value == U64(0xffffffffffffffff)) |
| 4790 | | { |
| 4791 | | emit_mov_r64_m64(&dst, dstreg, MBISD(REG_RBP, REG_EAX, 8, offset_from_rbp(drcbe, tablep.value))); |
| 4792 | | // mov dstreg,[eax*8+table] |
| 4793 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4794 | | } |
| 4795 | | |
| 4796 | | /* general case */ |
| 4797 | | else |
| 4798 | | { |
| 4799 | | emit_mov_r64_p64(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp |
| 4800 | | emit_mov_r64_m64(&dst, REG_EDX, MBISD(REG_RBP, REG_EAX, 8, offset_from_rbp(drcbe, tablep.value))); |
| 4801 | | // mov edx,[eax*84+table] |
| 4802 | | if (short_immediate(~maskp.value)) |
| 4803 | | emit_and_r64_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask |
| 4804 | | else |
| 4805 | | { |
| 4806 | | emit_mov_r64_imm(&dst, REG_R11, ~maskp.value); // mov r11,~mask |
| 4807 | | emit_and_r64_r64(&dst, dstreg, REG_R11); // and dstreg,r11 |
| 4808 | | } |
| 4809 | | if (short_immediate(maskp.value)) |
| 4810 | | emit_and_r64_imm(&dst, REG_EDX, maskp.value); // and edx,mask |
| 4811 | | else |
| 4812 | | { |
| 4813 | | emit_mov_r64_imm(&dst, REG_R11, maskp.value); // mov r11,mask |
| 4814 | | emit_and_r64_r64(&dst, REG_EDX, REG_R11); // and edx,r11 |
| 4815 | | } |
| 4816 | | emit_or_r64_r64(&dst, dstreg, REG_EDX); // or dstreg,edx |
| 4817 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4818 | | } |
| 4177 | emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp |
| 4178 | emit_mov_r64_p64(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp |
| 4819 | 4179 | } |
| 4180 | if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4181 | emit_call(&dst, (x86code *)drcbe->accessors[spacesizep.value / 16].write_word_masked); |
| 4182 | // call write_word_masked |
| 4183 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4184 | emit_call(&dst, (x86code *)drcbe->accessors[spacesizep.value / 16].write_dword_masked); |
| 4185 | // call write_dword_masked |
| 4186 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4187 | emit_call(&dst, (x86code *)drcbe->accessors[spacesizep.value / 16].write_qword_masked); |
| 4188 | // call write_qword_masked |
| 4820 | 4189 | return dst; |
| 4821 | 4190 | } |
| 4822 | 4191 | |
| 4823 | 4192 | |
| 4824 | 4193 | /*------------------------------------------------- |
| 4825 | | op_setc - process a SETC opcode |
| 4194 | op_carry - process a CARRY opcode |
| 4826 | 4195 | -------------------------------------------------*/ |
| 4827 | 4196 | |
| 4828 | | static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4197 | static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4829 | 4198 | { |
| 4830 | 4199 | drcuml_parameter srcp, bitp; |
| 4831 | 4200 | |
| r2821 | r2822 | |
| 4859 | 4228 | if (bitp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4860 | 4229 | { |
| 4861 | 4230 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 4862 | | emit_bt_m32_imm(&dst, MABS(srcp.value), bitp.value); // bt [srcp],bitp |
| 4231 | emit_bt_m32_imm(&dst, MABS(drcbe, srcp.value), bitp.value); // bt [srcp],bitp |
| 4863 | 4232 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4864 | 4233 | emit_bt_r32_imm(&dst, srcp.value, bitp.value); // bt srcp,bitp |
| 4865 | 4234 | } |
| 4866 | 4235 | else |
| 4867 | 4236 | { |
| 4868 | 4237 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 4869 | | emit_bt_m32_r32(&dst, MABS(srcp.value), REG_ECX); // bt [srcp],ecx |
| 4238 | emit_bt_m32_r32(&dst, MABS(drcbe, srcp.value), REG_ECX); // bt [srcp],ecx |
| 4870 | 4239 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4871 | 4240 | emit_bt_r32_r32(&dst, srcp.value, REG_ECX); // bt srcp,ecx |
| 4872 | 4241 | } |
| r2821 | r2822 | |
| 4878 | 4247 | if (bitp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4879 | 4248 | { |
| 4880 | 4249 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 4881 | | emit_bt_m64_imm(&dst, MABS(srcp.value), bitp.value); // bt [srcp],bitp |
| 4250 | emit_bt_m64_imm(&dst, MABS(drcbe, srcp.value), bitp.value); // bt [srcp],bitp |
| 4882 | 4251 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4883 | 4252 | emit_bt_r64_imm(&dst, srcp.value, bitp.value); // bt srcp,bitp |
| 4884 | 4253 | } |
| 4885 | 4254 | else |
| 4886 | 4255 | { |
| 4887 | 4256 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 4888 | | emit_bt_m64_r64(&dst, MABS(srcp.value), REG_ECX); // bt [srcp],ecx |
| 4257 | emit_bt_m64_r64(&dst, MABS(drcbe, srcp.value), REG_ECX); // bt [srcp],ecx |
| 4889 | 4258 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4890 | 4259 | emit_bt_r64_r64(&dst, srcp.value, REG_ECX); // bt srcp,ecx |
| 4891 | 4260 | } |
| r2821 | r2822 | |
| 4895 | 4264 | |
| 4896 | 4265 | |
| 4897 | 4266 | /*------------------------------------------------- |
| 4267 | op_set - process a SET opcode |
| 4268 | -------------------------------------------------*/ |
| 4269 | |
| 4270 | static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4271 | { |
| 4272 | drcuml_parameter dstp; |
| 4273 | int dstreg; |
| 4274 | |
| 4275 | /* validate instruction */ |
| 4276 | assert(inst->size == 4 || inst->size == 8); |
| 4277 | assert(inst->condflags >= DRCUML_COND_Z && inst->condflags < DRCUML_COND_MAX); |
| 4278 | |
| 4279 | /* normalize parameters */ |
| 4280 | param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); |
| 4281 | |
| 4282 | /* pick a target register for the general case */ |
| 4283 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4284 | |
| 4285 | /* set to AL */ |
| 4286 | emit_setcc_r8(&dst, X86_CONDITION(inst->condflags), REG_AL); // setcc al |
| 4287 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 4288 | |
| 4289 | /* 32-bit form */ |
| 4290 | if (inst->size == 4) |
| 4291 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4292 | |
| 4293 | /* 64-bit form */ |
| 4294 | else if (inst->size == 8) |
| 4295 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4296 | |
| 4297 | return dst; |
| 4298 | } |
| 4299 | |
| 4300 | |
| 4301 | /*------------------------------------------------- |
| 4898 | 4302 | op_mov - process a MOV opcode |
| 4899 | 4303 | -------------------------------------------------*/ |
| 4900 | 4304 | |
| r2821 | r2822 | |
| 5012 | 4416 | |
| 5013 | 4417 | |
| 5014 | 4418 | /*------------------------------------------------- |
| 5015 | | op_zext1 - process a ZEXT1 opcode |
| 4419 | op_sext - process a SEXT opcode |
| 5016 | 4420 | -------------------------------------------------*/ |
| 5017 | 4421 | |
| 5018 | | static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4422 | static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5019 | 4423 | { |
| 5020 | | drcuml_parameter dstp, srcp; |
| 4424 | drcuml_parameter dstp, srcp, sizep; |
| 5021 | 4425 | int dstreg; |
| 5022 | 4426 | |
| 5023 | 4427 | /* validate instruction */ |
| r2821 | r2822 | |
| 5025 | 4429 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5026 | 4430 | |
| 5027 | 4431 | /* normalize parameters */ |
| 5028 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 4432 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI, &sizep, PTYPE_I); |
| 5029 | 4433 | |
| 5030 | 4434 | /* degenerate cases -- convert to a move */ |
| 5031 | 4435 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5032 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT8)srcp.value); |
| 5033 | | |
| 5034 | | /* pick a target register for the general case */ |
| 5035 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5036 | | |
| 5037 | | /* general case */ |
| 5038 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5039 | | emit_movzx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movzx dstreg,[srcp] |
| 5040 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5041 | | emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp |
| 5042 | | |
| 5043 | | /* 32-bit form */ |
| 5044 | | if (inst->size == 4) |
| 5045 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5046 | | |
| 5047 | | /* 64-bit form */ |
| 5048 | | else if (inst->size == 8) |
| 5049 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5050 | | |
| 5051 | | return dst; |
| 5052 | | } |
| 5053 | | |
| 5054 | | |
| 5055 | | /*------------------------------------------------- |
| 5056 | | op_zext2 - process a ZEXT2 opcode |
| 5057 | | -------------------------------------------------*/ |
| 5058 | | |
| 5059 | | static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5060 | | { |
| 5061 | | drcuml_parameter dstp, srcp; |
| 5062 | | int dstreg; |
| 5063 | | |
| 5064 | | /* validate instruction */ |
| 5065 | | assert(inst->size == 4 || inst->size == 8); |
| 5066 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5067 | | |
| 5068 | | /* normalize parameters */ |
| 5069 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5070 | | |
| 5071 | | /* degenerate cases -- convert to a move */ |
| 5072 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5073 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT16)srcp.value); |
| 5074 | | |
| 5075 | | /* pick a target register for the general case */ |
| 5076 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5077 | | |
| 5078 | | /* general case */ |
| 5079 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5080 | | emit_movzx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movzx dstreg,[srcp] |
| 5081 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5082 | | emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp |
| 5083 | | |
| 5084 | | /* 32-bit form */ |
| 5085 | | if (inst->size == 4) |
| 5086 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5087 | | |
| 5088 | | /* 64-bit form */ |
| 5089 | | else if (inst->size == 8) |
| 5090 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5091 | | |
| 5092 | | return dst; |
| 5093 | | } |
| 5094 | | |
| 5095 | | |
| 5096 | | /*------------------------------------------------- |
| 5097 | | op_zext4 - process a ZEXT4 opcode |
| 5098 | | -------------------------------------------------*/ |
| 5099 | | |
| 5100 | | static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5101 | | { |
| 5102 | | drcuml_parameter dstp, srcp; |
| 5103 | | int dstreg; |
| 5104 | | |
| 5105 | | /* validate instruction */ |
| 5106 | | assert(inst->size == 8); |
| 5107 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5108 | | |
| 5109 | | /* normalize parameters */ |
| 5110 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5111 | | |
| 5112 | | /* degenerate cases -- convert to a move */ |
| 5113 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5114 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)srcp.value); |
| 5115 | | |
| 5116 | | /* pick a target register for the general case */ |
| 5117 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5118 | | |
| 5119 | | /* general case */ |
| 5120 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5121 | | emit_mov_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp] |
| 5122 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5123 | | emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp |
| 5124 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5125 | | |
| 5126 | | return dst; |
| 5127 | | } |
| 5128 | | |
| 5129 | | |
| 5130 | | /*------------------------------------------------- |
| 5131 | | op_sext1 - process a SEXT1 opcode |
| 5132 | | -------------------------------------------------*/ |
| 5133 | | |
| 5134 | | static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5135 | | { |
| 5136 | | drcuml_parameter dstp, srcp; |
| 5137 | | int dstreg; |
| 5138 | | |
| 5139 | | /* validate instruction */ |
| 5140 | | assert(inst->size == 4 || inst->size == 8); |
| 5141 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5142 | | |
| 5143 | | /* normalize parameters */ |
| 5144 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5145 | | |
| 5146 | | /* degenerate cases -- convert to a move */ |
| 5147 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5148 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); |
| 5149 | | |
| 5150 | | /* pick a target register for the general case */ |
| 5151 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5152 | | |
| 5153 | | /* convert 8-bit source registers */ |
| 5154 | | if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) |
| 5155 | 4436 | { |
| 5156 | | emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp |
| 5157 | | srcp.value = REG_EAX; |
| 4437 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4438 | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); |
| 4439 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4440 | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); |
| 4441 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4442 | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); |
| 5158 | 4443 | } |
| 5159 | 4444 | |
| 5160 | | /* 32-bit form */ |
| 5161 | | if (inst->size == 4) |
| 5162 | | { |
| 5163 | | /* general case */ |
| 5164 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5165 | | emit_movsx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 5166 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5167 | | emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 5168 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5169 | | } |
| 5170 | | |
| 5171 | | /* 64-bit form */ |
| 5172 | | else if (inst->size == 8) |
| 5173 | | { |
| 5174 | | /* general case */ |
| 5175 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5176 | | emit_movsx_r64_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 5177 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5178 | | emit_movsx_r64_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 5179 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5180 | | } |
| 5181 | | return dst; |
| 5182 | | } |
| 5183 | | |
| 5184 | | |
| 5185 | | /*------------------------------------------------- |
| 5186 | | op_sext2 - process a SEXT2 opcode |
| 5187 | | -------------------------------------------------*/ |
| 5188 | | |
| 5189 | | static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5190 | | { |
| 5191 | | drcuml_parameter dstp, srcp; |
| 5192 | | int dstreg; |
| 5193 | | |
| 5194 | | /* validate instruction */ |
| 5195 | | assert(inst->size == 4 || inst->size == 8); |
| 5196 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5197 | | |
| 5198 | | /* normalize parameters */ |
| 5199 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5200 | | |
| 5201 | | /* degenerate cases -- convert to a move */ |
| 5202 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5203 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); |
| 5204 | | |
| 5205 | 4445 | /* pick a target register for the general case */ |
| 5206 | 4446 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5207 | 4447 | |
| r2821 | r2822 | |
| 5210 | 4450 | { |
| 5211 | 4451 | /* general case */ |
| 5212 | 4452 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5213 | | emit_movsx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 4453 | { |
| 4454 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4455 | emit_movsx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 4456 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4457 | emit_movsx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 4458 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4459 | emit_mov_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp] |
| 4460 | } |
| 5214 | 4461 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5215 | | emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4462 | { |
| 4463 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4464 | emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4465 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4466 | emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4467 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4468 | emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp |
| 4469 | } |
| 5216 | 4470 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5217 | 4471 | } |
| 5218 | 4472 | |
| r2821 | r2822 | |
| 5221 | 4475 | { |
| 5222 | 4476 | /* general case */ |
| 5223 | 4477 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5224 | | emit_movsx_r64_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 4478 | { |
| 4479 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4480 | emit_movsx_r64_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 4481 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4482 | emit_movsx_r64_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] |
| 4483 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4484 | emit_movsxd_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // movsxd dstreg,[srcp] |
| 4485 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 4486 | emit_mov_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp] |
| 4487 | } |
| 5225 | 4488 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5226 | | emit_movsx_r64_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4489 | { |
| 4490 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4491 | emit_movsx_r64_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4492 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4493 | emit_movsx_r64_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4494 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4495 | emit_movsxd_r64_r32(&dst, dstreg, srcp.value); // movsxd dstreg,srcp |
| 4496 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 4497 | emit_mov_r64_r64(&dst, dstreg, srcp.value); // mov dstreg,srcp |
| 4498 | } |
| 5227 | 4499 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5228 | 4500 | } |
| 5229 | 4501 | return dst; |
| r2821 | r2822 | |
| 5231 | 4503 | |
| 5232 | 4504 | |
| 5233 | 4505 | /*------------------------------------------------- |
| 5234 | | op_sext4 - process a SEXT4 opcode |
| 4506 | op_roland - process an ROLAND opcode |
| 5235 | 4507 | -------------------------------------------------*/ |
| 5236 | 4508 | |
| 5237 | | static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4509 | static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5238 | 4510 | { |
| 5239 | | drcuml_parameter dstp, srcp; |
| 5240 | | int dstreg; |
| 5241 | | |
| 5242 | | /* validate instruction */ |
| 5243 | | assert(inst->size == 8); |
| 5244 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5245 | | |
| 5246 | | /* normalize parameters */ |
| 5247 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5248 | | |
| 5249 | | /* degenerate cases -- convert to a move */ |
| 5250 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5251 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); |
| 5252 | | |
| 5253 | | /* pick a target register for the general case */ |
| 5254 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5255 | | |
| 5256 | | /* 64-bit form */ |
| 5257 | | if (inst->size == 8) |
| 5258 | | { |
| 5259 | | /* general case */ |
| 5260 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5261 | | emit_movsxd_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // movsxd dstreg,[srcp] |
| 5262 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5263 | | emit_movsxd_r64_r32(&dst, dstreg, srcp.value); // movsxd dstreg,srcp |
| 5264 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5265 | | } |
| 5266 | | return dst; |
| 5267 | | } |
| 5268 | | |
| 5269 | | |
| 5270 | | /*------------------------------------------------- |
| 5271 | | op_xtract - process an XTRACT opcode |
| 5272 | | -------------------------------------------------*/ |
| 5273 | | |
| 5274 | | static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5275 | | { |
| 5276 | 4511 | drcuml_parameter dstp, srcp, shiftp, maskp; |
| 5277 | 4512 | int dstreg; |
| 5278 | 4513 | |
| r2821 | r2822 | |
| 5333 | 4568 | |
| 5334 | 4569 | |
| 5335 | 4570 | /*------------------------------------------------- |
| 5336 | | op_insert - process an INSERT opcode |
| 4571 | op_rolins - process an ROLINS opcode |
| 5337 | 4572 | -------------------------------------------------*/ |
| 5338 | 4573 | |
| 5339 | | static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4574 | static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5340 | 4575 | { |
| 5341 | 4576 | drcuml_parameter dstp, srcp, shiftp, maskp; |
| 5342 | 4577 | int dstreg; |
| r2821 | r2822 | |
| 5753 | 4988 | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 5754 | 4989 | if (compute_hi) |
| 5755 | 4990 | emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx |
| 4991 | |
| 4992 | /* compute flags */ |
| 4993 | if (inst->condflags != 0) |
| 4994 | { |
| 4995 | if (compute_hi) |
| 4996 | { |
| 4997 | if (inst->condflags == DRCUML_FLAG_Z) |
| 4998 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 4999 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5000 | emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx |
| 5001 | else |
| 5002 | { |
| 5003 | emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax |
| 5004 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5005 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5006 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5007 | } |
| 5008 | } |
| 5009 | else |
| 5010 | emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax |
| 5011 | } |
| 5756 | 5012 | } |
| 5757 | 5013 | |
| 5758 | 5014 | /* 64-bit form */ |
| r2821 | r2822 | |
| 5772 | 5028 | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax |
| 5773 | 5029 | if (compute_hi) |
| 5774 | 5030 | emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx |
| 5031 | |
| 5032 | /* compute flags */ |
| 5033 | if (inst->condflags != 0) |
| 5034 | { |
| 5035 | if (compute_hi) |
| 5036 | { |
| 5037 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5038 | emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax |
| 5039 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5040 | emit_test_r64_r64(&dst, REG_RDX, REG_RDX); // test rdx,rdx |
| 5041 | else |
| 5042 | { |
| 5043 | emit_mov_r32_r32(&dst, REG_ECX, REG_EAX); // mov ecx,eax |
| 5044 | emit_shr_r64_imm(&dst, REG_RAX, 32); // shr rax,32 |
| 5045 | emit_or_r64_r64(&dst, REG_RDX, REG_RCX); // or rdx,rcx |
| 5046 | emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax |
| 5047 | } |
| 5048 | } |
| 5049 | else |
| 5050 | emit_test_r64_r64(&dst, REG_RAX, REG_RAX); // test rax,rax |
| 5051 | } |
| 5775 | 5052 | } |
| 5776 | 5053 | return dst; |
| 5777 | 5054 | } |
| r2821 | r2822 | |
| 5850 | 5127 | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 5851 | 5128 | emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx |
| 5852 | 5129 | } |
| 5130 | |
| 5131 | /* compute flags */ |
| 5132 | if (inst->condflags != 0) |
| 5133 | { |
| 5134 | if (compute_hi) |
| 5135 | { |
| 5136 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5137 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5138 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5139 | emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx |
| 5140 | else |
| 5141 | { |
| 5142 | emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax |
| 5143 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5144 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5145 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5146 | } |
| 5147 | } |
| 5148 | else |
| 5149 | emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax |
| 5150 | } |
| 5853 | 5151 | } |
| 5854 | 5152 | |
| 5855 | 5153 | /* 64-bit form */ |
| r2821 | r2822 | |
| 5892 | 5190 | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax |
| 5893 | 5191 | emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx |
| 5894 | 5192 | } |
| 5193 | |
| 5194 | /* compute flags */ |
| 5195 | if (inst->condflags != 0) |
| 5196 | { |
| 5197 | if (compute_hi) |
| 5198 | { |
| 5199 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5200 | emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax |
| 5201 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5202 | emit_test_r64_r64(&dst, REG_RDX, REG_RDX); // test rdx,rdx |
| 5203 | else |
| 5204 | { |
| 5205 | emit_mov_r32_r32(&dst, REG_ECX, REG_EAX); // mov ecx,eax |
| 5206 | emit_shr_r64_imm(&dst, REG_RAX, 32); // shr rax,32 |
| 5207 | emit_or_r64_r64(&dst, REG_RDX, REG_RCX); // or rdx,rcx |
| 5208 | emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax |
| 5209 | } |
| 5210 | } |
| 5211 | else |
| 5212 | emit_test_r64_r64(&dst, REG_RAX, REG_RAX); // test rax,rax |
| 5213 | } |
| 5895 | 5214 | } |
| 5896 | 5215 | return dst; |
| 5897 | 5216 | } |
| r2821 | r2822 | |
| 6945 | 6264 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 6946 | 6265 | |
| 6947 | 6266 | /* normalize parameters */ |
| 6948 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 6267 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &addrp, PTYPE_MRI, &spacep, PTYPE_I); |
| 6949 | 6268 | |
| 6950 | 6269 | /* set up a call to the read dword/qword handler */ |
| 6951 | 6270 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| r2821 | r2822 | |
| 6986 | 6305 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 6987 | 6306 | |
| 6988 | 6307 | /* normalize parameters */ |
| 6989 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MF); |
| 6308 | param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MF, &spacep, PTYPE_I); |
| 6990 | 6309 | |
| 6991 | 6310 | /* general case */ |
| 6992 | 6311 | emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp |
| r2821 | r2822 | |
| 7061 | 6380 | |
| 7062 | 6381 | |
| 7063 | 6382 | /*------------------------------------------------- |
| 7064 | | op_ftoi4 - process a FTOI4 opcode |
| 6383 | op_ftoint - process a FTOINT opcode |
| 7065 | 6384 | -------------------------------------------------*/ |
| 7066 | 6385 | |
| 7067 | | static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6386 | static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7068 | 6387 | { |
| 7069 | | drcuml_parameter dstp, srcp; |
| 6388 | drcuml_parameter dstp, srcp, sizep, roundp; |
| 7070 | 6389 | int dstreg; |
| 7071 | 6390 | |
| 7072 | 6391 | /* validate instruction */ |
| r2821 | r2822 | |
| 7074 | 6393 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7075 | 6394 | |
| 7076 | 6395 | /* normalize parameters */ |
| 7077 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 6396 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF, &sizep, PTYPE_I, &roundp, PTYPE_I); |
| 7078 | 6397 | |
| 7079 | 6398 | /* pick a target register for the general case */ |
| 7080 | 6399 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 7081 | 6400 | |
| 7082 | | /* 32-bit form */ |
| 7083 | | if (inst->size == 4) |
| 6401 | /* set rounding mode if necessary */ |
| 6402 | if (roundp.value != DRCUML_FMOD_DEFAULT && roundp.value != DRCUML_FMOD_TRUNC) |
| 7084 | 6403 | { |
| 7085 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7086 | | emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] |
| 7087 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7088 | | emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp |
| 6404 | emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave] |
| 6405 | emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[roundp.value])); // ldmxcsr fpcontrol[mode] |
| 7089 | 6406 | } |
| 7090 | 6407 | |
| 7091 | | /* 64-bit form */ |
| 7092 | | else if (inst->size == 8) |
| 7093 | | { |
| 7094 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7095 | | emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] |
| 7096 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7097 | | emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp |
| 7098 | | } |
| 7099 | | |
| 7100 | | /* general case */ |
| 7101 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7102 | | return dst; |
| 7103 | | } |
| 7104 | | |
| 7105 | | |
| 7106 | | /*------------------------------------------------- |
| 7107 | | op_ftoi4t - process a FTOI4T opcode |
| 7108 | | -------------------------------------------------*/ |
| 7109 | | |
| 7110 | | static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7111 | | { |
| 7112 | | drcuml_parameter dstp, srcp; |
| 7113 | | int dstreg; |
| 7114 | | |
| 7115 | | /* validate instruction */ |
| 7116 | | assert(inst->size == 4 || inst->size == 8); |
| 7117 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7118 | | |
| 7119 | | /* normalize parameters */ |
| 7120 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7121 | | |
| 7122 | | /* pick a target register for the general case */ |
| 7123 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 7124 | | |
| 7125 | 6408 | /* 32-bit form */ |
| 7126 | 6409 | if (inst->size == 4) |
| 7127 | 6410 | { |
| 7128 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7129 | | emit_cvttss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] |
| 7130 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7131 | | emit_cvttss2si_r32_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp |
| 6411 | /* 32-bit integer source */ |
| 6412 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 6413 | { |
| 6414 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6415 | { |
| 6416 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6417 | emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] |
| 6418 | else |
| 6419 | emit_cvttss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] |
| 6420 | } |
| 6421 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 6422 | { |
| 6423 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6424 | emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp |
| 6425 | else |
| 6426 | emit_cvttss2si_r32_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp |
| 6427 | } |
| 6428 | } |
| 6429 | |
| 6430 | /* 64-bit integer source */ |
| 6431 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 6432 | { |
| 6433 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6434 | { |
| 6435 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6436 | emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] |
| 6437 | else |
| 6438 | emit_cvttss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] |
| 6439 | } |
| 6440 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 6441 | { |
| 6442 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6443 | emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp |
| 6444 | else |
| 6445 | emit_cvttss2si_r64_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp |
| 6446 | } |
| 6447 | } |
| 7132 | 6448 | } |
| 7133 | 6449 | |
| 7134 | 6450 | /* 64-bit form */ |
| 7135 | 6451 | else if (inst->size == 8) |
| 7136 | 6452 | { |
| 7137 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7138 | | emit_cvttsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] |
| 7139 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7140 | | emit_cvttsd2si_r32_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp |
| 7141 | | } |
| 7142 | | |
| 7143 | | /* general case */ |
| 7144 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7145 | | return dst; |
| 7146 | | } |
| 7147 | | |
| 7148 | | |
| 7149 | | /*------------------------------------------------- |
| 7150 | | op_ftoi4x - process a FTOI4R/F/C opcode |
| 7151 | | -------------------------------------------------*/ |
| 7152 | | |
| 7153 | | static x86code *op_ftoi4x(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, int mode) |
| 7154 | | { |
| 7155 | | drcuml_parameter dstp, srcp; |
| 7156 | | int dstreg; |
| 7157 | | |
| 7158 | | /* validate instruction */ |
| 7159 | | assert(inst->size == 4 || inst->size == 8); |
| 7160 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7161 | | |
| 7162 | | /* normalize parameters */ |
| 7163 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7164 | | |
| 7165 | | /* pick a target register for the general case */ |
| 7166 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 7167 | | |
| 7168 | | /* non-SSE4.1 case */ |
| 7169 | | if (!drcbe->sse41 || inst->size == 8) |
| 7170 | | { |
| 7171 | | /* save and set the control word */ |
| 7172 | | emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave] |
| 7173 | | emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[mode])); // ldmxcsr fpcontrol[mode] |
| 7174 | | |
| 7175 | | /* 32-bit form */ |
| 7176 | | if (inst->size == 4) |
| 6453 | /* 32-bit integer source */ |
| 6454 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 7177 | 6455 | { |
| 7178 | 6456 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7179 | | emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] |
| 6457 | { |
| 6458 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6459 | emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] |
| 6460 | else |
| 6461 | emit_cvttsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] |
| 6462 | } |
| 7180 | 6463 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7181 | | emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp |
| 6464 | { |
| 6465 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6466 | emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp |
| 6467 | else |
| 6468 | emit_cvttsd2si_r32_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp |
| 6469 | } |
| 7182 | 6470 | } |
| 7183 | 6471 | |
| 7184 | | /* 64-bit form */ |
| 7185 | | else if (inst->size == 8) |
| 6472 | /* 64-bit integer source */ |
| 6473 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 7186 | 6474 | { |
| 7187 | 6475 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7188 | | emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] |
| 6476 | { |
| 6477 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6478 | emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] |
| 6479 | else |
| 6480 | emit_cvttsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] |
| 6481 | } |
| 7189 | 6482 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7190 | | emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp |
| 6483 | { |
| 6484 | if (roundp.value != DRCUML_FMOD_TRUNC) |
| 6485 | emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp |
| 6486 | else |
| 6487 | emit_cvttsd2si_r64_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp |
| 6488 | } |
| 7191 | 6489 | } |
| 7192 | | |
| 7193 | | /* restore control word and proceed */ |
| 7194 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7195 | | emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave] |
| 7196 | 6490 | } |
| 7197 | 6491 | |
| 7198 | | /* SSE4.1 case */ |
| 6492 | /* general case */ |
| 6493 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 6494 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7199 | 6495 | else |
| 7200 | | { |
| 7201 | | /* 32-bit form */ |
| 7202 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7203 | | emit_roundss_r128_m32_imm(&dst, REG_XMM0, MABS(drcbe, srcp.value), fprnd_map[mode]); |
| 7204 | | // roundss xmm0,[srcp],mode |
| 7205 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7206 | | emit_roundss_r128_r128_imm(&dst, REG_XMM0, srcp.value, fprnd_map[mode]); // roundss xmm0,srcp,mode |
| 6496 | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7207 | 6497 | |
| 7208 | | /* store to the destination */ |
| 7209 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7210 | | emit_movd_m32_r128(&dst, MABS(drcbe, dstp.value), REG_XMM0); // movd [dstp],xmm0 |
| 7211 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7212 | | emit_movd_r32_r128(&dst, dstp.value, REG_XMM0); // movd dstp,xmm0 |
| 7213 | | } |
| 7214 | | return dst; |
| 6498 | /* restore rounding mode */ |
| 6499 | if (roundp.value != DRCUML_FMOD_DEFAULT && roundp.value != DRCUML_FMOD_TRUNC) |
| 6500 | emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave] |
| 7215 | 6501 | |
| 6502 | return dst; |
| 7216 | 6503 | } |
| 7217 | 6504 | |
| 7218 | | static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7219 | | { |
| 7220 | | return op_ftoi4x(drcbe, dst, inst, DRCUML_FMOD_ROUND); |
| 7221 | | } |
| 7222 | 6505 | |
| 7223 | | static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7224 | | { |
| 7225 | | return op_ftoi4x(drcbe, dst, inst, DRCUML_FMOD_FLOOR); |
| 7226 | | } |
| 7227 | | |
| 7228 | | static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7229 | | { |
| 7230 | | return op_ftoi4x(drcbe, dst, inst, DRCUML_FMOD_CEIL); |
| 7231 | | } |
| 7232 | | |
| 7233 | | |
| 7234 | 6506 | /*------------------------------------------------- |
| 7235 | | op_ftoi8 - process a FTOI8 opcode |
| 6507 | op_ffrint - process a FFRINT opcode |
| 7236 | 6508 | -------------------------------------------------*/ |
| 7237 | 6509 | |
| 7238 | | static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6510 | static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7239 | 6511 | { |
| 7240 | | drcuml_parameter dstp, srcp; |
| 6512 | drcuml_parameter dstp, srcp, sizep; |
| 7241 | 6513 | int dstreg; |
| 7242 | 6514 | |
| 7243 | 6515 | /* validate instruction */ |
| r2821 | r2822 | |
| 7245 | 6517 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7246 | 6518 | |
| 7247 | 6519 | /* normalize parameters */ |
| 7248 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 6520 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI, &sizep, PTYPE_I); |
| 7249 | 6521 | |
| 7250 | 6522 | /* pick a target register for the general case */ |
| 7251 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 6523 | dstreg = param_select_register(REG_XMM0, &dstp, NULL); |
| 7252 | 6524 | |
| 7253 | 6525 | /* 32-bit form */ |
| 7254 | 6526 | if (inst->size == 4) |
| 7255 | 6527 | { |
| 7256 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7257 | | emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] |
| 7258 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7259 | | emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp |
| 7260 | | } |
| 6528 | /* 32-bit integer source */ |
| 6529 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 6530 | { |
| 6531 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6532 | emit_cvtsi2ss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] |
| 6533 | else |
| 6534 | { |
| 6535 | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 6536 | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 6537 | emit_cvtsi2ss_r128_r32(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg |
| 6538 | } |
| 6539 | } |
| 7261 | 6540 | |
| 7262 | | /* 64-bit form */ |
| 7263 | | else if (inst->size == 8) |
| 7264 | | { |
| 7265 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7266 | | emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] |
| 7267 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7268 | | emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp |
| 6541 | /* 64-bit integer source */ |
| 6542 | else |
| 6543 | { |
| 6544 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6545 | emit_cvtsi2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] |
| 6546 | else |
| 6547 | { |
| 6548 | int srcreg = param_select_register(REG_RAX, &srcp, NULL); |
| 6549 | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 6550 | emit_cvtsi2ss_r128_r64(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg |
| 6551 | } |
| 6552 | } |
| 6553 | emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg |
| 7269 | 6554 | } |
| 7270 | 6555 | |
| 7271 | | /* general case */ |
| 7272 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7273 | | return dst; |
| 7274 | | } |
| 7275 | | |
| 7276 | | |
| 7277 | | /*------------------------------------------------- |
| 7278 | | op_ftoi8t - process a FTOI8T opcode |
| 7279 | | -------------------------------------------------*/ |
| 7280 | | |
| 7281 | | static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7282 | | { |
| 7283 | | drcuml_parameter dstp, srcp; |
| 7284 | | int dstreg; |
| 7285 | | |
| 7286 | | /* validate instruction */ |
| 7287 | | assert(inst->size == 4 || inst->size == 8); |
| 7288 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7289 | | |
| 7290 | | /* normalize parameters */ |
| 7291 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7292 | | |
| 7293 | | /* pick a target register for the general case */ |
| 7294 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 7295 | | |
| 7296 | | /* 32-bit form */ |
| 7297 | | if (inst->size == 4) |
| 7298 | | { |
| 7299 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7300 | | emit_cvttss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] |
| 7301 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7302 | | emit_cvttss2si_r64_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp |
| 7303 | | } |
| 7304 | | |
| 7305 | 6556 | /* 64-bit form */ |
| 7306 | 6557 | else if (inst->size == 8) |
| 7307 | 6558 | { |
| 7308 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7309 | | emit_cvttsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] |
| 7310 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7311 | | emit_cvttsd2si_r64_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp |
| 7312 | | } |
| 7313 | | |
| 7314 | | /* general case */ |
| 7315 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7316 | | return dst; |
| 7317 | | } |
| 7318 | | |
| 7319 | | |
| 7320 | | /*------------------------------------------------- |
| 7321 | | op_ftoi8x - process a FTOI8R/F/C opcode |
| 7322 | | -------------------------------------------------*/ |
| 7323 | | |
| 7324 | | static x86code *op_ftoi8x(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, int mode) |
| 7325 | | { |
| 7326 | | drcuml_parameter dstp, srcp; |
| 7327 | | int dstreg; |
| 7328 | | |
| 7329 | | /* validate instruction */ |
| 7330 | | assert(inst->size == 4 || inst->size == 8); |
| 7331 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7332 | | |
| 7333 | | /* normalize parameters */ |
| 7334 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7335 | | |
| 7336 | | /* pick a target register for the general case */ |
| 7337 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 7338 | | |
| 7339 | | /* non-SSE4.1 case */ |
| 7340 | | if (!drcbe->sse41 || inst->size == 4) |
| 7341 | | { |
| 7342 | | /* save and set the control word */ |
| 7343 | | emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave] |
| 7344 | | emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[mode])); // ldmxcsr fpcontrol[mode] |
| 7345 | | |
| 7346 | | /* 32-bit form */ |
| 7347 | | if (inst->size == 4) |
| 6559 | /* 32-bit integer source */ |
| 6560 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 7348 | 6561 | { |
| 7349 | 6562 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7350 | | emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] |
| 7351 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7352 | | emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp |
| 6563 | emit_cvtsi2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] |
| 6564 | else |
| 6565 | { |
| 6566 | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 6567 | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 6568 | emit_cvtsi2sd_r128_r32(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg |
| 6569 | } |
| 7353 | 6570 | } |
| 7354 | 6571 | |
| 7355 | | /* 64-bit form */ |
| 7356 | | else if (inst->size == 8) |
| 6572 | /* 64-bit integer source */ |
| 6573 | else |
| 7357 | 6574 | { |
| 7358 | 6575 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7359 | | emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] |
| 7360 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7361 | | emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp |
| 6576 | emit_cvtsi2sd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] |
| 6577 | else |
| 6578 | { |
| 6579 | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 6580 | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 6581 | emit_cvtsi2sd_r128_r64(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg |
| 6582 | } |
| 7362 | 6583 | } |
| 7363 | | |
| 7364 | | /* restore control word and proceed */ |
| 7365 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 7366 | | emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave] |
| 6584 | emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg |
| 7367 | 6585 | } |
| 7368 | | |
| 7369 | | /* SSE4.1 case */ |
| 7370 | | else |
| 7371 | | { |
| 7372 | | /* 64-bit form */ |
| 7373 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7374 | | emit_roundsd_r128_m64_imm(&dst, REG_XMM0, MABS(drcbe, srcp.value), fprnd_map[mode]); |
| 7375 | | // roundsd xmm0,[srcp],mode |
| 7376 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7377 | | emit_roundsd_r128_r128_imm(&dst, REG_XMM0, srcp.value, fprnd_map[mode]); // roundsd xmm0,srcp,mode |
| 7378 | | |
| 7379 | | /* store to the destination */ |
| 7380 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7381 | | emit_movq_m64_r128(&dst, MABS(drcbe, dstp.value), REG_XMM0); // movq [dstp],xmm0 |
| 7382 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7383 | | emit_movq_r64_r128(&dst, dstp.value, REG_XMM0); // movq dstp,xmm0 |
| 7384 | | } |
| 7385 | 6586 | return dst; |
| 7386 | | |
| 7387 | 6587 | } |
| 7388 | 6588 | |
| 7389 | | static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7390 | | { |
| 7391 | | return op_ftoi8x(drcbe, dst, inst, DRCUML_FMOD_ROUND); |
| 7392 | | } |
| 7393 | 6589 | |
| 7394 | | static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7395 | | { |
| 7396 | | return op_ftoi8x(drcbe, dst, inst, DRCUML_FMOD_FLOOR); |
| 7397 | | } |
| 7398 | | |
| 7399 | | static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7400 | | { |
| 7401 | | return op_ftoi8x(drcbe, dst, inst, DRCUML_FMOD_CEIL); |
| 7402 | | } |
| 7403 | | |
| 7404 | | |
| 7405 | 6590 | /*------------------------------------------------- |
| 7406 | | op_ffrfs - process a FFRFS opcode |
| 6591 | op_ffrflt - process a FFRFLT opcode |
| 7407 | 6592 | -------------------------------------------------*/ |
| 7408 | 6593 | |
| 7409 | | static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6594 | static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7410 | 6595 | { |
| 7411 | | drcuml_parameter dstp, srcp; |
| 6596 | drcuml_parameter dstp, srcp, sizep; |
| 7412 | 6597 | int dstreg; |
| 7413 | 6598 | |
| 7414 | 6599 | /* validate instruction */ |
| 7415 | | assert(inst->size == 8); |
| 7416 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7417 | | |
| 7418 | | /* normalize parameters */ |
| 7419 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); |
| 7420 | | |
| 7421 | | /* pick a target register for the general case */ |
| 7422 | | dstreg = param_select_register(REG_XMM0, &dstp, NULL); |
| 7423 | | |
| 7424 | | /* general case */ |
| 7425 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7426 | | emit_cvtss2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2sd dstreg,[srcp] |
| 7427 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7428 | | emit_cvtss2sd_r128_r128(&dst, dstreg, srcp.value); // cvtss2sd dstreg,srcp |
| 7429 | | emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg |
| 7430 | | |
| 7431 | | return dst; |
| 7432 | | } |
| 7433 | | |
| 7434 | | |
| 7435 | | /*------------------------------------------------- |
| 7436 | | op_ffrfd - process a FFRFD opcode |
| 7437 | | -------------------------------------------------*/ |
| 7438 | | |
| 7439 | | static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7440 | | { |
| 7441 | | drcuml_parameter dstp, srcp; |
| 7442 | | int dstreg; |
| 7443 | | |
| 7444 | | /* validate instruction */ |
| 7445 | | assert(inst->size == 4); |
| 7446 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7447 | | |
| 7448 | | /* normalize parameters */ |
| 7449 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); |
| 7450 | | |
| 7451 | | /* pick a target register for the general case */ |
| 7452 | | dstreg = param_select_register(REG_XMM0, &dstp, NULL); |
| 7453 | | |
| 7454 | | /* general case */ |
| 7455 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7456 | | emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp] |
| 7457 | | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 7458 | | emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp |
| 7459 | | emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg |
| 7460 | | |
| 7461 | | return dst; |
| 7462 | | } |
| 7463 | | |
| 7464 | | |
| 7465 | | /*------------------------------------------------- |
| 7466 | | op_ffri4 - process a FFRI4 opcode |
| 7467 | | -------------------------------------------------*/ |
| 7468 | | |
| 7469 | | static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7470 | | { |
| 7471 | | drcuml_parameter dstp, srcp; |
| 7472 | | int dstreg; |
| 7473 | | |
| 7474 | | /* validate instruction */ |
| 7475 | 6600 | assert(inst->size == 4 || inst->size == 8); |
| 7476 | 6601 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7477 | 6602 | |
| 7478 | 6603 | /* normalize parameters */ |
| 7479 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); |
| 6604 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF, &sizep, PTYPE_I); |
| 7480 | 6605 | |
| 7481 | 6606 | /* pick a target register for the general case */ |
| 7482 | 6607 | dstreg = param_select_register(REG_XMM0, &dstp, NULL); |
| 7483 | 6608 | |
| 7484 | | /* 32-bit form */ |
| 7485 | | if (inst->size == 4) |
| 6609 | /* single-to-double */ |
| 6610 | if (inst->size == 8 && sizep.value == DRCUML_SIZE_DWORD) |
| 7486 | 6611 | { |
| 7487 | 6612 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7488 | | emit_cvtsi2ss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] |
| 7489 | | else |
| 7490 | | { |
| 7491 | | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 7492 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 7493 | | emit_cvtsi2ss_r128_r32(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg |
| 7494 | | } |
| 7495 | | emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg |
| 6613 | emit_cvtss2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2sd dstreg,[srcp] |
| 6614 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 6615 | emit_cvtss2sd_r128_r128(&dst, dstreg, srcp.value); // cvtss2sd dstreg,srcp |
| 6616 | emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg |
| 7496 | 6617 | } |
| 7497 | 6618 | |
| 7498 | | /* 64-bit form */ |
| 7499 | | else if (inst->size == 8) |
| 6619 | /* double-to-single */ |
| 6620 | else if (inst->size == 4 && sizep.value == DRCUML_SIZE_QWORD) |
| 7500 | 6621 | { |
| 7501 | 6622 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7502 | | emit_cvtsi2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] |
| 7503 | | else |
| 7504 | | { |
| 7505 | | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 7506 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 7507 | | emit_cvtsi2sd_r128_r32(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg |
| 7508 | | } |
| 7509 | | emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg |
| 6623 | emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp] |
| 6624 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 6625 | emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp |
| 6626 | emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg |
| 7510 | 6627 | } |
| 7511 | 6628 | return dst; |
| 7512 | 6629 | } |
| 7513 | 6630 | |
| 7514 | 6631 | |
| 7515 | 6632 | /*------------------------------------------------- |
| 7516 | | op_ffri8 - process a FFRI8 opcode |
| 6633 | op_frnds - process a FRNDS opcode |
| 7517 | 6634 | -------------------------------------------------*/ |
| 7518 | 6635 | |
| 7519 | | static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6636 | static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7520 | 6637 | { |
| 7521 | 6638 | drcuml_parameter dstp, srcp; |
| 7522 | 6639 | int dstreg; |
| 7523 | 6640 | |
| 7524 | 6641 | /* validate instruction */ |
| 7525 | | assert(inst->size == 4 || inst->size == 8); |
| 6642 | assert(inst->size == 8); |
| 7526 | 6643 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7527 | 6644 | |
| 7528 | 6645 | /* normalize parameters */ |
| r2821 | r2822 | |
| 7531 | 6648 | /* pick a target register for the general case */ |
| 7532 | 6649 | dstreg = param_select_register(REG_XMM0, &dstp, NULL); |
| 7533 | 6650 | |
| 7534 | | /* 32-bit form */ |
| 7535 | | if (inst->size == 4) |
| 7536 | | { |
| 7537 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7538 | | emit_cvtsi2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] |
| 7539 | | else |
| 7540 | | { |
| 7541 | | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 7542 | | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 7543 | | emit_cvtsi2ss_r128_r64(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg |
| 7544 | | } |
| 7545 | | emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg |
| 7546 | | } |
| 7547 | | |
| 7548 | 6651 | /* 64-bit form */ |
| 7549 | | else if (inst->size == 8) |
| 7550 | | { |
| 7551 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7552 | | emit_cvtsi2sd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] |
| 7553 | | else |
| 7554 | | { |
| 7555 | | int srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 7556 | | emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 7557 | | emit_cvtsi2sd_r128_r64(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg |
| 7558 | | } |
| 7559 | | emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg |
| 7560 | | } |
| 6652 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6653 | emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp] |
| 6654 | else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) |
| 6655 | emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp |
| 6656 | emit_cvtss2sd_r128_r128(&dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg |
| 6657 | emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg |
| 7561 | 6658 | return dst; |
| 7562 | 6659 | } |
| 7563 | 6660 | |
src/emu/cpu/powerpc/ppcdrco.c
| r2821 | r2822 | |
| 1 | | /* |
| 2 | | PowerPC 4xx/6xx Dynamic Recompiler for x86 |
| 3 | | |
| 4 | | Written by Ville Linde |
| 5 | | */ |
| 6 | | |
| 7 | | #include "debugger.h" |
| 8 | | #include "ppc.h" |
| 9 | | #include "cpu/x86drc.h" |
| 10 | | |
| 11 | | |
| 12 | | #define PPC_DRC |
| 13 | | #define LOG_CODE (0) |
| 14 | | |
| 15 | | #define CACHE_SIZE (16 * 1024 * 1024) |
| 16 | | #define MAX_INSTRUCTIONS 512 |
| 17 | | |
| 18 | | |
| 19 | | #if (HAS_PPC603) |
| 20 | | static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int)); |
| 21 | | static void ppcdrc603_exit(void); |
| 22 | | #endif |
| 23 | | #if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240 || HAS_PPC604) |
| 24 | | static void ppcdrc603_reset(void); |
| 25 | | static int ppcdrc603_execute(int cycles); |
| 26 | | static void ppcdrc603_set_irq_line(int irqline, int state); |
| 27 | | #endif |
| 28 | | #if (HAS_PPC602) |
| 29 | | static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int)); |
| 30 | | static void ppcdrc602_exit(void); |
| 31 | | static void ppcdrc602_reset(void); |
| 32 | | static int ppcdrc602_execute(int cycles); |
| 33 | | static void ppcdrc602_set_irq_line(int irqline, int state); |
| 34 | | #endif |
| 35 | | #if (HAS_PPC403) |
| 36 | | static UINT8 ppc403_spu_r(UINT32 a); |
| 37 | | static void ppc403_spu_w(UINT32 a, UINT8 d); |
| 38 | | static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int)); |
| 39 | | static void ppcdrc403_exit(void); |
| 40 | | static void ppcdrc403_reset(void); |
| 41 | | static int ppcdrc403_execute(int cycles); |
| 42 | | static void ppcdrc403_set_irq_line(int irqline, int state); |
| 43 | | #endif |
| 44 | | |
| 45 | | static void ppcdrc_init(void); |
| 46 | | static void ppcdrc_reset(drc_core *drc); |
| 47 | | static void ppcdrc_recompile(drc_core *drc); |
| 48 | | static void ppcdrc_entrygen(drc_core *drc); |
| 49 | | |
| 50 | | #define RD ((op >> 21) & 0x1F) |
| 51 | | #define RT ((op >> 21) & 0x1f) |
| 52 | | #define RS ((op >> 21) & 0x1f) |
| 53 | | #define RA ((op >> 16) & 0x1f) |
| 54 | | #define RB ((op >> 11) & 0x1f) |
| 55 | | #define RC ((op >> 6) & 0x1f) |
| 56 | | |
| 57 | | #define MB ((op >> 6) & 0x1f) |
| 58 | | #define ME ((op >> 1) & 0x1f) |
| 59 | | #define SH ((op >> 11) & 0x1f) |
| 60 | | #define BO ((op >> 21) & 0x1f) |
| 61 | | #define BI ((op >> 16) & 0x1f) |
| 62 | | #define CRFD ((op >> 23) & 0x7) |
| 63 | | #define CRFA ((op >> 18) & 0x7) |
| 64 | | #define FXM ((op >> 12) & 0xff) |
| 65 | | #define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) |
| 66 | | |
| 67 | | #define SIMM16 (INT32)(INT16)(op & 0xffff) |
| 68 | | #define UIMM16 (UINT32)(op & 0xffff) |
| 69 | | |
| 70 | | #define RCBIT (op & 0x1) |
| 71 | | #define OEBIT (op & 0x400) |
| 72 | | #define AABIT (op & 0x2) |
| 73 | | #define LKBIT (op & 0x1) |
| 74 | | |
| 75 | | #define REG(x) (ppc.r[x]) |
| 76 | | #define LR (ppc.lr) |
| 77 | | #define CTR (ppc.ctr) |
| 78 | | #define XER (ppc.xer) |
| 79 | | #define CR(x) (ppc.cr[x]) |
| 80 | | #define MSR (ppc.msr) |
| 81 | | #define SRR0 (ppc.srr0) |
| 82 | | #define SRR1 (ppc.srr1) |
| 83 | | #define SRR2 (ppc.srr2) |
| 84 | | #define SRR3 (ppc.srr3) |
| 85 | | #define EVPR (ppc.evpr) |
| 86 | | #define EXIER (ppc.exier) |
| 87 | | #define EXISR (ppc.exisr) |
| 88 | | #define DEC (ppc.dec) |
| 89 | | |
| 90 | | |
| 91 | | // Stuff added for the 6xx |
| 92 | | #define FPR(x) (ppc.fpr[x]) |
| 93 | | #define FM ((op >> 17) & 0xFF) |
| 94 | | #define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) |
| 95 | | |
| 96 | | |
| 97 | | #define CHECK_SUPERVISOR() \ |
| 98 | | if((ppc.msr & 0x4000) != 0){ \ |
| 99 | | } |
| 100 | | |
| 101 | | #define CHECK_FPU_AVAILABLE() \ |
| 102 | | if((ppc.msr & 0x2000) == 0){ \ |
| 103 | | } |
| 104 | | |
| 105 | | #if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_PPC604||HAS_MPC8240) |
| 106 | | static UINT32 ppc_field_xlat[256]; |
| 107 | | #endif |
| 108 | | |
| 109 | | |
| 110 | | |
| 111 | | #define FPSCR_FX 0x80000000 |
| 112 | | #define FPSCR_FEX 0x40000000 |
| 113 | | #define FPSCR_VX 0x20000000 |
| 114 | | #define FPSCR_OX 0x10000000 |
| 115 | | #define FPSCR_UX 0x08000000 |
| 116 | | #define FPSCR_ZX 0x04000000 |
| 117 | | #define FPSCR_XX 0x02000000 |
| 118 | | |
| 119 | | |
| 120 | | |
| 121 | | #define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) |
| 122 | | #define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) |
| 123 | | #define _BIT(n) (1 << (n)) |
| 124 | | #define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) |
| 125 | | #define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) |
| 126 | | #define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) |
| 127 | | #define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) |
| 128 | | #define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) |
| 129 | | |
| 130 | | #define XER_SO 0x80000000 |
| 131 | | #define XER_OV 0x40000000 |
| 132 | | #define XER_CA 0x20000000 |
| 133 | | |
| 134 | | #define MSR_AP 0x00800000 /* Access privilege state (PPC602) */ |
| 135 | | #define MSR_SA 0x00400000 /* Supervisor access mode (PPC602) */ |
| 136 | | #define MSR_POW 0x00040000 /* Power Management Enable */ |
| 137 | | #define MSR_WE 0x00040000 |
| 138 | | #define MSR_CE 0x00020000 |
| 139 | | #define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ |
| 140 | | #define MSR_EE 0x00008000 /* External Interrupt Enable */ |
| 141 | | #define MSR_PR 0x00004000 /* Problem State */ |
| 142 | | #define MSR_FP 0x00002000 /* Floating Point Available */ |
| 143 | | #define MSR_ME 0x00001000 /* Machine Check Enable */ |
| 144 | | #define MSR_FE0 0x00000800 |
| 145 | | #define MSR_SE 0x00000400 /* Single Step Trace Enable */ |
| 146 | | #define MSR_BE 0x00000200 /* Branch Trace Enable */ |
| 147 | | #define MSR_DE 0x00000200 |
| 148 | | #define MSR_FE1 0x00000100 |
| 149 | | #define MSR_IP 0x00000040 /* Interrupt Prefix */ |
| 150 | | #define MSR_IR 0x00000020 /* Instruction Relocate */ |
| 151 | | #define MSR_DR 0x00000010 /* Data Relocate */ |
| 152 | | #define MSR_PE 0x00000008 |
| 153 | | #define MSR_PX 0x00000004 |
| 154 | | #define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ |
| 155 | | #define MSR_LE 0x00000001 |
| 156 | | |
| 157 | | #define TSR_ENW 0x80000000 |
| 158 | | #define TSR_WIS 0x40000000 |
| 159 | | |
| 160 | | #define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) |
| 161 | | #define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) |
| 162 | | |
| 163 | | typedef struct { |
| 164 | | UINT32 cr; |
| 165 | | UINT32 da; |
| 166 | | UINT32 sa; |
| 167 | | UINT32 ct; |
| 168 | | UINT32 cc; |
| 169 | | } DMA_REGS; |
| 170 | | |
| 171 | | typedef struct { |
| 172 | | UINT8 spls; |
| 173 | | UINT8 sphs; |
| 174 | | UINT16 brd; |
| 175 | | UINT8 spctl; |
| 176 | | UINT8 sprc; |
| 177 | | UINT8 sptc; |
| 178 | | UINT8 sprb; |
| 179 | | UINT8 sptb; |
| 180 | | emu_timer *rx_timer; |
| 181 | | emu_timer *tx_timer; |
| 182 | | } SPU_REGS; |
| 183 | | |
| 184 | | typedef union { |
| 185 | | UINT64 id; |
| 186 | | double fd; |
| 187 | | } FPR; |
| 188 | | |
| 189 | | typedef union { |
| 190 | | UINT32 i; |
| 191 | | float f; |
| 192 | | } FPR32; |
| 193 | | |
| 194 | | typedef struct { |
| 195 | | UINT32 u; |
| 196 | | UINT32 l; |
| 197 | | } BATENT; |
| 198 | | |
| 199 | | |
| 200 | | typedef struct { |
| 201 | | UINT32 r[32]; |
| 202 | | UINT32 pc; |
| 203 | | UINT32 npc; |
| 204 | | |
| 205 | | UINT32 lr; |
| 206 | | UINT32 ctr; |
| 207 | | UINT32 xer; |
| 208 | | UINT32 msr; |
| 209 | | UINT8 cr[8]; |
| 210 | | UINT32 pvr; |
| 211 | | UINT32 srr0; |
| 212 | | UINT32 srr1; |
| 213 | | UINT32 srr2; |
| 214 | | UINT32 srr3; |
| 215 | | UINT32 hid0; |
| 216 | | UINT32 hid1; |
| 217 | | UINT32 hid2; |
| 218 | | UINT32 sdr1; |
| 219 | | UINT32 sprg[4]; |
| 220 | | |
| 221 | | UINT32 dsisr; |
| 222 | | UINT32 dar; |
| 223 | | UINT32 ear; |
| 224 | | UINT32 dmiss; |
| 225 | | UINT32 dcmp; |
| 226 | | UINT32 hash1; |
| 227 | | UINT32 hash2; |
| 228 | | UINT32 imiss; |
| 229 | | UINT32 icmp; |
| 230 | | UINT32 rpa; |
| 231 | | |
| 232 | | BATENT ibat[4]; |
| 233 | | BATENT dbat[4]; |
| 234 | | |
| 235 | | UINT32 evpr; |
| 236 | | UINT32 exier; |
| 237 | | UINT32 exisr; |
| 238 | | UINT32 bear; |
| 239 | | UINT32 besr; |
| 240 | | UINT32 iocr; |
| 241 | | UINT32 br[8]; |
| 242 | | UINT32 iabr; |
| 243 | | UINT32 esr; |
| 244 | | UINT32 iccr; |
| 245 | | UINT32 dccr; |
| 246 | | UINT32 pit; |
| 247 | | UINT32 tsr; |
| 248 | | UINT32 tcr; |
| 249 | | UINT32 dbsr; |
| 250 | | UINT32 sgr; |
| 251 | | UINT32 pid; |
| 252 | | UINT32 pbl1, pbl2, pbu1, pbu2; |
| 253 | | UINT32 fit_bit; |
| 254 | | UINT32 fit_int_enable; |
| 255 | | UINT32 wdt_bit; |
| 256 | | UINT32 wdt_int_enable; |
| 257 | | UINT32 dac1, dac2; |
| 258 | | UINT32 iac1, iac2; |
| 259 | | |
| 260 | | SPU_REGS spu; |
| 261 | | DMA_REGS dma[4]; |
| 262 | | UINT32 dmasr; |
| 263 | | |
| 264 | | int reserved; |
| 265 | | UINT32 reserved_address; |
| 266 | | |
| 267 | | int exception_pending; |
| 268 | | |
| 269 | | UINT64 tb; /* 56-bit timebase register */ |
| 270 | | |
| 271 | | int (*irq_callback)(int irqline); |
| 272 | | drc_core *drc; |
| 273 | | UINT32 drcoptions; |
| 274 | | |
| 275 | | x86code * invoke_exception_handler; |
| 276 | | x86code * generate_interrupt_exception; |
| 277 | | x86code * generate_syscall_exception; |
| 278 | | x86code * generate_decrementer_exception; |
| 279 | | x86code * generate_trap_exception; |
| 280 | | x86code * generate_dsi_exception; |
| 281 | | x86code * generate_isi_exception; |
| 282 | | x86code * generate_fit_exception; |
| 283 | | |
| 284 | | // PowerPC 60x specific registers */ |
| 285 | | UINT32 dec, dec_frac; |
| 286 | | UINT32 fpscr; |
| 287 | | |
| 288 | | FPR fpr[32]; |
| 289 | | UINT32 sr[16]; |
| 290 | | |
| 291 | | int is603; |
| 292 | | int is602; |
| 293 | | |
| 294 | | /* PowerPC 602 specific registers */ |
| 295 | | UINT32 lt; |
| 296 | | UINT32 sp; |
| 297 | | UINT32 ibr; |
| 298 | | UINT32 esasrr; |
| 299 | | UINT32 sebr; |
| 300 | | UINT32 ser; |
| 301 | | |
| 302 | | /* PowerPC function pointers for memory accesses/exceptions */ |
| 303 | | UINT8 (*read8)(offs_t address); |
| 304 | | UINT16 (*read16)(offs_t address); |
| 305 | | UINT32 (*read32)(offs_t address); |
| 306 | | UINT64 (*read64)(offs_t address); |
| 307 | | void (*write8)(offs_t address, UINT8 data); |
| 308 | | void (*write16)(offs_t address, UINT16 data); |
| 309 | | void (*write32)(offs_t address, UINT32 data); |
| 310 | | void (*write64)(offs_t address, UINT64 data); |
| 311 | | UINT16 (*read16_unaligned)(offs_t address); |
| 312 | | UINT32 (*read32_unaligned)(offs_t address); |
| 313 | | UINT64 (*read64_unaligned)(offs_t address); |
| 314 | | void (*write16_unaligned)(offs_t address, UINT16 data); |
| 315 | | void (*write32_unaligned)(offs_t address, UINT32 data); |
| 316 | | void (*write64_unaligned)(offs_t address, UINT64 data); |
| 317 | | |
| 318 | | /* saved ESP when entering entry point */ |
| 319 | | UINT32 host_esp; |
| 320 | | |
| 321 | | UINT32 (* optable19[1024])(drc_core *, UINT32); |
| 322 | | UINT32 (* optable31[1024])(drc_core *, UINT32); |
| 323 | | UINT32 (* optable59[1024])(drc_core *, UINT32); |
| 324 | | UINT32 (* optable63[1024])(drc_core *, UINT32); |
| 325 | | UINT32 (* optable[64])(drc_core *, UINT32); |
| 326 | | } PPC_REGS; |
| 327 | | |
| 328 | | |
| 329 | | |
| 330 | | typedef struct { |
| 331 | | int code; |
| 332 | | int subcode; |
| 333 | | UINT32 (* handler)(drc_core *, UINT32); |
| 334 | | } PPC_OPCODE; |
| 335 | | |
| 336 | | |
| 337 | | /* code logging info */ |
| 338 | | typedef struct _code_log_entry code_log_entry; |
| 339 | | struct _code_log_entry |
| 340 | | { |
| 341 | | UINT32 pc; |
| 342 | | UINT32 op; |
| 343 | | void * base; |
| 344 | | }; |
| 345 | | |
| 346 | | |
| 347 | | |
| 348 | | static int ppc_icount; |
| 349 | | static int ppc_tb_base_icount; |
| 350 | | static int ppc_dec_base_icount; |
| 351 | | static int ppc_dec_trigger_cycle; |
| 352 | | static int bus_freq_multiplier = 1; |
| 353 | | static int ppc_fit_trigger_cycle; |
| 354 | | static PPC_REGS ppc; |
| 355 | | static UINT32 ppc_rotate_mask[32][32]; |
| 356 | | |
| 357 | | #define ROPCODE(pc) cpu_readop32(pc) |
| 358 | | #define ROPCODE64(pc) cpu_readop64(DWORD_XOR_BE(pc)) |
| 359 | | |
| 360 | | INLINE void SET_CR0(INT32 rd) |
| 361 | | { |
| 362 | | if( rd < 0 ) { |
| 363 | | CR(0) = 0x8; |
| 364 | | } else if( rd > 0 ) { |
| 365 | | CR(0) = 0x4; |
| 366 | | } else { |
| 367 | | CR(0) = 0x2; |
| 368 | | } |
| 369 | | |
| 370 | | if( XER & XER_SO ) |
| 371 | | CR(0) |= 0x1; |
| 372 | | } |
| 373 | | |
| 374 | | INLINE void SET_CR1(void) |
| 375 | | { |
| 376 | | CR(1) = (ppc.fpscr >> 28) & 0xf; |
| 377 | | } |
| 378 | | |
| 379 | | INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) |
| 380 | | { |
| 381 | | if( ADD_OV(rd, ra, rb) ) |
| 382 | | XER |= XER_SO | XER_OV; |
| 383 | | else |
| 384 | | XER &= ~XER_OV; |
| 385 | | } |
| 386 | | |
| 387 | | INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) |
| 388 | | { |
| 389 | | if( SUB_OV(rd, ra, rb) ) |
| 390 | | XER |= XER_SO | XER_OV; |
| 391 | | else |
| 392 | | XER &= ~XER_OV; |
| 393 | | } |
| 394 | | |
| 395 | | INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) |
| 396 | | { |
| 397 | | if( ADD_CA(rd, ra, rb) ) |
| 398 | | XER |= XER_CA; |
| 399 | | else |
| 400 | | XER &= ~XER_CA; |
| 401 | | } |
| 402 | | |
| 403 | | INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) |
| 404 | | { |
| 405 | | if( SUB_CA(rd, ra, rb) ) |
| 406 | | XER |= XER_CA; |
| 407 | | else |
| 408 | | XER &= ~XER_CA; |
| 409 | | } |
| 410 | | |
| 411 | | INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) |
| 412 | | { |
| 413 | | UINT32 ctr_ok; |
| 414 | | UINT32 condition_ok; |
| 415 | | UINT32 bo0 = (bo & 0x10) ? 1 : 0; |
| 416 | | UINT32 bo1 = (bo & 0x08) ? 1 : 0; |
| 417 | | UINT32 bo2 = (bo & 0x04) ? 1 : 0; |
| 418 | | UINT32 bo3 = (bo & 0x02) ? 1 : 0; |
| 419 | | |
| 420 | | if( bo2 == 0 ) |
| 421 | | --CTR; |
| 422 | | |
| 423 | | ctr_ok = bo2 | ((CTR != 0) ^ bo3); |
| 424 | | condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); |
| 425 | | |
| 426 | | return ctr_ok && condition_ok; |
| 427 | | } |
| 428 | | |
| 429 | | INLINE UINT64 ppc_read_timebase(void) |
| 430 | | { |
| 431 | | int cycles = ppc_tb_base_icount - ppc_icount; |
| 432 | | |
| 433 | | if (ppc.is603 || ppc.is602) |
| 434 | | { |
| 435 | | // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly |
| 436 | | return ppc.tb + (cycles / 4); |
| 437 | | } |
| 438 | | else |
| 439 | | { |
| 440 | | // timebase is incremented once every core cycle on PPC403 |
| 441 | | return ppc.tb + cycles; |
| 442 | | } |
| 443 | | } |
| 444 | | |
| 445 | | INLINE void ppc_write_timebase_l(UINT32 tbl) |
| 446 | | { |
| 447 | | ppc_tb_base_icount = ppc_icount; |
| 448 | | |
| 449 | | ppc.tb &= ~0xffffffff; |
| 450 | | ppc.tb |= tbl; |
| 451 | | } |
| 452 | | |
| 453 | | INLINE void ppc_write_timebase_h(UINT32 tbh) |
| 454 | | { |
| 455 | | ppc_tb_base_icount = ppc_icount; |
| 456 | | |
| 457 | | ppc.tb &= 0xffffffff; |
| 458 | | ppc.tb |= (UINT64)(tbh) << 32; |
| 459 | | } |
| 460 | | |
| 461 | | INLINE UINT32 read_decrementer(void) |
| 462 | | { |
| 463 | | int cycles = ppc_dec_base_icount - ppc_icount; |
| 464 | | |
| 465 | | // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly |
| 466 | | return DEC - (cycles / (bus_freq_multiplier * 2)); |
| 467 | | } |
| 468 | | |
| 469 | | INLINE void write_decrementer(UINT32 value) |
| 470 | | { |
| 471 | | ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2); |
| 472 | | |
| 473 | | DEC = value; |
| 474 | | |
| 475 | | // check if decrementer exception occurs during execution |
| 476 | | if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) |
| 477 | | { |
| 478 | | ppc_dec_trigger_cycle = ppc_icount - DEC; |
| 479 | | } |
| 480 | | else |
| 481 | | { |
| 482 | | ppc_dec_trigger_cycle = 0x7fffffff; |
| 483 | | } |
| 484 | | } |
| 485 | | |
| 486 | | /*********************************************************************/ |
| 487 | | |
| 488 | | INLINE void ppc_exception(int exception_type) |
| 489 | | { |
| 490 | | void *exception_code = NULL; |
| 491 | | void (*invoke_exception_handler)(void *handler); |
| 492 | | |
| 493 | | switch(exception_type) |
| 494 | | { |
| 495 | | case EXCEPTION_DECREMENTER: |
| 496 | | exception_code = ppc.generate_decrementer_exception; |
| 497 | | break; |
| 498 | | case EXCEPTION_DSI: |
| 499 | | exception_code = ppc.generate_dsi_exception; |
| 500 | | break; |
| 501 | | case EXCEPTION_ISI: |
| 502 | | exception_code = ppc.generate_isi_exception; |
| 503 | | break; |
| 504 | | default: |
| 505 | | fatalerror("Unknown exception %d", exception_type); |
| 506 | | break; |
| 507 | | } |
| 508 | | |
| 509 | | memcpy(&invoke_exception_handler, &ppc.invoke_exception_handler, sizeof(invoke_exception_handler)); |
| 510 | | invoke_exception_handler(exception_code); |
| 511 | | } |
| 512 | | |
| 513 | | /*********************************************************************/ |
| 514 | | |
| 515 | | INLINE void ppc_set_spr(int spr, UINT32 value) |
| 516 | | { |
| 517 | | switch (spr) |
| 518 | | { |
| 519 | | case SPR_LR: LR = value; return; |
| 520 | | case SPR_CTR: CTR = value; return; |
| 521 | | case SPR_XER: XER = value; return; |
| 522 | | case SPR_SRR0: ppc.srr0 = value; return; |
| 523 | | case SPR_SRR1: ppc.srr1 = value; return; |
| 524 | | case SPR_SPRG0: ppc.sprg[0] = value; return; |
| 525 | | case SPR_SPRG1: ppc.sprg[1] = value; return; |
| 526 | | case SPR_SPRG2: ppc.sprg[2] = value; return; |
| 527 | | case SPR_SPRG3: ppc.sprg[3] = value; return; |
| 528 | | case SPR_PVR: return; |
| 529 | | } |
| 530 | | |
| 531 | | #if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601 || HAS_PPC604) |
| 532 | | if(ppc.is603 || ppc.is602) { |
| 533 | | switch(spr) |
| 534 | | { |
| 535 | | case SPR603E_DEC: |
| 536 | | if((value & 0x80000000) && !(DEC & 0x80000000)) |
| 537 | | { |
| 538 | | /* trigger interrupt */ |
| 539 | | if( MSR & MSR_EE ) |
| 540 | | ppc_exception(EXCEPTION_DECREMENTER); |
| 541 | | } |
| 542 | | write_decrementer(value); |
| 543 | | return; |
| 544 | | |
| 545 | | case SPR603E_TBL_W: |
| 546 | | case SPR603E_TBL_R: // special 603e case |
| 547 | | ppc_write_timebase_l(value); |
| 548 | | return; |
| 549 | | |
| 550 | | case SPR603E_TBU_R: |
| 551 | | case SPR603E_TBU_W: // special 603e case |
| 552 | | ppc_write_timebase_h(value); |
| 553 | | return; |
| 554 | | |
| 555 | | case SPR603E_HID0: |
| 556 | | ppc.hid0 = value; |
| 557 | | return; |
| 558 | | |
| 559 | | case SPR603E_HID1: |
| 560 | | ppc.hid1 = value; |
| 561 | | return; |
| 562 | | |
| 563 | | case SPR603E_HID2: |
| 564 | | ppc.hid1 = value; |
| 565 | | return; |
| 566 | | |
| 567 | | case SPR603E_DSISR: ppc.dsisr = value; return; |
| 568 | | case SPR603E_DAR: ppc.dar = value; return; |
| 569 | | case SPR603E_EAR: ppc.ear = value; return; |
| 570 | | case SPR603E_DMISS: ppc.dmiss = value; return; |
| 571 | | case SPR603E_DCMP: ppc.dcmp = value; return; |
| 572 | | case SPR603E_HASH1: ppc.hash1 = value; return; |
| 573 | | case SPR603E_HASH2: ppc.hash2 = value; return; |
| 574 | | case SPR603E_IMISS: ppc.imiss = value; return; |
| 575 | | case SPR603E_ICMP: ppc.icmp = value; return; |
| 576 | | case SPR603E_RPA: ppc.rpa = value; return; |
| 577 | | |
| 578 | | case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; |
| 579 | | case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; |
| 580 | | case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; |
| 581 | | case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; |
| 582 | | case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; |
| 583 | | case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; |
| 584 | | case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; |
| 585 | | case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; |
| 586 | | case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; |
| 587 | | case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; |
| 588 | | case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; |
| 589 | | case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; |
| 590 | | case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; |
| 591 | | case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; |
| 592 | | case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; |
| 593 | | case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; |
| 594 | | |
| 595 | | case SPR603E_SDR1: |
| 596 | | ppc.sdr1 = value; |
| 597 | | return; |
| 598 | | |
| 599 | | case SPR603E_IABR: ppc.iabr = value; return; |
| 600 | | } |
| 601 | | } |
| 602 | | #endif |
| 603 | | |
| 604 | | #if (HAS_PPC602) |
| 605 | | if (ppc.is602) { |
| 606 | | switch(spr) |
| 607 | | { |
| 608 | | case SPR602_LT: ppc.lt = value; return; |
| 609 | | case SPR602_IBR: ppc.ibr = value; return; |
| 610 | | case SPR602_SP: ppc.sp = value; return; |
| 611 | | case SPR602_SEBR: ppc.sebr = value; return; |
| 612 | | case SPR602_SER: ppc.ser = value; return; |
| 613 | | case SPR602_TCR: ppc.tcr = value; return; |
| 614 | | } |
| 615 | | } |
| 616 | | #endif |
| 617 | | |
| 618 | | #if (HAS_PPC403) |
| 619 | | if (!ppc.is603 && !ppc.is602) { |
| 620 | | switch(spr) |
| 621 | | { |
| 622 | | case SPR403_TBHI: ppc_write_timebase_h(value); return; |
| 623 | | case SPR403_TBLO: ppc_write_timebase_l(value); return; |
| 624 | | |
| 625 | | case SPR403_TSR: |
| 626 | | ppc.tsr &= ~value; // 1 clears, 0 does nothing |
| 627 | | return; |
| 628 | | |
| 629 | | case SPR403_TCR: |
| 630 | | switch((value >> 24) & 0x3) |
| 631 | | { |
| 632 | | case 0: ppc.fit_bit = 1 << 8; break; |
| 633 | | case 1: ppc.fit_bit = 1 << 12; break; |
| 634 | | case 2: ppc.fit_bit = 1 << 16; break; |
| 635 | | case 3: ppc.fit_bit = 1 << 20; break; |
| 636 | | } |
| 637 | | switch((value >> 30) & 0x3) |
| 638 | | { |
| 639 | | case 0: ppc.wdt_bit = 1 << 16; break; |
| 640 | | case 1: ppc.wdt_bit = 1 << 20; break; |
| 641 | | case 2: ppc.wdt_bit = 1 << 24; break; |
| 642 | | case 3: ppc.wdt_bit = 1 << 28; break; |
| 643 | | } |
| 644 | | ppc.fit_int_enable = (value >> 23) & 0x1; |
| 645 | | ppc.wdt_int_enable = (value >> 27) & 0x1; |
| 646 | | ppc.tcr = value; |
| 647 | | |
| 648 | | if (!ppc.fit_int_enable) |
| 649 | | { |
| 650 | | ppc.exception_pending &= ~0x4; |
| 651 | | } |
| 652 | | return; |
| 653 | | |
| 654 | | case SPR403_ESR: ppc.esr = value; return; |
| 655 | | case SPR403_ICCR: ppc.iccr = value; return; |
| 656 | | case SPR403_DCCR: ppc.dccr = value; return; |
| 657 | | case SPR403_EVPR: EVPR = value & 0xffff0000; return; |
| 658 | | case SPR403_PIT: ppc.pit = value; return; |
| 659 | | case SPR403_SGR: ppc.sgr = value; return; |
| 660 | | case SPR403_DBSR: ppc.dbsr = value; return; |
| 661 | | case SPR403_DCWR: return; |
| 662 | | case SPR403_PID: ppc.pid = value; return; |
| 663 | | case SPR403_PBL1: ppc.pbl1 = value; return; |
| 664 | | case SPR403_PBU1: ppc.pbu1 = value; return; |
| 665 | | case SPR403_PBL2: ppc.pbl2 = value; return; |
| 666 | | case SPR403_PBU2: ppc.pbu2 = value; return; |
| 667 | | case SPR403_SRR2: ppc.srr2 = value; return; |
| 668 | | case SPR403_SRR3: ppc.srr3 = value; return; |
| 669 | | case SPR403_DAC1: ppc.dac1 = value; return; |
| 670 | | case SPR403_DAC2: ppc.dac2 = value; return; |
| 671 | | case SPR403_IAC1: ppc.iac1 = value; return; |
| 672 | | case SPR403_IAC2: ppc.iac2 = value; return; |
| 673 | | } |
| 674 | | } |
| 675 | | #endif |
| 676 | | |
| 677 | | fatalerror("ppc: set_spr: unknown spr %d (%03X) !", spr, spr); |
| 678 | | } |
| 679 | | |
| 680 | | INLINE UINT32 ppc_get_spr(int spr) |
| 681 | | { |
| 682 | | switch(spr) |
| 683 | | { |
| 684 | | case SPR_LR: return LR; |
| 685 | | case SPR_CTR: return CTR; |
| 686 | | case SPR_XER: return XER; |
| 687 | | case SPR_SRR0: return ppc.srr0; |
| 688 | | case SPR_SRR1: return ppc.srr1; |
| 689 | | case SPR_SPRG0: return ppc.sprg[0]; |
| 690 | | case SPR_SPRG1: return ppc.sprg[1]; |
| 691 | | case SPR_SPRG2: return ppc.sprg[2]; |
| 692 | | case SPR_SPRG3: return ppc.sprg[3]; |
| 693 | | case SPR_PVR: return ppc.pvr; |
| 694 | | } |
| 695 | | |
| 696 | | #if (HAS_PPC403) |
| 697 | | if (!ppc.is603 && !ppc.is602) |
| 698 | | { |
| 699 | | switch (spr) |
| 700 | | { |
| 701 | | case SPR403_TBLU: |
| 702 | | case SPR403_TBLO: return (UINT32)(ppc_read_timebase()); |
| 703 | | case SPR403_TBHU: |
| 704 | | case SPR403_TBHI: return (UINT32)(ppc_read_timebase() >> 32); |
| 705 | | |
| 706 | | case SPR403_EVPR: return EVPR; |
| 707 | | case SPR403_ESR: return ppc.esr; |
| 708 | | case SPR403_TCR: return ppc.tcr; |
| 709 | | case SPR403_ICCR: return ppc.iccr; |
| 710 | | case SPR403_DCCR: return ppc.dccr; |
| 711 | | case SPR403_PIT: return ppc.pit; |
| 712 | | case SPR403_DBSR: return ppc.dbsr; |
| 713 | | case SPR403_SGR: return ppc.sgr; |
| 714 | | case SPR403_TSR: return ppc.tsr; |
| 715 | | case SPR403_PBL1: return ppc.pbl1; |
| 716 | | case SPR403_PBU1: return ppc.pbu1; |
| 717 | | case SPR403_PBL2: return ppc.pbl2; |
| 718 | | case SPR403_PBU2: return ppc.pbu2; |
| 719 | | case SPR403_SRR2: return ppc.srr2; |
| 720 | | case SPR403_SRR3: return ppc.srr3; |
| 721 | | case SPR403_DAC1: return ppc.dac1; |
| 722 | | case SPR403_DAC2: return ppc.dac2; |
| 723 | | case SPR403_IAC1: return ppc.iac1; |
| 724 | | case SPR403_IAC2: return ppc.iac2; |
| 725 | | } |
| 726 | | } |
| 727 | | #endif |
| 728 | | |
| 729 | | #if (HAS_PPC602) |
| 730 | | if (ppc.is602) { |
| 731 | | switch(spr) |
| 732 | | { |
| 733 | | case SPR602_LT: return ppc.lt; |
| 734 | | case SPR602_IBR: return ppc.ibr; |
| 735 | | case SPR602_ESASRR: return ppc.esasrr; |
| 736 | | case SPR602_SEBR: return ppc.sebr; |
| 737 | | case SPR602_SER: return ppc.ser; |
| 738 | | case SPR602_SP: return ppc.sp; |
| 739 | | case SPR602_TCR: return ppc.tcr; |
| 740 | | } |
| 741 | | } |
| 742 | | #endif |
| 743 | | |
| 744 | | #if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601 || HAS_PPC604) |
| 745 | | if (ppc.is603 || ppc.is602) |
| 746 | | { |
| 747 | | switch (spr) |
| 748 | | { |
| 749 | | case SPR603E_TBL_R: |
| 750 | | fatalerror("ppc: get_spr: TBL_R "); |
| 751 | | break; |
| 752 | | |
| 753 | | case SPR603E_TBU_R: |
| 754 | | fatalerror("ppc: get_spr: TBU_R "); |
| 755 | | break; |
| 756 | | |
| 757 | | case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); |
| 758 | | case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); |
| 759 | | case SPR603E_HID0: return ppc.hid0; |
| 760 | | case SPR603E_HID1: return ppc.hid1; |
| 761 | | case SPR603E_HID2: return ppc.hid2; |
| 762 | | case SPR603E_DEC: return read_decrementer(); |
| 763 | | case SPR603E_SDR1: return ppc.sdr1; |
| 764 | | case SPR603E_DSISR: return ppc.dsisr; |
| 765 | | case SPR603E_DAR: return ppc.dar; |
| 766 | | case SPR603E_EAR: return ppc.ear; |
| 767 | | case SPR603E_IBAT0L: return ppc.ibat[0].l; |
| 768 | | case SPR603E_IBAT0U: return ppc.ibat[0].u; |
| 769 | | case SPR603E_IBAT1L: return ppc.ibat[1].l; |
| 770 | | case SPR603E_IBAT1U: return ppc.ibat[1].u; |
| 771 | | case SPR603E_IBAT2L: return ppc.ibat[2].l; |
| 772 | | case SPR603E_IBAT2U: return ppc.ibat[2].u; |
| 773 | | case SPR603E_IBAT3L: return ppc.ibat[3].l; |
| 774 | | case SPR603E_IBAT3U: return ppc.ibat[3].u; |
| 775 | | case SPR603E_DBAT0L: return ppc.dbat[0].l; |
| 776 | | case SPR603E_DBAT0U: return ppc.dbat[0].u; |
| 777 | | case SPR603E_DBAT1L: return ppc.dbat[1].l; |
| 778 | | case SPR603E_DBAT1U: return ppc.dbat[1].u; |
| 779 | | case SPR603E_DBAT2L: return ppc.dbat[2].l; |
| 780 | | case SPR603E_DBAT2U: return ppc.dbat[2].u; |
| 781 | | case SPR603E_DBAT3L: return ppc.dbat[3].l; |
| 782 | | case SPR603E_DBAT3U: return ppc.dbat[3].u; |
| 783 | | } |
| 784 | | } |
| 785 | | #endif |
| 786 | | |
| 787 | | fatalerror("ppc: get_spr: unknown spr %d (%03X) !", spr, spr); |
| 788 | | return 0; |
| 789 | | } |
| 790 | | |
| 791 | | static UINT8 ppc_read8_translated(offs_t address); |
| 792 | | static UINT16 ppc_read16_translated(offs_t address); |
| 793 | | static UINT32 ppc_read32_translated(offs_t address); |
| 794 | | static UINT64 ppc_read64_translated(offs_t address); |
| 795 | | static void ppc_write8_translated(offs_t address, UINT8 data); |
| 796 | | static void ppc_write16_translated(offs_t address, UINT16 data); |
| 797 | | static void ppc_write32_translated(offs_t address, UINT32 data); |
| 798 | | static void ppc_write64_translated(offs_t address, UINT64 data); |
| 799 | | |
| 800 | | INLINE void ppc_set_msr(UINT32 value) |
| 801 | | { |
| 802 | | if( value & (MSR_ILE | MSR_LE) ) |
| 803 | | fatalerror("ppc: set_msr: little_endian mode not supported !"); |
| 804 | | |
| 805 | | MSR = value; |
| 806 | | |
| 807 | | if (ppc.is603 || ppc.is602) |
| 808 | | { |
| 809 | | if (!(MSR & MSR_DR)) |
| 810 | | { |
| 811 | | ppc.read8 = program_read_byte_64be; |
| 812 | | ppc.read16 = program_read_word_64be; |
| 813 | | ppc.read32 = program_read_dword_64be; |
| 814 | | ppc.read64 = program_read_qword_64be; |
| 815 | | ppc.write8 = program_write_byte_64be; |
| 816 | | ppc.write16 = program_write_word_64be; |
| 817 | | ppc.write32 = program_write_dword_64be; |
| 818 | | ppc.write64 = program_write_qword_64be; |
| 819 | | } |
| 820 | | else |
| 821 | | { |
| 822 | | ppc.read8 = ppc_read8_translated; |
| 823 | | ppc.read16 = ppc_read16_translated; |
| 824 | | ppc.read32 = ppc_read32_translated; |
| 825 | | ppc.read64 = ppc_read64_translated; |
| 826 | | ppc.write8 = ppc_write8_translated; |
| 827 | | ppc.write16 = ppc_write16_translated; |
| 828 | | ppc.write32 = ppc_write32_translated; |
| 829 | | ppc.write64 = ppc_write64_translated; |
| 830 | | } |
| 831 | | } |
| 832 | | } |
| 833 | | |
| 834 | | INLINE UINT32 ppc_get_msr(void) |
| 835 | | { |
| 836 | | return MSR; |
| 837 | | } |
| 838 | | |
| 839 | | INLINE void ppc_set_cr(UINT32 value) |
| 840 | | { |
| 841 | | CR(0) = (value >> 28) & 0xf; |
| 842 | | CR(1) = (value >> 24) & 0xf; |
| 843 | | CR(2) = (value >> 20) & 0xf; |
| 844 | | CR(3) = (value >> 16) & 0xf; |
| 845 | | CR(4) = (value >> 12) & 0xf; |
| 846 | | CR(5) = (value >> 8) & 0xf; |
| 847 | | CR(6) = (value >> 4) & 0xf; |
| 848 | | CR(7) = (value >> 0) & 0xf; |
| 849 | | } |
| 850 | | |
| 851 | | INLINE UINT32 ppc_get_cr(void) |
| 852 | | { |
| 853 | | return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); |
| 854 | | } |
| 855 | | |
| 856 | | #ifdef UNUSED_FUNCTION |
| 857 | | static void log_code(drc_core *drc) |
| 858 | | { |
| 859 | | #if LOG_CODE |
| 860 | | FILE *temp; |
| 861 | | temp = fopen("code.bin", "wb"); |
| 862 | | fwrite(drc->cache_base, 1, drc->cache_top - drc->cache_base, temp); |
| 863 | | fclose(temp); |
| 864 | | #endif |
| 865 | | } |
| 866 | | #endif |
| 867 | | |
| 868 | | /***********************************************************************/ |
| 869 | | |
| 870 | | #include "ppc_mem.c" |
| 871 | | |
| 872 | | #if (HAS_PPC403) |
| 873 | | #include "ppc403.c" |
| 874 | | #endif |
| 875 | | |
| 876 | | #if (HAS_PPC602) |
| 877 | | #include "ppc602.c" |
| 878 | | #endif |
| 879 | | |
| 880 | | /*************************************************************************** |
| 881 | | CODE LOGGING |
| 882 | | ***************************************************************************/ |
| 883 | | |
| 884 | | #if LOG_CODE |
| 885 | | |
| 886 | | static code_log_entry code_log_buffer[MAX_INSTRUCTIONS*2]; |
| 887 | | static int code_log_index; |
| 888 | | static FILE *logfile; |
| 889 | | |
| 890 | | |
| 891 | | /*------------------------------------------------- |
| 892 | | open_logfile - open the log file if it is |
| 893 | | not already opened |
| 894 | | -------------------------------------------------*/ |
| 895 | | |
| 896 | | INLINE int open_logfile(void) |
| 897 | | { |
| 898 | | if (logfile == NULL) |
| 899 | | logfile = fopen("ppcdrc.asm", "w"); |
| 900 | | return (logfile != NULL); |
| 901 | | } |
| 902 | | |
| 903 | | |
| 904 | | /*------------------------------------------------- |
| 905 | | code_log_reset - reset the logging index |
| 906 | | -------------------------------------------------*/ |
| 907 | | |
| 908 | | INLINE void code_log_reset(void) |
| 909 | | { |
| 910 | | code_log_index = 0; |
| 911 | | } |
| 912 | | |
| 913 | | |
| 914 | | /*------------------------------------------------- |
| 915 | | code_log_add_entry - add an entry to the log |
| 916 | | -------------------------------------------------*/ |
| 917 | | |
| 918 | | INLINE void code_log_add_entry(UINT32 pc, UINT32 op, void *base) |
| 919 | | { |
| 920 | | code_log_buffer[code_log_index].pc = pc; |
| 921 | | code_log_buffer[code_log_index].op = op; |
| 922 | | code_log_buffer[code_log_index].base = base; |
| 923 | | code_log_index++; |
| 924 | | } |
| 925 | | |
| 926 | | |
| 927 | | /*------------------------------------------------- |
| 928 | | code_log - actually log some code |
| 929 | | -------------------------------------------------*/ |
| 930 | | |
| 931 | | static void code_log(const char *label, x86code *start, x86code *stop) |
| 932 | | { |
| 933 | | extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode); |
| 934 | | offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); |
| 935 | | UINT8 *cur = start; |
| 936 | | |
| 937 | | /* open the file, creating it if necessary */ |
| 938 | | if (!open_logfile()) |
| 939 | | return; |
| 940 | | fprintf(logfile, "\n%s\n", label); |
| 941 | | |
| 942 | | /* loop from the start until the cache top */ |
| 943 | | while (cur < stop) |
| 944 | | { |
| 945 | | char buffer[100]; |
| 946 | | int bytes; |
| 947 | | int op; |
| 948 | | |
| 949 | | /* skip filler opcodes */ |
| 950 | | if (*cur == 0xcc) |
| 951 | | { |
| 952 | | cur++; |
| 953 | | continue; |
| 954 | | } |
| 955 | | |
| 956 | | /* disassemble this instruction */ |
| 957 | | #ifdef PTR64 |
| 958 | | bytes = i386_dasm_one(buffer, (UINT32)(FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK; |
| 959 | | #else |
| 960 | | bytes = i386_dasm_one(buffer, (UINT32)cur, cur, 32) & DASMFLAG_LENGTHMASK; |
| 961 | | #endif |
| 962 | | |
| 963 | | /* look for a match in the registered opcodes */ |
| 964 | | for (op = 0; op < code_log_index; op++) |
| 965 | | if (code_log_buffer[op].base == (void *)cur) |
| 966 | | break; |
| 967 | | |
| 968 | | /* if no match, just output the current instruction */ |
| 969 | | if (op == code_log_index) |
| 970 | | fprintf(logfile, "%p: %s\n", cur, buffer); |
| 971 | | |
| 972 | | /* otherwise, output with the original instruction to the right */ |
| 973 | | else |
| 974 | | { |
| 975 | | char buffer2[100]; |
| 976 | | ppc_dasm_one(buffer2, code_log_buffer[op].pc, code_log_buffer[op].op); |
| 977 | | fprintf(logfile, "%p: %-50s %08X: %s\n", cur, buffer, code_log_buffer[op].pc, buffer2); |
| 978 | | } |
| 979 | | |
| 980 | | /* advance past this instruction */ |
| 981 | | cur += bytes; |
| 982 | | } |
| 983 | | |
| 984 | | /* flush the file */ |
| 985 | | fflush(logfile); |
| 986 | | } |
| 987 | | |
| 988 | | #else |
| 989 | | |
| 990 | | #define code_log_reset() |
| 991 | | #define code_log_add_entry(a,b,c) |
| 992 | | #define code_log(a,b,c) |
| 993 | | |
| 994 | | #endif |
| 995 | | |
| 996 | | |
| 997 | | /********************************************************************/ |
| 998 | | |
| 999 | | #include "ppc_ops.c" |
| 1000 | | #include "drc_ops.c" |
| 1001 | | #include "drc_ops.h" |
| 1002 | | |
| 1003 | | /* Initialization and shutdown */ |
| 1004 | | |
| 1005 | | static void ppc_init(void) |
| 1006 | | { |
| 1007 | | int i,j; |
| 1008 | | |
| 1009 | | for( i=0; i < 64; i++ ) { |
| 1010 | | ppc.optable[i] = recompile_invalid; |
| 1011 | | } |
| 1012 | | for( i=0; i < 1024; i++ ) { |
| 1013 | | ppc.optable19[i] = recompile_invalid; |
| 1014 | | ppc.optable31[i] = recompile_invalid; |
| 1015 | | ppc.optable59[i] = recompile_invalid; |
| 1016 | | ppc.optable63[i] = recompile_invalid; |
| 1017 | | } |
| 1018 | | |
| 1019 | | /* Fill the opcode tables */ |
| 1020 | | for( i=0; i < (sizeof(ppcdrc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) { |
| 1021 | | |
| 1022 | | switch(ppcdrc_opcode_common[i].code) |
| 1023 | | { |
| 1024 | | case 19: |
| 1025 | | ppc.optable19[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler; |
| 1026 | | break; |
| 1027 | | |
| 1028 | | case 31: |
| 1029 | | ppc.optable31[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler; |
| 1030 | | break; |
| 1031 | | |
| 1032 | | case 59: |
| 1033 | | case 63: |
| 1034 | | break; |
| 1035 | | |
| 1036 | | default: |
| 1037 | | ppc.optable[ppcdrc_opcode_common[i].code] = ppcdrc_opcode_common[i].handler; |
| 1038 | | } |
| 1039 | | |
| 1040 | | } |
| 1041 | | |
| 1042 | | /* Calculate rotate mask table */ |
| 1043 | | for( i=0; i < 32; i++ ) { |
| 1044 | | for( j=0; j < 32; j++ ) { |
| 1045 | | UINT32 mask; |
| 1046 | | int mb = i; |
| 1047 | | int me = j; |
| 1048 | | mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); |
| 1049 | | if( mb > me ) |
| 1050 | | mask = ~mask; |
| 1051 | | |
| 1052 | | ppc_rotate_mask[i][j] = mask; |
| 1053 | | } |
| 1054 | | } |
| 1055 | | } |
| 1056 | | |
| 1057 | | #if (HAS_PPC403) |
| 1058 | | static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1059 | | { |
| 1060 | | const ppc_config *config = _config; |
| 1061 | | |
| 1062 | | ppc_init(); |
| 1063 | | ppcdrc_init(); |
| 1064 | | |
| 1065 | | /* PPC403 specific opcodes */ |
| 1066 | | ppc.optable31[454] = recompile_dccci; |
| 1067 | | ppc.optable31[486] = recompile_dcread; |
| 1068 | | ppc.optable31[262] = recompile_icbt; |
| 1069 | | ppc.optable31[966] = recompile_iccci; |
| 1070 | | ppc.optable31[998] = recompile_icread; |
| 1071 | | ppc.optable31[323] = recompile_mfdcr; |
| 1072 | | ppc.optable31[451] = recompile_mtdcr; |
| 1073 | | ppc.optable31[131] = recompile_wrtee; |
| 1074 | | ppc.optable31[163] = recompile_wrteei; |
| 1075 | | ppc.optable19[51] = recompile_rfci; |
| 1076 | | |
| 1077 | | ppc.spu.rx_timer = timer_alloc(ppc403_spu_rx_callback, NULL); |
| 1078 | | ppc.spu.tx_timer = timer_alloc(ppc403_spu_tx_callback, NULL); |
| 1079 | | |
| 1080 | | ppc.is603 = 0; |
| 1081 | | ppc.is602 = 0; |
| 1082 | | |
| 1083 | | ppc.read8 = ppc403_read8; |
| 1084 | | ppc.read16 = ppc403_read16; |
| 1085 | | ppc.read32 = ppc403_read32; |
| 1086 | | ppc.write8 = ppc403_write8; |
| 1087 | | ppc.write16 = ppc403_write16; |
| 1088 | | ppc.write32 = ppc403_write32; |
| 1089 | | ppc.read16_unaligned = ppc403_read16_unaligned; |
| 1090 | | ppc.read32_unaligned = ppc403_read32_unaligned; |
| 1091 | | ppc.write16_unaligned = ppc403_write16_unaligned; |
| 1092 | | ppc.write32_unaligned = ppc403_write32_unaligned; |
| 1093 | | |
| 1094 | | ppc.irq_callback = irqcallback; |
| 1095 | | |
| 1096 | | ppc.pvr = config->pvr; |
| 1097 | | } |
| 1098 | | |
| 1099 | | static void ppcdrc403_exit(void) |
| 1100 | | { |
| 1101 | | #if LOG_CODE |
| 1102 | | //if (symfile) fclose(symfile); |
| 1103 | | #endif |
| 1104 | | ppcdrc_exit(); |
| 1105 | | } |
| 1106 | | |
| 1107 | | static void ppcdrc403_reset(void) |
| 1108 | | { |
| 1109 | | ppc.pc = ppc.npc = 0xfffffffc; |
| 1110 | | |
| 1111 | | ppc_set_msr(0); |
| 1112 | | change_pc(ppc.pc); |
| 1113 | | |
| 1114 | | /* reset the DRC */ |
| 1115 | | drc_cache_reset(ppc.drc); |
| 1116 | | } |
| 1117 | | |
| 1118 | | static int ppcdrc403_execute(int cycles) |
| 1119 | | { |
| 1120 | | /* count cycles and interrupt cycles */ |
| 1121 | | ppc_icount = cycles; |
| 1122 | | ppc_tb_base_icount = cycles; |
| 1123 | | |
| 1124 | | ppc_fit_trigger_cycle = 0x7fffffff; |
| 1125 | | |
| 1126 | | if (ppc.fit_int_enable) |
| 1127 | | { |
| 1128 | | UINT32 tb = (UINT32)ppc.tb; |
| 1129 | | UINT32 fit_cycles = 0; |
| 1130 | | |
| 1131 | | if (ppc.tb & ppc.fit_bit) |
| 1132 | | { |
| 1133 | | fit_cycles += ppc.fit_bit; |
| 1134 | | tb += fit_cycles; |
| 1135 | | } |
| 1136 | | |
| 1137 | | fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1)); |
| 1138 | | |
| 1139 | | ppc_fit_trigger_cycle = ppc_icount - fit_cycles; |
| 1140 | | } |
| 1141 | | |
| 1142 | | drc_execute(ppc.drc); |
| 1143 | | |
| 1144 | | // update timebase |
| 1145 | | ppc.tb += (ppc_tb_base_icount - ppc_icount); |
| 1146 | | |
| 1147 | | return cycles - ppc_icount; |
| 1148 | | } |
| 1149 | | |
| 1150 | | static void ppcdrc403_set_irq_line(int irqline, int state) |
| 1151 | | { |
| 1152 | | if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4) |
| 1153 | | { |
| 1154 | | UINT32 mask = (1 << (4 - irqline)); |
| 1155 | | if( state == ASSERT_LINE) { |
| 1156 | | if (EXIER & mask) |
| 1157 | | { |
| 1158 | | ppc.exisr |= mask; |
| 1159 | | ppc.exception_pending |= 0x1; |
| 1160 | | |
| 1161 | | if (ppc.irq_callback) |
| 1162 | | { |
| 1163 | | ppc.irq_callback(irqline); |
| 1164 | | } |
| 1165 | | } |
| 1166 | | } |
| 1167 | | // clear line is used to clear the interrupt when the interrupts are level-sensitive |
| 1168 | | else if (state == CLEAR_LINE) |
| 1169 | | { |
| 1170 | | ppc.exisr &= ~mask; |
| 1171 | | } |
| 1172 | | } |
| 1173 | | else if (irqline == PPC403_SPU_RX) |
| 1174 | | { |
| 1175 | | UINT32 mask = 0x08000000; |
| 1176 | | if (state) { |
| 1177 | | if( EXIER & mask ) { |
| 1178 | | ppc.exisr |= mask; |
| 1179 | | ppc.exception_pending |= 0x1; |
| 1180 | | } |
| 1181 | | } |
| 1182 | | } |
| 1183 | | else if (irqline == PPC403_SPU_TX) |
| 1184 | | { |
| 1185 | | UINT32 mask = 0x04000000; |
| 1186 | | if (state) { |
| 1187 | | if( EXIER & mask ) { |
| 1188 | | ppc.exisr |= mask; |
| 1189 | | ppc.exception_pending |= 0x1; |
| 1190 | | } |
| 1191 | | } |
| 1192 | | } |
| 1193 | | else |
| 1194 | | { |
| 1195 | | fatalerror("PPC: Unknown IRQ line %d", irqline); |
| 1196 | | } |
| 1197 | | } |
| 1198 | | #endif |
| 1199 | | |
| 1200 | | #if (HAS_PPC603) |
| 1201 | | static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1202 | | { |
| 1203 | | int pll_config = 0; |
| 1204 | | float multiplier; |
| 1205 | | const ppc_config *config = _config; |
| 1206 | | int i; |
| 1207 | | |
| 1208 | | ppc_init(); |
| 1209 | | ppcdrc_init(); |
| 1210 | | |
| 1211 | | ppc.optable[48] = recompile_lfs; |
| 1212 | | ppc.optable[49] = recompile_lfsu; |
| 1213 | | ppc.optable[50] = recompile_lfd; |
| 1214 | | ppc.optable[51] = recompile_lfdu; |
| 1215 | | ppc.optable[52] = recompile_stfs; |
| 1216 | | ppc.optable[53] = recompile_stfsu; |
| 1217 | | ppc.optable[54] = recompile_stfd; |
| 1218 | | ppc.optable[55] = recompile_stfdu; |
| 1219 | | ppc.optable31[631] = recompile_lfdux; |
| 1220 | | ppc.optable31[599] = recompile_lfdx; |
| 1221 | | ppc.optable31[567] = recompile_lfsux; |
| 1222 | | ppc.optable31[535] = recompile_lfsx; |
| 1223 | | ppc.optable31[595] = recompile_mfsr; |
| 1224 | | ppc.optable31[659] = recompile_mfsrin; |
| 1225 | | ppc.optable31[371] = recompile_mftb; |
| 1226 | | ppc.optable31[210] = recompile_mtsr; |
| 1227 | | ppc.optable31[242] = recompile_mtsrin; |
| 1228 | | ppc.optable31[758] = recompile_dcba; |
| 1229 | | ppc.optable31[759] = recompile_stfdux; |
| 1230 | | ppc.optable31[727] = recompile_stfdx; |
| 1231 | | ppc.optable31[983] = recompile_stfiwx; |
| 1232 | | ppc.optable31[695] = recompile_stfsux; |
| 1233 | | ppc.optable31[663] = recompile_stfsx; |
| 1234 | | ppc.optable31[370] = recompile_tlbia; |
| 1235 | | ppc.optable31[306] = recompile_tlbie; |
| 1236 | | ppc.optable31[566] = recompile_tlbsync; |
| 1237 | | ppc.optable31[310] = recompile_eciwx; |
| 1238 | | ppc.optable31[438] = recompile_ecowx; |
| 1239 | | |
| 1240 | | ppc.optable63[264] = recompile_fabsx; |
| 1241 | | ppc.optable63[21] = recompile_faddx; |
| 1242 | | ppc.optable63[32] = recompile_fcmpo; |
| 1243 | | ppc.optable63[0] = recompile_fcmpu; |
| 1244 | | ppc.optable63[14] = recompile_fctiwx; |
| 1245 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1246 | | ppc.optable63[18] = recompile_fdivx; |
| 1247 | | ppc.optable63[72] = recompile_fmrx; |
| 1248 | | ppc.optable63[136] = recompile_fnabsx; |
| 1249 | | ppc.optable63[40] = recompile_fnegx; |
| 1250 | | ppc.optable63[12] = recompile_frspx; |
| 1251 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1252 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1253 | | ppc.optable63[20] = recompile_fsubx; |
| 1254 | | ppc.optable63[583] = recompile_mffsx; |
| 1255 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1256 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1257 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1258 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1259 | | ppc.optable63[64] = recompile_mcrfs; |
| 1260 | | |
| 1261 | | ppc.optable59[21] = recompile_faddsx; |
| 1262 | | ppc.optable59[18] = recompile_fdivsx; |
| 1263 | | ppc.optable59[24] = recompile_fresx; |
| 1264 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1265 | | ppc.optable59[20] = recompile_fsubsx; |
| 1266 | | |
| 1267 | | for(i = 0; i < 32; i++) |
| 1268 | | { |
| 1269 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1270 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1271 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1272 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1273 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1274 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 1275 | | |
| 1276 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1277 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1278 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1279 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1280 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1281 | | } |
| 1282 | | |
| 1283 | | #if (HAS_PPC602 || HAS_MPC8240) |
| 1284 | | ppc.optable31[978] = recompile_tlbld; |
| 1285 | | #endif /* (HAS_PPC602 || HAS_MPC8240) */ |
| 1286 | | |
| 1287 | | for(i = 0; i < 256; i++) |
| 1288 | | { |
| 1289 | | ppc_field_xlat[i] = |
| 1290 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1291 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1292 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1293 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1294 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1295 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1296 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1297 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1298 | | } |
| 1299 | | |
| 1300 | | ppc.is603 = 1; |
| 1301 | | |
| 1302 | | ppc.read8 = program_read_byte_64be; |
| 1303 | | ppc.read16 = program_read_word_64be; |
| 1304 | | ppc.read32 = program_read_dword_64be; |
| 1305 | | ppc.read64 = program_read_qword_64be; |
| 1306 | | ppc.write8 = program_write_byte_64be; |
| 1307 | | ppc.write16 = program_write_word_64be; |
| 1308 | | ppc.write32 = program_write_dword_64be; |
| 1309 | | ppc.write64 = program_write_qword_64be; |
| 1310 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1311 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1312 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1313 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1314 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1315 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1316 | | |
| 1317 | | ppc.irq_callback = irqcallback; |
| 1318 | | |
| 1319 | | ppc.pvr = config->pvr; |
| 1320 | | |
| 1321 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1322 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1323 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1324 | | |
| 1325 | | switch(config->pvr) |
| 1326 | | { |
| 1327 | | case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1328 | | case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1329 | | case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1330 | | default: break; |
| 1331 | | } |
| 1332 | | |
| 1333 | | if (pll_config == -1) |
| 1334 | | { |
| 1335 | | fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); |
| 1336 | | } |
| 1337 | | |
| 1338 | | ppc.hid1 = pll_config << 28; |
| 1339 | | } |
| 1340 | | |
| 1341 | | static void ppcdrc603_exit(void) |
| 1342 | | { |
| 1343 | | #if LOG_CODE |
| 1344 | | //if (symfile) fclose(symfile); |
| 1345 | | #endif |
| 1346 | | ppcdrc_exit(); |
| 1347 | | } |
| 1348 | | #endif |
| 1349 | | |
| 1350 | | #if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240 || HAS_PPC604) |
| 1351 | | static void ppcdrc603_reset(void) |
| 1352 | | { |
| 1353 | | ppc.pc = ppc.npc = 0xfff00100; |
| 1354 | | |
| 1355 | | ppc_set_msr(0x40); |
| 1356 | | change_pc(ppc.pc); |
| 1357 | | |
| 1358 | | /* reset the DRC */ |
| 1359 | | drc_cache_reset(ppc.drc); |
| 1360 | | } |
| 1361 | | |
| 1362 | | static int ppcdrc603_execute(int cycles) |
| 1363 | | { |
| 1364 | | /* count cycles and interrupt cycles */ |
| 1365 | | ppc_icount = cycles; |
| 1366 | | ppc_tb_base_icount = cycles; |
| 1367 | | ppc_dec_base_icount = cycles + ppc.dec_frac; |
| 1368 | | |
| 1369 | | // check if decrementer exception occurs during execution |
| 1370 | | if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) |
| 1371 | | { |
| 1372 | | ppc_dec_trigger_cycle = ppc_icount - DEC; |
| 1373 | | } |
| 1374 | | else |
| 1375 | | { |
| 1376 | | ppc_dec_trigger_cycle = 0x7fffffff; |
| 1377 | | } |
| 1378 | | |
| 1379 | | drc_execute(ppc.drc); |
| 1380 | | |
| 1381 | | // update timebase |
| 1382 | | // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly |
| 1383 | | ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); |
| 1384 | | |
| 1385 | | // update decrementer |
| 1386 | | ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2)); |
| 1387 | | DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); |
| 1388 | | |
| 1389 | | return cycles - ppc_icount; |
| 1390 | | } |
| 1391 | | |
| 1392 | | static void ppcdrc603_set_irq_line(int irqline, int state) |
| 1393 | | { |
| 1394 | | if( state ) { |
| 1395 | | ppc.exception_pending |= 0x1; |
| 1396 | | if (ppc.irq_callback) |
| 1397 | | { |
| 1398 | | ppc.irq_callback(irqline); |
| 1399 | | } |
| 1400 | | } |
| 1401 | | } |
| 1402 | | #endif |
| 1403 | | |
| 1404 | | #if (HAS_PPC602) |
| 1405 | | static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1406 | | { |
| 1407 | | float multiplier; |
| 1408 | | const ppc_config *config = _config; |
| 1409 | | int i; |
| 1410 | | |
| 1411 | | ppc_init(); |
| 1412 | | ppcdrc_init(); |
| 1413 | | |
| 1414 | | ppc.optable[48] = recompile_lfs; |
| 1415 | | ppc.optable[49] = recompile_lfsu; |
| 1416 | | ppc.optable[50] = recompile_lfd; |
| 1417 | | ppc.optable[51] = recompile_lfdu; |
| 1418 | | ppc.optable[52] = recompile_stfs; |
| 1419 | | ppc.optable[53] = recompile_stfsu; |
| 1420 | | ppc.optable[54] = recompile_stfd; |
| 1421 | | ppc.optable[55] = recompile_stfdu; |
| 1422 | | ppc.optable31[631] = recompile_lfdux; |
| 1423 | | ppc.optable31[599] = recompile_lfdx; |
| 1424 | | ppc.optable31[567] = recompile_lfsux; |
| 1425 | | ppc.optable31[535] = recompile_lfsx; |
| 1426 | | ppc.optable31[595] = recompile_mfsr; |
| 1427 | | ppc.optable31[659] = recompile_mfsrin; |
| 1428 | | ppc.optable31[371] = recompile_mftb; |
| 1429 | | ppc.optable31[210] = recompile_mtsr; |
| 1430 | | ppc.optable31[242] = recompile_mtsrin; |
| 1431 | | ppc.optable31[758] = recompile_dcba; |
| 1432 | | ppc.optable31[759] = recompile_stfdux; |
| 1433 | | ppc.optable31[727] = recompile_stfdx; |
| 1434 | | ppc.optable31[983] = recompile_stfiwx; |
| 1435 | | ppc.optable31[695] = recompile_stfsux; |
| 1436 | | ppc.optable31[663] = recompile_stfsx; |
| 1437 | | ppc.optable31[370] = recompile_tlbia; |
| 1438 | | ppc.optable31[306] = recompile_tlbie; |
| 1439 | | ppc.optable31[566] = recompile_tlbsync; |
| 1440 | | ppc.optable31[310] = recompile_eciwx; |
| 1441 | | ppc.optable31[438] = recompile_ecowx; |
| 1442 | | |
| 1443 | | ppc.optable63[264] = recompile_fabsx; |
| 1444 | | ppc.optable63[21] = recompile_faddx; |
| 1445 | | ppc.optable63[32] = recompile_fcmpo; |
| 1446 | | ppc.optable63[0] = recompile_fcmpu; |
| 1447 | | ppc.optable63[14] = recompile_fctiwx; |
| 1448 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1449 | | ppc.optable63[18] = recompile_fdivx; |
| 1450 | | ppc.optable63[72] = recompile_fmrx; |
| 1451 | | ppc.optable63[136] = recompile_fnabsx; |
| 1452 | | ppc.optable63[40] = recompile_fnegx; |
| 1453 | | ppc.optable63[12] = recompile_frspx; |
| 1454 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1455 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1456 | | ppc.optable63[20] = recompile_fsubx; |
| 1457 | | ppc.optable63[583] = recompile_mffsx; |
| 1458 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1459 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1460 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1461 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1462 | | ppc.optable63[64] = recompile_mcrfs; |
| 1463 | | |
| 1464 | | ppc.optable59[21] = recompile_faddsx; |
| 1465 | | ppc.optable59[18] = recompile_fdivsx; |
| 1466 | | ppc.optable59[24] = recompile_fresx; |
| 1467 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1468 | | ppc.optable59[20] = recompile_fsubsx; |
| 1469 | | |
| 1470 | | for(i = 0; i < 32; i++) |
| 1471 | | { |
| 1472 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1473 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1474 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1475 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1476 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1477 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 1478 | | |
| 1479 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1480 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1481 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1482 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1483 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1484 | | } |
| 1485 | | |
| 1486 | | for(i = 0; i < 256; i++) |
| 1487 | | { |
| 1488 | | ppc_field_xlat[i] = |
| 1489 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1490 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1491 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1492 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1493 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1494 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1495 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1496 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1497 | | } |
| 1498 | | |
| 1499 | | // PPC602 specific opcodes |
| 1500 | | ppc.optable31[596] = recompile_esa; |
| 1501 | | ppc.optable31[628] = recompile_dsa; |
| 1502 | | ppc.optable31[1010] = recompile_tlbli; |
| 1503 | | ppc.optable31[978] = recompile_tlbld; |
| 1504 | | |
| 1505 | | ppc.is603 = 0; |
| 1506 | | ppc.is602 = 1; |
| 1507 | | |
| 1508 | | ppc.read8 = program_read_byte_64be; |
| 1509 | | ppc.read16 = program_read_word_64be; |
| 1510 | | ppc.read32 = program_read_dword_64be; |
| 1511 | | ppc.read64 = program_read_qword_64be; |
| 1512 | | ppc.write8 = program_write_byte_64be; |
| 1513 | | ppc.write16 = program_write_word_64be; |
| 1514 | | ppc.write32 = program_write_dword_64be; |
| 1515 | | ppc.write64 = program_write_qword_64be; |
| 1516 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1517 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1518 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1519 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1520 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1521 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1522 | | |
| 1523 | | ppc.irq_callback = irqcallback; |
| 1524 | | |
| 1525 | | ppc.pvr = config->pvr; |
| 1526 | | |
| 1527 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1528 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1529 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1530 | | } |
| 1531 | | |
| 1532 | | static void ppcdrc602_exit(void) |
| 1533 | | { |
| 1534 | | #if LOG_CODE |
| 1535 | | //if (symfile) fclose(symfile); |
| 1536 | | #endif |
| 1537 | | ppcdrc_exit(); |
| 1538 | | } |
| 1539 | | |
| 1540 | | static void ppcdrc602_reset(void) |
| 1541 | | { |
| 1542 | | ppc.pc = ppc.npc = 0xfff00100; |
| 1543 | | |
| 1544 | | ppc_set_msr(0x40); |
| 1545 | | change_pc(ppc.pc); |
| 1546 | | |
| 1547 | | ppc.hid0 = 1; |
| 1548 | | |
| 1549 | | /* reset the DRC */ |
| 1550 | | drc_cache_reset(ppc.drc); |
| 1551 | | } |
| 1552 | | |
| 1553 | | static int ppcdrc602_execute(int cycles) |
| 1554 | | { |
| 1555 | | /* count cycles and interrupt cycles */ |
| 1556 | | ppc_icount = cycles; |
| 1557 | | ppc_tb_base_icount = cycles; |
| 1558 | | ppc_dec_base_icount = cycles; |
| 1559 | | |
| 1560 | | // check if decrementer exception occurs during execution |
| 1561 | | if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) |
| 1562 | | { |
| 1563 | | ppc_dec_trigger_cycle = ppc_icount - DEC; |
| 1564 | | } |
| 1565 | | else |
| 1566 | | { |
| 1567 | | ppc_dec_trigger_cycle = 0x7fffffff; |
| 1568 | | } |
| 1569 | | |
| 1570 | | drc_execute(ppc.drc); |
| 1571 | | |
| 1572 | | // update timebase |
| 1573 | | // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly |
| 1574 | | ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); |
| 1575 | | |
| 1576 | | // update decrementer |
| 1577 | | DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); |
| 1578 | | |
| 1579 | | return cycles - ppc_icount; |
| 1580 | | } |
| 1581 | | |
| 1582 | | static void ppcdrc602_set_irq_line(int irqline, int state) |
| 1583 | | { |
| 1584 | | if( state ) { |
| 1585 | | ppc.exception_pending |= 0x1; |
| 1586 | | if (ppc.irq_callback) |
| 1587 | | { |
| 1588 | | ppc.irq_callback(irqline); |
| 1589 | | } |
| 1590 | | } |
| 1591 | | } |
| 1592 | | #endif |
| 1593 | | |
| 1594 | | #if (HAS_MPC8240) |
| 1595 | | static void mpc8240drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1596 | | { |
| 1597 | | float multiplier; |
| 1598 | | const ppc_config *config = _config; |
| 1599 | | int i; |
| 1600 | | |
| 1601 | | ppc_init(); |
| 1602 | | ppcdrc_init(); |
| 1603 | | |
| 1604 | | ppc.optable[48] = recompile_lfs; |
| 1605 | | ppc.optable[49] = recompile_lfsu; |
| 1606 | | ppc.optable[50] = recompile_lfd; |
| 1607 | | ppc.optable[51] = recompile_lfdu; |
| 1608 | | ppc.optable[52] = recompile_stfs; |
| 1609 | | ppc.optable[53] = recompile_stfsu; |
| 1610 | | ppc.optable[54] = recompile_stfd; |
| 1611 | | ppc.optable[55] = recompile_stfdu; |
| 1612 | | ppc.optable31[631] = recompile_lfdux; |
| 1613 | | ppc.optable31[599] = recompile_lfdx; |
| 1614 | | ppc.optable31[567] = recompile_lfsux; |
| 1615 | | ppc.optable31[535] = recompile_lfsx; |
| 1616 | | ppc.optable31[595] = recompile_mfsr; |
| 1617 | | ppc.optable31[659] = recompile_mfsrin; |
| 1618 | | ppc.optable31[371] = recompile_mftb; |
| 1619 | | ppc.optable31[210] = recompile_mtsr; |
| 1620 | | ppc.optable31[242] = recompile_mtsrin; |
| 1621 | | ppc.optable31[758] = recompile_dcba; |
| 1622 | | ppc.optable31[759] = recompile_stfdux; |
| 1623 | | ppc.optable31[727] = recompile_stfdx; |
| 1624 | | ppc.optable31[983] = recompile_stfiwx; |
| 1625 | | ppc.optable31[695] = recompile_stfsux; |
| 1626 | | ppc.optable31[663] = recompile_stfsx; |
| 1627 | | ppc.optable31[370] = recompile_tlbia; |
| 1628 | | ppc.optable31[306] = recompile_tlbie; |
| 1629 | | ppc.optable31[566] = recompile_tlbsync; |
| 1630 | | ppc.optable31[310] = recompile_eciwx; |
| 1631 | | ppc.optable31[438] = recompile_ecowx; |
| 1632 | | |
| 1633 | | ppc.optable63[264] = recompile_fabsx; |
| 1634 | | ppc.optable63[21] = recompile_faddx; |
| 1635 | | ppc.optable63[32] = recompile_fcmpo; |
| 1636 | | ppc.optable63[0] = recompile_fcmpu; |
| 1637 | | ppc.optable63[14] = recompile_fctiwx; |
| 1638 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1639 | | ppc.optable63[18] = recompile_fdivx; |
| 1640 | | ppc.optable63[72] = recompile_fmrx; |
| 1641 | | ppc.optable63[136] = recompile_fnabsx; |
| 1642 | | ppc.optable63[40] = recompile_fnegx; |
| 1643 | | ppc.optable63[12] = recompile_frspx; |
| 1644 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1645 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1646 | | ppc.optable63[20] = recompile_fsubx; |
| 1647 | | ppc.optable63[583] = recompile_mffsx; |
| 1648 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1649 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1650 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1651 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1652 | | ppc.optable63[64] = recompile_mcrfs; |
| 1653 | | |
| 1654 | | ppc.optable59[21] = recompile_faddsx; |
| 1655 | | ppc.optable59[18] = recompile_fdivsx; |
| 1656 | | ppc.optable59[24] = recompile_fresx; |
| 1657 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1658 | | ppc.optable59[20] = recompile_fsubsx; |
| 1659 | | |
| 1660 | | for(i = 0; i < 32; i++) |
| 1661 | | { |
| 1662 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1663 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1664 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1665 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1666 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1667 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 1668 | | |
| 1669 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1670 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1671 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1672 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1673 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1674 | | } |
| 1675 | | |
| 1676 | | for(i = 0; i < 256; i++) |
| 1677 | | { |
| 1678 | | ppc_field_xlat[i] = |
| 1679 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1680 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1681 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1682 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1683 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1684 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1685 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1686 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1687 | | } |
| 1688 | | |
| 1689 | | // MPC8240 specific opcodes |
| 1690 | | ppc.optable31[978] = recompile_tlbld; |
| 1691 | | ppc.optable31[1010] = recompile_tlbli; |
| 1692 | | |
| 1693 | | ppc.is603 = 1; |
| 1694 | | |
| 1695 | | ppc.read8 = program_read_byte_64be; |
| 1696 | | ppc.read16 = program_read_word_64be; |
| 1697 | | ppc.read32 = program_read_dword_64be; |
| 1698 | | ppc.read64 = program_read_qword_64be; |
| 1699 | | ppc.write8 = program_write_byte_64be; |
| 1700 | | ppc.write16 = program_write_word_64be; |
| 1701 | | ppc.write32 = program_write_dword_64be; |
| 1702 | | ppc.write64 = program_write_qword_64be; |
| 1703 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1704 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1705 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1706 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1707 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1708 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1709 | | |
| 1710 | | ppc.irq_callback = irqcallback; |
| 1711 | | |
| 1712 | | ppc.pvr = config->pvr; |
| 1713 | | |
| 1714 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1715 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1716 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1717 | | } |
| 1718 | | |
| 1719 | | static void mpc8240drc_exit(void) |
| 1720 | | { |
| 1721 | | ppcdrc_exit(); |
| 1722 | | } |
| 1723 | | #endif |
| 1724 | | |
| 1725 | | |
| 1726 | | #if (HAS_PPC601) |
| 1727 | | static void ppc601drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1728 | | { |
| 1729 | | int pll_config = 0; |
| 1730 | | float multiplier; |
| 1731 | | const ppc_config *config = _config; |
| 1732 | | int i; |
| 1733 | | |
| 1734 | | ppc_init(); |
| 1735 | | ppcdrc_init(); |
| 1736 | | |
| 1737 | | ppc.optable[48] = recompile_lfs; |
| 1738 | | ppc.optable[49] = recompile_lfsu; |
| 1739 | | ppc.optable[50] = recompile_lfd; |
| 1740 | | ppc.optable[51] = recompile_lfdu; |
| 1741 | | ppc.optable[52] = recompile_stfs; |
| 1742 | | ppc.optable[53] = recompile_stfsu; |
| 1743 | | ppc.optable[54] = recompile_stfd; |
| 1744 | | ppc.optable[55] = recompile_stfdu; |
| 1745 | | ppc.optable31[631] = recompile_lfdux; |
| 1746 | | ppc.optable31[599] = recompile_lfdx; |
| 1747 | | ppc.optable31[567] = recompile_lfsux; |
| 1748 | | ppc.optable31[535] = recompile_lfsx; |
| 1749 | | ppc.optable31[595] = recompile_mfsr; |
| 1750 | | ppc.optable31[659] = recompile_mfsrin; |
| 1751 | | ppc.optable31[371] = recompile_mftb; |
| 1752 | | ppc.optable31[210] = recompile_mtsr; |
| 1753 | | ppc.optable31[242] = recompile_mtsrin; |
| 1754 | | ppc.optable31[758] = recompile_dcba; |
| 1755 | | ppc.optable31[759] = recompile_stfdux; |
| 1756 | | ppc.optable31[727] = recompile_stfdx; |
| 1757 | | ppc.optable31[983] = recompile_stfiwx; |
| 1758 | | ppc.optable31[695] = recompile_stfsux; |
| 1759 | | ppc.optable31[663] = recompile_stfsx; |
| 1760 | | ppc.optable31[370] = recompile_tlbia; |
| 1761 | | ppc.optable31[306] = recompile_tlbie; |
| 1762 | | ppc.optable31[566] = recompile_tlbsync; |
| 1763 | | ppc.optable31[310] = recompile_eciwx; |
| 1764 | | ppc.optable31[438] = recompile_ecowx; |
| 1765 | | |
| 1766 | | ppc.optable63[264] = recompile_fabsx; |
| 1767 | | ppc.optable63[21] = recompile_faddx; |
| 1768 | | ppc.optable63[32] = recompile_fcmpo; |
| 1769 | | ppc.optable63[0] = recompile_fcmpu; |
| 1770 | | ppc.optable63[14] = recompile_fctiwx; |
| 1771 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1772 | | ppc.optable63[18] = recompile_fdivx; |
| 1773 | | ppc.optable63[72] = recompile_fmrx; |
| 1774 | | ppc.optable63[136] = recompile_fnabsx; |
| 1775 | | ppc.optable63[40] = recompile_fnegx; |
| 1776 | | ppc.optable63[12] = recompile_frspx; |
| 1777 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1778 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1779 | | ppc.optable63[20] = recompile_fsubx; |
| 1780 | | ppc.optable63[583] = recompile_mffsx; |
| 1781 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1782 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1783 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1784 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1785 | | ppc.optable63[64] = recompile_mcrfs; |
| 1786 | | |
| 1787 | | ppc.optable59[21] = recompile_faddsx; |
| 1788 | | ppc.optable59[18] = recompile_fdivsx; |
| 1789 | | ppc.optable59[24] = recompile_fresx; |
| 1790 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1791 | | ppc.optable59[20] = recompile_fsubsx; |
| 1792 | | |
| 1793 | | for(i = 0; i < 32; i++) |
| 1794 | | { |
| 1795 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1796 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1797 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1798 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1799 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1800 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 1801 | | |
| 1802 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1803 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1804 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1805 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1806 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1807 | | } |
| 1808 | | |
| 1809 | | for(i = 0; i < 256; i++) |
| 1810 | | { |
| 1811 | | ppc_field_xlat[i] = |
| 1812 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1813 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1814 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1815 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1816 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1817 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1818 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1819 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1820 | | } |
| 1821 | | |
| 1822 | | ppc.is603 = 1; |
| 1823 | | |
| 1824 | | ppc.read8 = program_read_byte_64be; |
| 1825 | | ppc.read16 = program_read_word_64be; |
| 1826 | | ppc.read32 = program_read_dword_64be; |
| 1827 | | ppc.read64 = program_read_qword_64be; |
| 1828 | | ppc.write8 = program_write_byte_64be; |
| 1829 | | ppc.write16 = program_write_word_64be; |
| 1830 | | ppc.write32 = program_write_dword_64be; |
| 1831 | | ppc.write64 = program_write_qword_64be; |
| 1832 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1833 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1834 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1835 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1836 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1837 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1838 | | |
| 1839 | | ppc.irq_callback = irqcallback; |
| 1840 | | |
| 1841 | | ppc.pvr = config->pvr; |
| 1842 | | |
| 1843 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1844 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1845 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1846 | | |
| 1847 | | switch(config->pvr) |
| 1848 | | { |
| 1849 | | case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1850 | | case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1851 | | case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1852 | | default: break; |
| 1853 | | } |
| 1854 | | |
| 1855 | | if (pll_config == -1) |
| 1856 | | { |
| 1857 | | fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); |
| 1858 | | } |
| 1859 | | |
| 1860 | | ppc.hid1 = pll_config << 28; |
| 1861 | | } |
| 1862 | | |
| 1863 | | static void ppc601drc_exit(void) |
| 1864 | | { |
| 1865 | | #if LOG_CODE |
| 1866 | | //if (symfile) fclose(symfile); |
| 1867 | | #endif |
| 1868 | | ppcdrc_exit(); |
| 1869 | | } |
| 1870 | | #endif |
| 1871 | | |
| 1872 | | |
| 1873 | | #if (HAS_PPC604) |
| 1874 | | static void ppc604drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1875 | | { |
| 1876 | | float multiplier; |
| 1877 | | const ppc_config *config = _config; |
| 1878 | | int i; |
| 1879 | | |
| 1880 | | ppc_init(); |
| 1881 | | ppcdrc_init(); |
| 1882 | | |
| 1883 | | ppc.optable[48] = recompile_lfs; |
| 1884 | | ppc.optable[49] = recompile_lfsu; |
| 1885 | | ppc.optable[50] = recompile_lfd; |
| 1886 | | ppc.optable[51] = recompile_lfdu; |
| 1887 | | ppc.optable[52] = recompile_stfs; |
| 1888 | | ppc.optable[53] = recompile_stfsu; |
| 1889 | | ppc.optable[54] = recompile_stfd; |
| 1890 | | ppc.optable[55] = recompile_stfdu; |
| 1891 | | ppc.optable31[631] = recompile_lfdux; |
| 1892 | | ppc.optable31[599] = recompile_lfdx; |
| 1893 | | ppc.optable31[567] = recompile_lfsux; |
| 1894 | | ppc.optable31[535] = recompile_lfsx; |
| 1895 | | ppc.optable31[595] = recompile_mfsr; |
| 1896 | | ppc.optable31[659] = recompile_mfsrin; |
| 1897 | | ppc.optable31[371] = recompile_mftb; |
| 1898 | | ppc.optable31[210] = recompile_mtsr; |
| 1899 | | ppc.optable31[242] = recompile_mtsrin; |
| 1900 | | ppc.optable31[758] = recompile_dcba; |
| 1901 | | ppc.optable31[759] = recompile_stfdux; |
| 1902 | | ppc.optable31[727] = recompile_stfdx; |
| 1903 | | ppc.optable31[983] = recompile_stfiwx; |
| 1904 | | ppc.optable31[695] = recompile_stfsux; |
| 1905 | | ppc.optable31[663] = recompile_stfsx; |
| 1906 | | ppc.optable31[370] = recompile_tlbia; |
| 1907 | | ppc.optable31[306] = recompile_tlbie; |
| 1908 | | ppc.optable31[566] = recompile_tlbsync; |
| 1909 | | ppc.optable31[310] = recompile_eciwx; |
| 1910 | | ppc.optable31[438] = recompile_ecowx; |
| 1911 | | |
| 1912 | | ppc.optable63[264] = recompile_fabsx; |
| 1913 | | ppc.optable63[21] = recompile_faddx; |
| 1914 | | ppc.optable63[32] = recompile_fcmpo; |
| 1915 | | ppc.optable63[0] = recompile_fcmpu; |
| 1916 | | ppc.optable63[14] = recompile_fctiwx; |
| 1917 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1918 | | ppc.optable63[18] = recompile_fdivx; |
| 1919 | | ppc.optable63[72] = recompile_fmrx; |
| 1920 | | ppc.optable63[136] = recompile_fnabsx; |
| 1921 | | ppc.optable63[40] = recompile_fnegx; |
| 1922 | | ppc.optable63[12] = recompile_frspx; |
| 1923 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1924 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1925 | | ppc.optable63[20] = recompile_fsubx; |
| 1926 | | ppc.optable63[583] = recompile_mffsx; |
| 1927 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1928 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1929 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1930 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1931 | | ppc.optable63[64] = recompile_mcrfs; |
| 1932 | | |
| 1933 | | ppc.optable59[21] = recompile_faddsx; |
| 1934 | | ppc.optable59[18] = recompile_fdivsx; |
| 1935 | | ppc.optable59[24] = recompile_fresx; |
| 1936 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1937 | | ppc.optable59[20] = recompile_fsubsx; |
| 1938 | | |
| 1939 | | for(i = 0; i < 32; i++) |
| 1940 | | { |
| 1941 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1942 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1943 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1944 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1945 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1946 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 1947 | | |
| 1948 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1949 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1950 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1951 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1952 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1953 | | } |
| 1954 | | |
| 1955 | | ppc.optable31[978] = recompile_tlbld; |
| 1956 | | |
| 1957 | | for(i = 0; i < 256; i++) |
| 1958 | | { |
| 1959 | | ppc_field_xlat[i] = |
| 1960 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1961 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1962 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1963 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1964 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1965 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1966 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1967 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1968 | | } |
| 1969 | | |
| 1970 | | ppc.is603 = 1; |
| 1971 | | |
| 1972 | | ppc.read8 = program_read_byte_64be; |
| 1973 | | ppc.read16 = program_read_word_64be; |
| 1974 | | ppc.read32 = program_read_dword_64be; |
| 1975 | | ppc.read64 = program_read_qword_64be; |
| 1976 | | ppc.write8 = program_write_byte_64be; |
| 1977 | | ppc.write16 = program_write_word_64be; |
| 1978 | | ppc.write32 = program_write_dword_64be; |
| 1979 | | ppc.write64 = program_write_qword_64be; |
| 1980 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1981 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1982 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1983 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1984 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1985 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1986 | | |
| 1987 | | ppc.irq_callback = irqcallback; |
| 1988 | | |
| 1989 | | ppc.pvr = config->pvr; |
| 1990 | | |
| 1991 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1992 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1993 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1994 | | } |
| 1995 | | |
| 1996 | | static void ppc604drc_exit(void) |
| 1997 | | { |
| 1998 | | #if LOG_CODE |
| 1999 | | //if (symfile) fclose(symfile); |
| 2000 | | #endif |
| 2001 | | ppcdrc_exit(); |
| 2002 | | } |
| 2003 | | #endif |
| 2004 | | |
| 2005 | | |
| 2006 | | static void ppc_get_context(void *dst) |
| 2007 | | { |
| 2008 | | /* copy the context */ |
| 2009 | | if (dst) |
| 2010 | | *(PPC_REGS *)dst = ppc; |
| 2011 | | } |
| 2012 | | |
| 2013 | | |
| 2014 | | static void ppc_set_context(void *src) |
| 2015 | | { |
| 2016 | | /* copy the context */ |
| 2017 | | if (src) |
| 2018 | | ppc = *(PPC_REGS *)src; |
| 2019 | | |
| 2020 | | change_pc(ppc.pc); |
| 2021 | | } |
| 2022 | | |
| 2023 | | |
| 2024 | | /************************************************************************** |
| 2025 | | * Generic set_info |
| 2026 | | **************************************************************************/ |
| 2027 | | |
| 2028 | | static void ppc_set_info(UINT32 state, cpuinfo *info) |
| 2029 | | { |
| 2030 | | switch (state) |
| 2031 | | { |
| 2032 | | case CPUINFO_INT_PC: |
| 2033 | | case CPUINFO_INT_REGISTER + PPC_PC: ppc.pc = info->i; break; |
| 2034 | | case CPUINFO_INT_REGISTER + PPC_MSR: ppc_set_msr(info->i); break; |
| 2035 | | case CPUINFO_INT_REGISTER + PPC_CR: ppc_set_cr(info->i); break; |
| 2036 | | case CPUINFO_INT_REGISTER + PPC_LR: LR = info->i; break; |
| 2037 | | case CPUINFO_INT_REGISTER + PPC_CTR: CTR = info->i; break; |
| 2038 | | case CPUINFO_INT_REGISTER + PPC_XER: XER = info->i; break; |
| 2039 | | case CPUINFO_INT_REGISTER + PPC_SRR0: SRR0 = info->i; break; |
| 2040 | | case CPUINFO_INT_REGISTER + PPC_SRR1: SRR1 = info->i; break; |
| 2041 | | |
| 2042 | | case CPUINFO_INT_REGISTER + PPC_R0: ppc.r[0] = info->i; break; |
| 2043 | | case CPUINFO_INT_REGISTER + PPC_R1: ppc.r[1] = info->i; break; |
| 2044 | | case CPUINFO_INT_REGISTER + PPC_R2: ppc.r[2] = info->i; break; |
| 2045 | | case CPUINFO_INT_REGISTER + PPC_R3: ppc.r[3] = info->i; break; |
| 2046 | | case CPUINFO_INT_REGISTER + PPC_R4: ppc.r[4] = info->i; break; |
| 2047 | | case CPUINFO_INT_REGISTER + PPC_R5: ppc.r[5] = info->i; break; |
| 2048 | | case CPUINFO_INT_REGISTER + PPC_R6: ppc.r[6] = info->i; break; |
| 2049 | | case CPUINFO_INT_REGISTER + PPC_R7: ppc.r[7] = info->i; break; |
| 2050 | | case CPUINFO_INT_REGISTER + PPC_R8: ppc.r[8] = info->i; break; |
| 2051 | | case CPUINFO_INT_REGISTER + PPC_R9: ppc.r[9] = info->i; break; |
| 2052 | | case CPUINFO_INT_REGISTER + PPC_R10: ppc.r[10] = info->i; break; |
| 2053 | | case CPUINFO_INT_REGISTER + PPC_R11: ppc.r[11] = info->i; break; |
| 2054 | | case CPUINFO_INT_REGISTER + PPC_R12: ppc.r[12] = info->i; break; |
| 2055 | | case CPUINFO_INT_REGISTER + PPC_R13: ppc.r[13] = info->i; break; |
| 2056 | | case CPUINFO_INT_REGISTER + PPC_R14: ppc.r[14] = info->i; break; |
| 2057 | | case CPUINFO_INT_REGISTER + PPC_R15: ppc.r[15] = info->i; break; |
| 2058 | | case CPUINFO_INT_REGISTER + PPC_R16: ppc.r[16] = info->i; break; |
| 2059 | | case CPUINFO_INT_REGISTER + PPC_R17: ppc.r[17] = info->i; break; |
| 2060 | | case CPUINFO_INT_REGISTER + PPC_R18: ppc.r[18] = info->i; break; |
| 2061 | | case CPUINFO_INT_REGISTER + PPC_R19: ppc.r[19] = info->i; break; |
| 2062 | | case CPUINFO_INT_REGISTER + PPC_R20: ppc.r[20] = info->i; break; |
| 2063 | | case CPUINFO_INT_REGISTER + PPC_R21: ppc.r[21] = info->i; break; |
| 2064 | | case CPUINFO_INT_REGISTER + PPC_R22: ppc.r[22] = info->i; break; |
| 2065 | | case CPUINFO_INT_REGISTER + PPC_R23: ppc.r[23] = info->i; break; |
| 2066 | | case CPUINFO_INT_REGISTER + PPC_R24: ppc.r[24] = info->i; break; |
| 2067 | | case CPUINFO_INT_REGISTER + PPC_R25: ppc.r[25] = info->i; break; |
| 2068 | | case CPUINFO_INT_REGISTER + PPC_R26: ppc.r[26] = info->i; break; |
| 2069 | | case CPUINFO_INT_REGISTER + PPC_R27: ppc.r[27] = info->i; break; |
| 2070 | | case CPUINFO_INT_REGISTER + PPC_R28: ppc.r[28] = info->i; break; |
| 2071 | | case CPUINFO_INT_REGISTER + PPC_R29: ppc.r[29] = info->i; break; |
| 2072 | | case CPUINFO_INT_REGISTER + PPC_R30: ppc.r[30] = info->i; break; |
| 2073 | | case CPUINFO_INT_REGISTER + PPC_R31: ppc.r[31] = info->i; break; |
| 2074 | | |
| 2075 | | case CPUINFO_INT_PPC_DRC_OPTIONS: ppc.drcoptions = info->i; break; |
| 2076 | | } |
| 2077 | | } |
| 2078 | | |
| 2079 | | static void ppc_get_info(UINT32 state, cpuinfo *info) |
| 2080 | | { |
| 2081 | | switch(state) |
| 2082 | | { |
| 2083 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2084 | | case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break; |
| 2085 | | case CPUINFO_INT_INPUT_LINES: info->i = 1; break; |
| 2086 | | case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; |
| 2087 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2088 | | case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; |
| 2089 | | case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; |
| 2090 | | case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; |
| 2091 | | case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; |
| 2092 | | case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; |
| 2093 | | case CPUINFO_INT_MAX_CYCLES: info->i = 40; break; |
| 2094 | | |
| 2095 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2096 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2097 | | case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break; |
| 2098 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; |
| 2099 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; |
| 2100 | | case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break; |
| 2101 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; |
| 2102 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; |
| 2103 | | case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break; |
| 2104 | | |
| 2105 | | case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break; |
| 2106 | | |
| 2107 | | case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; |
| 2108 | | |
| 2109 | | case CPUINFO_INT_PC: /* intentional fallthrough */ |
| 2110 | | case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc.pc; break; |
| 2111 | | case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc_get_msr(); break; |
| 2112 | | case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc_get_cr(); break; |
| 2113 | | case CPUINFO_INT_REGISTER + PPC_LR: info->i = LR; break; |
| 2114 | | case CPUINFO_INT_REGISTER + PPC_CTR: info->i = CTR; break; |
| 2115 | | case CPUINFO_INT_REGISTER + PPC_XER: info->i = XER; break; |
| 2116 | | case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = SRR0; break; |
| 2117 | | case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = SRR1; break; |
| 2118 | | |
| 2119 | | case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc.r[0]; break; |
| 2120 | | case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc.r[1]; break; |
| 2121 | | case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc.r[2]; break; |
| 2122 | | case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc.r[3]; break; |
| 2123 | | case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc.r[4]; break; |
| 2124 | | case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc.r[5]; break; |
| 2125 | | case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc.r[6]; break; |
| 2126 | | case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc.r[7]; break; |
| 2127 | | case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc.r[8]; break; |
| 2128 | | case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc.r[9]; break; |
| 2129 | | case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc.r[10]; break; |
| 2130 | | case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc.r[11]; break; |
| 2131 | | case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc.r[12]; break; |
| 2132 | | case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc.r[13]; break; |
| 2133 | | case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc.r[14]; break; |
| 2134 | | case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc.r[15]; break; |
| 2135 | | case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc.r[16]; break; |
| 2136 | | case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc.r[17]; break; |
| 2137 | | case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc.r[18]; break; |
| 2138 | | case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc.r[19]; break; |
| 2139 | | case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc.r[20]; break; |
| 2140 | | case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc.r[21]; break; |
| 2141 | | case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc.r[22]; break; |
| 2142 | | case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc.r[23]; break; |
| 2143 | | case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc.r[24]; break; |
| 2144 | | case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc.r[25]; break; |
| 2145 | | case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc.r[26]; break; |
| 2146 | | case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc.r[27]; break; |
| 2147 | | case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc.r[28]; break; |
| 2148 | | case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc.r[29]; break; |
| 2149 | | case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc.r[30]; break; |
| 2150 | | case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc.r[31]; break; |
| 2151 | | |
| 2152 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2153 | | case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppc_get_context; break; |
| 2154 | | case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppc_set_context; break; |
| 2155 | | case CPUINFO_PTR_BURN: info->burn = NULL; break; |
| 2156 | | #ifdef ENABLE_DEBUGGER |
| 2157 | | case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppc_dasm; break; |
| 2158 | | #endif /* ENABLE_DEBUGGER */ |
| 2159 | | case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc_icount; break; |
| 2160 | | |
| 2161 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2162 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; |
| 2163 | | case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "PowerPC"); break; |
| 2164 | | case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break; |
| 2165 | | case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; |
| 2166 | | case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 2167 | | |
| 2168 | | case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; |
| 2169 | | |
| 2170 | | case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc.pc); break; |
| 2171 | | case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR: %08X", ppc_get_msr()); break; |
| 2172 | | case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc_get_cr()); break; |
| 2173 | | case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", LR); break; |
| 2174 | | case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR: %08X", CTR); break; |
| 2175 | | case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER: %08X", XER); break; |
| 2176 | | case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", SRR0); break; |
| 2177 | | case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", SRR1); break; |
| 2178 | | |
| 2179 | | case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc.r[0]); break; |
| 2180 | | case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc.r[1]); break; |
| 2181 | | case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc.r[2]); break; |
| 2182 | | case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc.r[3]); break; |
| 2183 | | case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc.r[4]); break; |
| 2184 | | case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc.r[5]); break; |
| 2185 | | case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc.r[6]); break; |
| 2186 | | case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc.r[7]); break; |
| 2187 | | case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc.r[8]); break; |
| 2188 | | case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc.r[9]); break; |
| 2189 | | case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10: %08X", ppc.r[10]); break; |
| 2190 | | case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11: %08X", ppc.r[11]); break; |
| 2191 | | case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12: %08X", ppc.r[12]); break; |
| 2192 | | case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13: %08X", ppc.r[13]); break; |
| 2193 | | case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14: %08X", ppc.r[14]); break; |
| 2194 | | case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15: %08X", ppc.r[15]); break; |
| 2195 | | case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16: %08X", ppc.r[16]); break; |
| 2196 | | case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17: %08X", ppc.r[17]); break; |
| 2197 | | case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18: %08X", ppc.r[18]); break; |
| 2198 | | case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19: %08X", ppc.r[19]); break; |
| 2199 | | case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20: %08X", ppc.r[20]); break; |
| 2200 | | case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21: %08X", ppc.r[21]); break; |
| 2201 | | case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22: %08X", ppc.r[22]); break; |
| 2202 | | case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23: %08X", ppc.r[23]); break; |
| 2203 | | case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24: %08X", ppc.r[24]); break; |
| 2204 | | case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25: %08X", ppc.r[25]); break; |
| 2205 | | case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26: %08X", ppc.r[26]); break; |
| 2206 | | case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27: %08X", ppc.r[27]); break; |
| 2207 | | case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28: %08X", ppc.r[28]); break; |
| 2208 | | case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29: %08X", ppc.r[29]); break; |
| 2209 | | case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30: %08X", ppc.r[30]); break; |
| 2210 | | case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31: %08X", ppc.r[31]); break; |
| 2211 | | } |
| 2212 | | } |
| 2213 | | |
| 2214 | | |
| 2215 | | |
| 2216 | | /* PowerPC 403 */ |
| 2217 | | #if (HAS_PPC403) |
| 2218 | | static void ppc403_set_info(UINT32 state, cpuinfo *info) |
| 2219 | | { |
| 2220 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2221 | | { |
| 2222 | | ppcdrc403_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2223 | | return; |
| 2224 | | } |
| 2225 | | switch(state) |
| 2226 | | { |
| 2227 | | default: ppc_set_info(state, info); break; |
| 2228 | | } |
| 2229 | | } |
| 2230 | | |
| 2231 | | void ppc403_get_info(UINT32 state, cpuinfo *info) |
| 2232 | | { |
| 2233 | | switch(state) |
| 2234 | | { |
| 2235 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2236 | | case CPUINFO_INT_INPUT_LINES: info->i = 7; break; |
| 2237 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2238 | | |
| 2239 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2240 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc403_set_info; break; |
| 2241 | | case CPUINFO_PTR_INIT: info->init = ppcdrc403_init; break; |
| 2242 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc403_reset; break; |
| 2243 | | case CPUINFO_PTR_EXIT: info->exit = ppcdrc403_exit; break; |
| 2244 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc403_execute; break; |
| 2245 | | |
| 2246 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2247 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; |
| 2248 | | |
| 2249 | | default: ppc_get_info(state, info); break; |
| 2250 | | } |
| 2251 | | } |
| 2252 | | #endif |
| 2253 | | |
| 2254 | | /* PowerPC 603 */ |
| 2255 | | #if (HAS_PPC603) |
| 2256 | | static void ppc603_set_info(UINT32 state, cpuinfo *info) |
| 2257 | | { |
| 2258 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2259 | | { |
| 2260 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2261 | | return; |
| 2262 | | } |
| 2263 | | switch(state) |
| 2264 | | { |
| 2265 | | case CPUINFO_INT_REGISTER + PPC_DEC: write_decrementer(info->i); break; |
| 2266 | | default: ppc_set_info(state, info); break; |
| 2267 | | } |
| 2268 | | } |
| 2269 | | |
| 2270 | | void ppc603_get_info(UINT32 state, cpuinfo *info) |
| 2271 | | { |
| 2272 | | switch(state) |
| 2273 | | { |
| 2274 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2275 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2276 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2277 | | case CPUINFO_INT_REGISTER + PPC_DEC: info->i = read_decrementer(); break; |
| 2278 | | |
| 2279 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2280 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2281 | | case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2282 | | case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break; |
| 2283 | | |
| 2284 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2285 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc603_set_info; break; |
| 2286 | | case CPUINFO_PTR_INIT: info->init = ppcdrc603_init; break; |
| 2287 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2288 | | case CPUINFO_PTR_EXIT: info->exit = ppcdrc603_exit; break; |
| 2289 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2290 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2291 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2292 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2293 | | case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break; |
| 2294 | | |
| 2295 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2296 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC603"); break; |
| 2297 | | case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", read_decrementer()); break; |
| 2298 | | |
| 2299 | | default: ppc_get_info(state, info); break; |
| 2300 | | } |
| 2301 | | } |
| 2302 | | #endif |
| 2303 | | |
| 2304 | | /* PowerPC 602 */ |
| 2305 | | #if (HAS_PPC602) |
| 2306 | | static void ppc602_set_info(UINT32 state, cpuinfo *info) |
| 2307 | | { |
| 2308 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2309 | | { |
| 2310 | | ppcdrc602_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2311 | | return; |
| 2312 | | } |
| 2313 | | switch(state) |
| 2314 | | { |
| 2315 | | default: ppc_set_info(state, info); break; |
| 2316 | | } |
| 2317 | | } |
| 2318 | | |
| 2319 | | void ppc602_get_info(UINT32 state, cpuinfo *info) |
| 2320 | | { |
| 2321 | | switch(state) |
| 2322 | | { |
| 2323 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2324 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2325 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2326 | | |
| 2327 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2328 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2329 | | case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2330 | | case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break; |
| 2331 | | |
| 2332 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2333 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc602_set_info; break; |
| 2334 | | case CPUINFO_PTR_INIT: info->init = ppcdrc602_init; break; |
| 2335 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc602_reset; break; |
| 2336 | | case CPUINFO_PTR_EXIT: info->exit = ppcdrc602_exit; break; |
| 2337 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc602_execute; break; |
| 2338 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2339 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2340 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2341 | | case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break; |
| 2342 | | |
| 2343 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2344 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC602"); break; |
| 2345 | | |
| 2346 | | default: ppc_get_info(state, info); break; |
| 2347 | | } |
| 2348 | | } |
| 2349 | | #endif |
| 2350 | | |
| 2351 | | /* Motorola MPC8240 */ |
| 2352 | | |
| 2353 | | #if (HAS_MPC8240) |
| 2354 | | static void mpc8240_set_info(UINT32 state, cpuinfo *info) |
| 2355 | | { |
| 2356 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2357 | | { |
| 2358 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2359 | | return; |
| 2360 | | } |
| 2361 | | switch(state) |
| 2362 | | { |
| 2363 | | default: ppc_set_info(state, info); break; |
| 2364 | | } |
| 2365 | | } |
| 2366 | | |
| 2367 | | void mpc8240_get_info(UINT32 state, cpuinfo *info) |
| 2368 | | { |
| 2369 | | switch(state) |
| 2370 | | { |
| 2371 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2372 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2373 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2374 | | |
| 2375 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2376 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2377 | | |
| 2378 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2379 | | case CPUINFO_PTR_SET_INFO: info->setinfo = mpc8240_set_info; break; |
| 2380 | | case CPUINFO_PTR_INIT: info->init = mpc8240drc_init; break; |
| 2381 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2382 | | case CPUINFO_PTR_EXIT: info->exit = mpc8240drc_exit; break; |
| 2383 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2384 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2385 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2386 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2387 | | |
| 2388 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2389 | | case CPUINFO_STR_NAME: strcpy(info->s, "MPC8240"); break; |
| 2390 | | |
| 2391 | | default: ppc_get_info(state, info); break; |
| 2392 | | } |
| 2393 | | } |
| 2394 | | #endif |
| 2395 | | |
| 2396 | | |
| 2397 | | /* PPC601 */ |
| 2398 | | |
| 2399 | | #if (HAS_PPC601) |
| 2400 | | static void ppc601_set_info(UINT32 state, cpuinfo *info) |
| 2401 | | { |
| 2402 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2403 | | { |
| 2404 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2405 | | return; |
| 2406 | | } |
| 2407 | | switch(state) |
| 2408 | | { |
| 2409 | | default: ppc_set_info(state, info); break; |
| 2410 | | } |
| 2411 | | } |
| 2412 | | |
| 2413 | | void ppc601_get_info(UINT32 state, cpuinfo *info) |
| 2414 | | { |
| 2415 | | switch(state) |
| 2416 | | { |
| 2417 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2418 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2419 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2420 | | |
| 2421 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2422 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2423 | | |
| 2424 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2425 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc601_set_info; break; |
| 2426 | | case CPUINFO_PTR_INIT: info->init = ppc601drc_init; break; |
| 2427 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2428 | | case CPUINFO_PTR_EXIT: info->exit = ppc601drc_exit; break; |
| 2429 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2430 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2431 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2432 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2433 | | |
| 2434 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2435 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC601"); break; |
| 2436 | | |
| 2437 | | default: ppc_get_info(state, info); break; |
| 2438 | | } |
| 2439 | | } |
| 2440 | | #endif |
| 2441 | | |
| 2442 | | /* PPC604 */ |
| 2443 | | |
| 2444 | | #if (HAS_PPC604) |
| 2445 | | static void ppc604_set_info(UINT32 state, cpuinfo *info) |
| 2446 | | { |
| 2447 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2448 | | { |
| 2449 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2450 | | return; |
| 2451 | | } |
| 2452 | | switch(state) |
| 2453 | | { |
| 2454 | | default: ppc_set_info(state, info); break; |
| 2455 | | } |
| 2456 | | } |
| 2457 | | |
| 2458 | | void ppc604_get_info(UINT32 state, cpuinfo *info) |
| 2459 | | { |
| 2460 | | switch(state) |
| 2461 | | { |
| 2462 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2463 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2464 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2465 | | |
| 2466 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2467 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2468 | | |
| 2469 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2470 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc604_set_info; break; |
| 2471 | | case CPUINFO_PTR_INIT: info->init = ppc604drc_init; break; |
| 2472 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2473 | | case CPUINFO_PTR_EXIT: info->exit = ppc604drc_exit; break; |
| 2474 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2475 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2476 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2477 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2478 | | |
| 2479 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2480 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC604"); break; |
| 2481 | | |
| 2482 | | default: ppc_get_info(state, info); break; |
| 2483 | | } |
| 2484 | | } |
| 2485 | | #endif |
src/emu/cpu/powerpc/ppcdrc.c
| r2821 | r2822 | |
| 1 | | /* |
| 2 | | PowerPC 4xx/6xx Dynamic Recompiler for x86 |
| 1 | /*************************************************************************** |
| 3 | 2 | |
| 4 | | Written by Ville Linde |
| 5 | | */ |
| 3 | ppcdrc.c |
| 6 | 4 | |
| 5 | Universal machine language-based PowerPC emulator. |
| 6 | |
| 7 | Copyright Aaron Giles |
| 8 | Released for general non-commercial use under the MAME license |
| 9 | Visit http://mamedev.org for licensing and usage restrictions. |
| 10 | |
| 11 | **************************************************************************** |
| 12 | |
| 13 | Future improvements/changes: |
| 14 | |
| 15 | * Timing for long instructions (stmw/lmw/mul/div/stswi) |
| 16 | |
| 17 | * Eliminate unnecessary flag calculations using information from the |
| 18 | frontend |
| 19 | |
| 20 | ***************************************************************************/ |
| 21 | |
| 22 | #include <stddef.h> |
| 23 | #include "cpuintrf.h" |
| 7 | 24 | #include "debugger.h" |
| 8 | | #include "ppc.h" |
| 9 | | #include "cpu/x86drc.h" |
| 25 | #include "ppccom.h" |
| 26 | #include "ppcfe.h" |
| 27 | #include "deprecat.h" |
| 28 | #include "cpu/drcfe.h" |
| 29 | #include "cpu/drcuml.h" |
| 30 | #include "cpu/drcumlsh.h" |
| 10 | 31 | |
| 32 | extern offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); |
| 11 | 33 | |
| 12 | | #define PPC_DRC |
| 13 | | #define LOG_CODE (0) |
| 14 | 34 | |
| 15 | | #define CACHE_SIZE (16 * 1024 * 1024) |
| 16 | | #define MAX_INSTRUCTIONS 512 |
| 17 | 35 | |
| 36 | /*************************************************************************** |
| 37 | DEBUGGING |
| 38 | ***************************************************************************/ |
| 18 | 39 | |
| 19 | | #if (HAS_PPC603) |
| 20 | | static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int)); |
| 21 | | static void ppcdrc603_exit(void); |
| 22 | | #endif |
| 23 | | #if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240 || HAS_PPC604) |
| 24 | | static void ppcdrc603_reset(void); |
| 25 | | static int ppcdrc603_execute(int cycles); |
| 26 | | static void ppcdrc603_set_irq_line(int irqline, int state); |
| 27 | | #endif |
| 28 | | #if (HAS_PPC602) |
| 29 | | static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int)); |
| 30 | | static void ppcdrc602_exit(void); |
| 31 | | static void ppcdrc602_reset(void); |
| 32 | | static int ppcdrc602_execute(int cycles); |
| 33 | | static void ppcdrc602_set_irq_line(int irqline, int state); |
| 34 | | #endif |
| 35 | | #if (HAS_PPC403) |
| 36 | | static UINT8 ppc403_spu_r(UINT32 a); |
| 37 | | static void ppc403_spu_w(UINT32 a, UINT8 d); |
| 38 | | static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int)); |
| 39 | | static void ppcdrc403_exit(void); |
| 40 | | static void ppcdrc403_reset(void); |
| 41 | | static int ppcdrc403_execute(int cycles); |
| 42 | | static void ppcdrc403_set_irq_line(int irqline, int state); |
| 43 | | #endif |
| 40 | #define FORCE_C_BACKEND (0) |
| 41 | #define LOG_UML (0) |
| 42 | #define LOG_NATIVE (0) |
| 44 | 43 | |
| 45 | | static void ppcdrc_init(void); |
| 46 | | static void ppcdrc_reset(drc_core *drc); |
| 47 | | static void ppcdrc_recompile(drc_core *drc); |
| 48 | | static void ppcdrc_entrygen(drc_core *drc); |
| 44 | #define DISABLE_FAST_REGISTERS (0) |
| 45 | #define SINGLE_INSTRUCTION_MODE (0) |
| 49 | 46 | |
| 50 | | #define RD ((op >> 21) & 0x1F) |
| 51 | | #define RT ((op >> 21) & 0x1f) |
| 52 | | #define RS ((op >> 21) & 0x1f) |
| 53 | | #define RA ((op >> 16) & 0x1f) |
| 54 | | #define RB ((op >> 11) & 0x1f) |
| 55 | | #define RC ((op >> 6) & 0x1f) |
| 47 | #define PRINTF_EXCEPTIONS (0) |
| 48 | #define PRINTF_MMU (0) |
| 56 | 49 | |
| 57 | | #define MB ((op >> 6) & 0x1f) |
| 58 | | #define ME ((op >> 1) & 0x1f) |
| 59 | | #define SH ((op >> 11) & 0x1f) |
| 60 | | #define BO ((op >> 21) & 0x1f) |
| 61 | | #define BI ((op >> 16) & 0x1f) |
| 62 | | #define CRFD ((op >> 23) & 0x7) |
| 63 | | #define CRFA ((op >> 18) & 0x7) |
| 64 | | #define FXM ((op >> 12) & 0xff) |
| 65 | | #define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) |
| 50 | #define PROBE_ADDRESS ~0 |
| 66 | 51 | |
| 67 | | #define SIMM16 (INT32)(INT16)(op & 0xffff) |
| 68 | | #define UIMM16 (UINT32)(op & 0xffff) |
| 69 | 52 | |
| 70 | | #define RCBIT (op & 0x1) |
| 71 | | #define OEBIT (op & 0x400) |
| 72 | | #define AABIT (op & 0x2) |
| 73 | | #define LKBIT (op & 0x1) |
| 74 | 53 | |
| 75 | | #define REG(x) (ppc.r[x]) |
| 76 | | #define LR (ppc.lr) |
| 77 | | #define CTR (ppc.ctr) |
| 78 | | #define XER (ppc.xer) |
| 79 | | #define CR(x) (ppc.cr[x]) |
| 80 | | #define MSR (ppc.msr) |
| 81 | | #define SRR0 (ppc.srr0) |
| 82 | | #define SRR1 (ppc.srr1) |
| 83 | | #define SRR2 (ppc.srr2) |
| 84 | | #define SRR3 (ppc.srr3) |
| 85 | | #define EVPR (ppc.evpr) |
| 86 | | #define EXIER (ppc.exier) |
| 87 | | #define EXISR (ppc.exisr) |
| 88 | | #define DEC (ppc.dec) |
| 54 | /*************************************************************************** |
| 55 | CONSTANTS |
| 56 | ***************************************************************************/ |
| 89 | 57 | |
| 58 | /* map variables */ |
| 59 | #define MAPVAR_PC MVAR(0) |
| 60 | #define MAPVAR_CYCLES MVAR(1) |
| 61 | #define MAPVAR_DSISR MVAR(2) |
| 90 | 62 | |
| 91 | | // Stuff added for the 6xx |
| 92 | | #define FPR(x) (ppc.fpr[x]) |
| 93 | | #define FM ((op >> 17) & 0xFF) |
| 94 | | #define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) |
| 63 | /* mode bits */ |
| 64 | #define MODE_LITTLE_ENDIAN 0x01 |
| 65 | #define MODE_DATA_TRANSLATION 0x02 |
| 66 | #define MODE_USER 0x04 |
| 95 | 67 | |
| 68 | /* size of the execution code cache */ |
| 69 | #define CACHE_SIZE (32 * 1024 * 1024) |
| 96 | 70 | |
| 97 | | #define CHECK_SUPERVISOR() \ |
| 98 | | if((ppc.msr & 0x4000) != 0){ \ |
| 99 | | } |
| 71 | /* compilation boundaries -- how far back/forward does the analysis extend? */ |
| 72 | #define COMPILE_BACKWARDS_BYTES 128 |
| 73 | #define COMPILE_FORWARDS_BYTES 512 |
| 74 | #define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) |
| 75 | #define COMPILE_MAX_SEQUENCE 64 |
| 100 | 76 | |
| 101 | | #define CHECK_FPU_AVAILABLE() \ |
| 102 | | if((ppc.msr & 0x2000) == 0){ \ |
| 103 | | } |
| 77 | /* exit codes */ |
| 78 | #define EXECUTE_OUT_OF_CYCLES 0 |
| 79 | #define EXECUTE_MISSING_CODE 1 |
| 80 | #define EXECUTE_UNMAPPED_CODE 2 |
| 81 | #define EXECUTE_RESET_CACHE 3 |
| 104 | 82 | |
| 105 | | #if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_PPC604||HAS_MPC8240) |
| 106 | | static UINT32 ppc_field_xlat[256]; |
| 107 | | #endif |
| 108 | 83 | |
| 109 | 84 | |
| 85 | /*************************************************************************** |
| 86 | MACROS |
| 87 | ***************************************************************************/ |
| 110 | 88 | |
| 111 | | #define FPSCR_FX 0x80000000 |
| 112 | | #define FPSCR_FEX 0x40000000 |
| 113 | | #define FPSCR_VX 0x20000000 |
| 114 | | #define FPSCR_OX 0x10000000 |
| 115 | | #define FPSCR_UX 0x08000000 |
| 116 | | #define FPSCR_ZX 0x04000000 |
| 117 | | #define FPSCR_XX 0x02000000 |
| 89 | #define R32(reg) ppc->impstate->regmap[reg].type, ppc->impstate->regmap[reg].value |
| 90 | #define R32Z(reg) (((reg) == 0) ? DRCUML_PTYPE_IMMEDIATE : ppc->impstate->regmap[reg].type), (((reg) == 0) ? 0 : ppc->impstate->regmap[reg].value) |
| 91 | #define F64(reg) ppc->impstate->fdregmap[reg].type, ppc->impstate->fdregmap[reg].value |
| 92 | #define CR32 MEM(&ppc->cr) |
| 93 | #define FPSCR32 MEM(&ppc->fpscr) |
| 94 | #define MSR32 MEM(&ppc->msr) |
| 95 | #define SR32(reg) MEM(&ppc->sr[reg]) |
| 96 | #define SPR32(reg) MEM(&ppc->spr[reg]) |
| 118 | 97 | |
| 98 | #define CRMASK(reg) (0xf0000000 >> ((reg) * 4)) |
| 119 | 99 | |
| 100 | #define FLAGS_RC(op) ((op & M_RC) ? (DRCUML_FLAG_S | DRCUML_FLAG_Z) : 0) |
| 101 | #define FLAGS_OE(op) ((op & M_OE) ? DRCUML_FLAG_V : 0) |
| 102 | #define FLAGS_RCOE(op) (FLAGS_RC(op) | FLAGS_OE(op)) |
| 103 | #define FLAGS_RCOECA(op) (FLAGS_RCOE(op) | DRCUML_FLAG_C) |
| 120 | 104 | |
| 121 | | #define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) |
| 122 | | #define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) |
| 123 | | #define _BIT(n) (1 << (n)) |
| 124 | | #define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) |
| 125 | | #define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) |
| 126 | | #define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) |
| 127 | | #define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) |
| 128 | | #define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) |
| 105 | /* DSISR values for various addressing types */ |
| 106 | #define DSISR_IMM(op) ((0) | /* bits 15-16: cleared */ \ |
| 107 | ((((op) >> (31- 5)) & 0x01) << (31-17)) | /* bit 17: opcode bit 5 */ \ |
| 108 | ((((op) >> (31- 4)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 1-4 */ \ |
| 109 | ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ |
| 110 | (0)) /* bits 27-31: undefined */ |
| 129 | 111 | |
| 130 | | #define XER_SO 0x80000000 |
| 131 | | #define XER_OV 0x40000000 |
| 132 | | #define XER_CA 0x20000000 |
| 112 | #define DSISR_IMMU(op) ((0) | /* bits 15-16: cleared */ \ |
| 113 | ((((op) >> (31- 5)) & 0x01) << (31-17)) | /* bit 17: opcode bit 5 */ \ |
| 114 | ((((op) >> (31- 4)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 1-4 */ \ |
| 115 | ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ |
| 116 | ((((op) >> (31-15)) & 0x1f) << (31-31))) /* bits 27-31: opcode bits 11-15 */ |
| 133 | 117 | |
| 134 | | #define MSR_AP 0x00800000 /* Access privilege state (PPC602) */ |
| 135 | | #define MSR_SA 0x00400000 /* Supervisor access mode (PPC602) */ |
| 136 | | #define MSR_POW 0x00040000 /* Power Management Enable */ |
| 137 | | #define MSR_WE 0x00040000 |
| 138 | | #define MSR_CE 0x00020000 |
| 139 | | #define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ |
| 140 | | #define MSR_EE 0x00008000 /* External Interrupt Enable */ |
| 141 | | #define MSR_PR 0x00004000 /* Problem State */ |
| 142 | | #define MSR_FP 0x00002000 /* Floating Point Available */ |
| 143 | | #define MSR_ME 0x00001000 /* Machine Check Enable */ |
| 144 | | #define MSR_FE0 0x00000800 |
| 145 | | #define MSR_SE 0x00000400 /* Single Step Trace Enable */ |
| 146 | | #define MSR_BE 0x00000200 /* Branch Trace Enable */ |
| 147 | | #define MSR_DE 0x00000200 |
| 148 | | #define MSR_FE1 0x00000100 |
| 149 | | #define MSR_IP 0x00000040 /* Interrupt Prefix */ |
| 150 | | #define MSR_IR 0x00000020 /* Instruction Relocate */ |
| 151 | | #define MSR_DR 0x00000010 /* Data Relocate */ |
| 152 | | #define MSR_PE 0x00000008 |
| 153 | | #define MSR_PX 0x00000004 |
| 154 | | #define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ |
| 155 | | #define MSR_LE 0x00000001 |
| 118 | #define DSISR_IDX(op) (((((op) >> (31-30)) & 0x03) << (31-16)) | /* bits 15-16: opcode bits 29-30 */ \ |
| 119 | ((((op) >> (31-25)) & 0x01) << (31-17)) | /* bit 17: opcode bit 25 */ \ |
| 120 | ((((op) >> (31-24)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 21-24 */ \ |
| 121 | ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ |
| 122 | (0)) /* bits 27-31: undefined */ |
| 156 | 123 | |
| 157 | | #define TSR_ENW 0x80000000 |
| 158 | | #define TSR_WIS 0x40000000 |
| 124 | #define DSISR_IDXU(op) (((((op) >> (31-30)) & 0x03) << (31-16)) | /* bits 15-16: opcode bits 29-30 */ \ |
| 125 | ((((op) >> (31-25)) & 0x01) << (31-17)) | /* bit 17: opcode bit 25 */ \ |
| 126 | ((((op) >> (31-24)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 21-24 */ \ |
| 127 | ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ |
| 128 | ((((op) >> (31-15)) & 0x1f) << (31-31))) /* bits 27-31: opcode bits 11-15 */ |
| 159 | 129 | |
| 160 | | #define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) |
| 161 | | #define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) |
| 162 | 130 | |
| 163 | | typedef struct { |
| 164 | | UINT32 cr; |
| 165 | | UINT32 da; |
| 166 | | UINT32 sa; |
| 167 | | UINT32 ct; |
| 168 | | UINT32 cc; |
| 169 | | } DMA_REGS; |
| 170 | 131 | |
| 171 | | typedef struct { |
| 172 | | UINT8 spls; |
| 173 | | UINT8 sphs; |
| 174 | | UINT16 brd; |
| 175 | | UINT8 spctl; |
| 176 | | UINT8 sprc; |
| 177 | | UINT8 sptc; |
| 178 | | UINT8 sprb; |
| 179 | | UINT8 sptb; |
| 180 | | emu_timer *rx_timer; |
| 181 | | emu_timer *tx_timer; |
| 182 | | } SPU_REGS; |
| 132 | /*************************************************************************** |
| 133 | STRUCTURES & TYPEDEFS |
| 134 | ***************************************************************************/ |
| 183 | 135 | |
| 184 | | typedef union { |
| 185 | | UINT64 id; |
| 186 | | double fd; |
| 187 | | } FPR; |
| 136 | /* fast RAM info */ |
| 137 | typedef struct _fast_ram_info fast_ram_info; |
| 138 | struct _fast_ram_info |
| 139 | { |
| 140 | offs_t start; /* start of the RAM block */ |
| 141 | offs_t end; /* end of the RAM block */ |
| 142 | UINT8 readonly; /* TRUE if read-only */ |
| 143 | void * base; /* base in memory where the RAM lives */ |
| 144 | }; |
| 188 | 145 | |
| 189 | | typedef union { |
| 190 | | UINT32 i; |
| 191 | | float f; |
| 192 | | } FPR32; |
| 193 | 146 | |
| 194 | | typedef struct { |
| 195 | | UINT32 u; |
| 196 | | UINT32 l; |
| 197 | | } BATENT; |
| 147 | /* hotspot info */ |
| 148 | typedef struct _hotspot_info hotspot_info; |
| 149 | struct _hotspot_info |
| 150 | { |
| 151 | offs_t pc; /* PC to consider */ |
| 152 | UINT32 opcode; /* required opcode at that PC */ |
| 153 | UINT32 cycles; /* number of cycles to eat when hit */ |
| 154 | }; |
| 198 | 155 | |
| 199 | 156 | |
| 200 | | typedef struct { |
| 201 | | UINT32 r[32]; |
| 202 | | UINT32 pc; |
| 203 | | UINT32 npc; |
| 157 | /* internal compiler state */ |
| 158 | typedef struct _compiler_state compiler_state; |
| 159 | struct _compiler_state |
| 160 | { |
| 161 | UINT32 cycles; /* accumulated cycles */ |
| 162 | UINT8 checkints; /* need to check interrupts before next instruction */ |
| 163 | UINT8 checksoftints; /* need to check software interrupts before next instruction */ |
| 164 | drcuml_codelabel labelnum; /* index for local labels */ |
| 165 | }; |
| 204 | 166 | |
| 205 | | UINT32 lr; |
| 206 | | UINT32 ctr; |
| 207 | | UINT32 xer; |
| 208 | | UINT32 msr; |
| 209 | | UINT8 cr[8]; |
| 210 | | UINT32 pvr; |
| 211 | | UINT32 srr0; |
| 212 | | UINT32 srr1; |
| 213 | | UINT32 srr2; |
| 214 | | UINT32 srr3; |
| 215 | | UINT32 hid0; |
| 216 | | UINT32 hid1; |
| 217 | | UINT32 hid2; |
| 218 | | UINT32 sdr1; |
| 219 | | UINT32 sprg[4]; |
| 220 | 167 | |
| 221 | | UINT32 dsisr; |
| 222 | | UINT32 dar; |
| 223 | | UINT32 ear; |
| 224 | | UINT32 dmiss; |
| 225 | | UINT32 dcmp; |
| 226 | | UINT32 hash1; |
| 227 | | UINT32 hash2; |
| 228 | | UINT32 imiss; |
| 229 | | UINT32 icmp; |
| 230 | | UINT32 rpa; |
| 168 | /* PowerPC implementation state */ |
| 169 | struct _ppcimp_state |
| 170 | { |
| 171 | /* core state */ |
| 172 | drccache * cache; /* pointer to the DRC code cache */ |
| 173 | drcuml_state * drcuml; /* DRC UML generator state */ |
| 174 | drcfe_state * drcfe; /* pointer to the DRC front-end state */ |
| 175 | UINT32 drcoptions; /* configurable DRC options */ |
| 231 | 176 | |
| 232 | | BATENT ibat[4]; |
| 233 | | BATENT dbat[4]; |
| 177 | /* parameters for subroutines */ |
| 178 | UINT64 numcycles; /* return value from gettotalcycles */ |
| 179 | UINT32 mode; /* current global mode */ |
| 180 | UINT32 arg0; /* print_debug argument 1 */ |
| 181 | UINT32 arg1; /* print_debug argument 2 */ |
| 182 | UINT32 updateaddr; /* update address storage */ |
| 183 | UINT32 swcount; /* counter for sw instructions */ |
| 184 | UINT32 swreg; /* reg index for sw instructions */ |
| 185 | UINT32 tempaddr; /* temporary address storage */ |
| 186 | UINT64 tempdata; /* temporary data storage */ |
| 187 | double fp0; /* floating point 0 */ |
| 234 | 188 | |
| 235 | | UINT32 evpr; |
| 236 | | UINT32 exier; |
| 237 | | UINT32 exisr; |
| 238 | | UINT32 bear; |
| 239 | | UINT32 besr; |
| 240 | | UINT32 iocr; |
| 241 | | UINT32 br[8]; |
| 242 | | UINT32 iabr; |
| 243 | | UINT32 esr; |
| 244 | | UINT32 iccr; |
| 245 | | UINT32 dccr; |
| 246 | | UINT32 pit; |
| 247 | | UINT32 tsr; |
| 248 | | UINT32 tcr; |
| 249 | | UINT32 dbsr; |
| 250 | | UINT32 sgr; |
| 251 | | UINT32 pid; |
| 252 | | UINT32 pbl1, pbl2, pbu1, pbu2; |
| 253 | | UINT32 fit_bit; |
| 254 | | UINT32 fit_int_enable; |
| 255 | | UINT32 wdt_bit; |
| 256 | | UINT32 wdt_int_enable; |
| 257 | | UINT32 dac1, dac2; |
| 258 | | UINT32 iac1, iac2; |
| 189 | /* tables */ |
| 190 | UINT8 fpmode[4]; /* FPU mode table */ |
| 191 | UINT32 sz_cr_table[32]; /* SZ CR table */ |
| 192 | UINT32 cmp_cr_table[32]; /* CMP CR table */ |
| 193 | UINT32 cmpl_cr_table[32]; /* CMPL CR table */ |
| 194 | UINT32 fcmp_cr_table[32]; /* FCMP CR table */ |
| 259 | 195 | |
| 260 | | SPU_REGS spu; |
| 261 | | DMA_REGS dma[4]; |
| 262 | | UINT32 dmasr; |
| 196 | /* internal stuff */ |
| 197 | UINT8 cache_dirty; /* true if we need to flush the cache */ |
| 263 | 198 | |
| 264 | | int reserved; |
| 265 | | UINT32 reserved_address; |
| 199 | /* register mappings */ |
| 200 | drcuml_parameter regmap[32]; /* parameter to register mappings for all 32 integer registers */ |
| 201 | drcuml_parameter fsregmap[32]; /* parameter to register mappings for all 32 floating point registers */ |
| 202 | drcuml_parameter fdregmap[32]; /* parameter to register mappings for all 32 floating point registers */ |
| 266 | 203 | |
| 267 | | int exception_pending; |
| 204 | /* subroutines */ |
| 205 | drcuml_codehandle * entry; /* entry point */ |
| 206 | drcuml_codehandle * nocode; /* nocode exception handler */ |
| 207 | drcuml_codehandle * out_of_cycles; /* out of cycles exception handler */ |
| 208 | drcuml_codehandle * tlb_mismatch; /* tlb mismatch handler */ |
| 209 | drcuml_codehandle * swap_tgpr; /* swap TGPR handler */ |
| 210 | drcuml_codehandle * read8[4]; /* read byte */ |
| 211 | drcuml_codehandle * write8[4]; /* write byte */ |
| 212 | drcuml_codehandle * read16[4]; /* read half */ |
| 213 | drcuml_codehandle * read16mask[4]; /* read half */ |
| 214 | drcuml_codehandle * write16[4]; /* write half */ |
| 215 | drcuml_codehandle * write16mask[4]; /* write half */ |
| 216 | drcuml_codehandle * read32[4]; /* read word */ |
| 217 | drcuml_codehandle * read32align[4]; /* read word aligned */ |
| 218 | drcuml_codehandle * read32mask[4]; /* read word */ |
| 219 | drcuml_codehandle * write32[4]; /* write word */ |
| 220 | drcuml_codehandle * write32align[4]; /* write word aligned */ |
| 221 | drcuml_codehandle * write32mask[4]; /* write word */ |
| 222 | drcuml_codehandle * read64[4]; /* read double */ |
| 223 | drcuml_codehandle * read64mask[4]; /* read double */ |
| 224 | drcuml_codehandle * write64[4]; /* write double */ |
| 225 | drcuml_codehandle * write64mask[4]; /* write double */ |
| 226 | drcuml_codehandle * exception[EXCEPTION_COUNT]; /* array of exception handlers */ |
| 227 | drcuml_codehandle * exception_norecover[EXCEPTION_COUNT]; /* array of exception handlers */ |
| 268 | 228 | |
| 269 | | UINT64 tb; /* 56-bit timebase register */ |
| 229 | /* fast RAM */ |
| 230 | UINT32 fastram_select; |
| 231 | fast_ram_info fastram[PPC_MAX_FASTRAM]; |
| 270 | 232 | |
| 271 | | int (*irq_callback)(int irqline); |
| 272 | | drc_core *drc; |
| 273 | | UINT32 drcoptions; |
| 233 | /* hotspots */ |
| 234 | UINT32 hotspot_select; |
| 235 | hotspot_info hotspot[PPC_MAX_HOTSPOTS]; |
| 236 | }; |
| 274 | 237 | |
| 275 | | x86code * invoke_exception_handler; |
| 276 | | x86code * generate_interrupt_exception; |
| 277 | | x86code * generate_syscall_exception; |
| 278 | | x86code * generate_decrementer_exception; |
| 279 | | x86code * generate_trap_exception; |
| 280 | | x86code * generate_dsi_exception; |
| 281 | | x86code * generate_isi_exception; |
| 282 | | x86code * generate_fit_exception; |
| 283 | 238 | |
| 284 | | // PowerPC 60x specific registers */ |
| 285 | | UINT32 dec, dec_frac; |
| 286 | | UINT32 fpscr; |
| 287 | 239 | |
| 288 | | FPR fpr[32]; |
| 289 | | UINT32 sr[16]; |
| 240 | /*************************************************************************** |
| 241 | FUNCTION PROTOTYPES |
| 242 | ***************************************************************************/ |
| 290 | 243 | |
| 291 | | int is603; |
| 292 | | int is602; |
| 244 | static void code_flush_cache(drcuml_state *drcuml); |
| 245 | static void code_compile_block(drcuml_state *drcuml, UINT8 mode, offs_t pc); |
| 293 | 246 | |
| 294 | | /* PowerPC 602 specific registers */ |
| 295 | | UINT32 lt; |
| 296 | | UINT32 sp; |
| 297 | | UINT32 ibr; |
| 298 | | UINT32 esasrr; |
| 299 | | UINT32 sebr; |
| 300 | | UINT32 ser; |
| 247 | static void cfunc_printf_exception(void *param); |
| 248 | static void cfunc_printf_probe(void *param); |
| 301 | 249 | |
| 302 | | /* PowerPC function pointers for memory accesses/exceptions */ |
| 303 | | UINT8 (*read8)(offs_t address); |
| 304 | | UINT16 (*read16)(offs_t address); |
| 305 | | UINT32 (*read32)(offs_t address); |
| 306 | | UINT64 (*read64)(offs_t address); |
| 307 | | void (*write8)(offs_t address, UINT8 data); |
| 308 | | void (*write16)(offs_t address, UINT16 data); |
| 309 | | void (*write32)(offs_t address, UINT32 data); |
| 310 | | void (*write64)(offs_t address, UINT64 data); |
| 311 | | UINT16 (*read16_unaligned)(offs_t address); |
| 312 | | UINT32 (*read32_unaligned)(offs_t address); |
| 313 | | UINT64 (*read64_unaligned)(offs_t address); |
| 314 | | void (*write16_unaligned)(offs_t address, UINT16 data); |
| 315 | | void (*write32_unaligned)(offs_t address, UINT32 data); |
| 316 | | void (*write64_unaligned)(offs_t address, UINT64 data); |
| 250 | static void static_generate_entry_point(drcuml_state *drcuml); |
| 251 | static void static_generate_nocode_handler(drcuml_state *drcuml); |
| 252 | static void static_generate_out_of_cycles(drcuml_state *drcuml); |
| 253 | static void static_generate_tlb_mismatch(drcuml_state *drcuml); |
| 254 | static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int recover, const char *name); |
| 255 | static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr, drcuml_codehandle *masked); |
| 256 | static void static_generate_swap_tgpr(drcuml_state *drcuml); |
| 317 | 257 | |
| 318 | | /* saved ESP when entering entry point */ |
| 319 | | UINT32 host_esp; |
| 258 | static void generate_update_mode(drcuml_block *block); |
| 259 | static void generate_update_cycles(drcuml_block *block, compiler_state *compiler, drcuml_ptype ptype, UINT64 pvalue, int allow_exception); |
| 260 | static void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); |
| 261 | static void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 262 | static int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 263 | static int generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 264 | static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 265 | static int generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 266 | static int generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); |
| 320 | 267 | |
| 321 | | UINT32 (* optable19[1024])(drc_core *, UINT32); |
| 322 | | UINT32 (* optable31[1024])(drc_core *, UINT32); |
| 323 | | UINT32 (* optable59[1024])(drc_core *, UINT32); |
| 324 | | UINT32 (* optable63[1024])(drc_core *, UINT32); |
| 325 | | UINT32 (* optable[64])(drc_core *, UINT32); |
| 326 | | } PPC_REGS; |
| 268 | static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op); |
| 269 | static const char *log_desc_flags_to_string(UINT32 flags); |
| 270 | static void log_register_list(drcuml_state *drcuml, const char *string, UINT64 gprmask, UINT64 fprmask); |
| 271 | static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent); |
| 327 | 272 | |
| 328 | 273 | |
| 329 | 274 | |
| 330 | | typedef struct { |
| 331 | | int code; |
| 332 | | int subcode; |
| 333 | | UINT32 (* handler)(drc_core *, UINT32); |
| 334 | | } PPC_OPCODE; |
| 275 | /*************************************************************************** |
| 276 | PRIVATE GLOBAL VARIABLES |
| 277 | ***************************************************************************/ |
| 335 | 278 | |
| 279 | static powerpc_state *ppc; |
| 336 | 280 | |
| 337 | | /* code logging info */ |
| 338 | | typedef struct _code_log_entry code_log_entry; |
| 339 | | struct _code_log_entry |
| 281 | |
| 282 | /* lookup table for FP modes */ |
| 283 | static const UINT8 fpmode_source[4] = |
| 340 | 284 | { |
| 341 | | UINT32 pc; |
| 342 | | UINT32 op; |
| 343 | | void * base; |
| 285 | DRCUML_FMOD_ROUND, |
| 286 | DRCUML_FMOD_TRUNC, |
| 287 | DRCUML_FMOD_CEIL, |
| 288 | DRCUML_FMOD_FLOOR |
| 344 | 289 | }; |
| 345 | 290 | |
| 291 | /* flag lookup table for SZ */ |
| 292 | static const UINT32 sz_cr_table_source[32] = |
| 293 | { |
| 294 | /* ..... */ 0x40000000, |
| 295 | /* ....C */ 0x42000000, |
| 296 | /* ...V. */ 0x4c000000, |
| 297 | /* ...VC */ 0x4e000000, |
| 298 | /* ..Z.. */ 0x20000000, |
| 299 | /* ..Z.C */ 0x22000000, |
| 300 | /* ..ZV. */ 0x2c000000, |
| 301 | /* ..ZVC */ 0x2e000000, |
| 302 | /* .S... */ 0x80000000, |
| 303 | /* .S..C */ 0x82000000, |
| 304 | /* .S.V. */ 0x8c000000, |
| 305 | /* .S.VC */ 0x8e000000, |
| 306 | /* .SZ.. */ 0x20000000, |
| 307 | /* .SZ.C */ 0x22000000, |
| 308 | /* .SZV. */ 0x2c000000, |
| 309 | /* .SZVC */ 0x2e000000, |
| 310 | /* U.... */ 0x40000000, |
| 311 | /* U...C */ 0x42000000, |
| 312 | /* U..V. */ 0x4c000000, |
| 313 | /* U..VC */ 0x4e000000, |
| 314 | /* U.Z.. */ 0x20000000, |
| 315 | /* U.Z.C */ 0x22000000, |
| 316 | /* U.ZV. */ 0x2c000000, |
| 317 | /* U.ZVC */ 0x2e000000, |
| 318 | /* US... */ 0x80000000, |
| 319 | /* US..C */ 0x82000000, |
| 320 | /* US.V. */ 0x8c000000, |
| 321 | /* US.VC */ 0x8e000000, |
| 322 | /* USZ.. */ 0x20000000, |
| 323 | /* USZ.C */ 0x22000000, |
| 324 | /* USZV. */ 0x2c000000, |
| 325 | /* USZVC */ 0x2e000000 |
| 326 | }; |
| 346 | 327 | |
| 328 | /* flag lookup table for CMP */ |
| 329 | static const UINT32 cmp_cr_table_source[32] = |
| 330 | { |
| 331 | /* ..... */ 0x44444444, |
| 332 | /* ....C */ 0x44444444, |
| 333 | /* ...V. */ 0x88888888, |
| 334 | /* ...VC */ 0x88888888, |
| 335 | /* ..Z.. */ 0x22222222, |
| 336 | /* ..Z.C */ 0x22222222, |
| 337 | /* ..ZV. */ 0x22222222, |
| 338 | /* ..ZVC */ 0x22222222, |
| 339 | /* .S... */ 0x88888888, |
| 340 | /* .S..C */ 0x88888888, |
| 341 | /* .S.V. */ 0x44444444, |
| 342 | /* .S.VC */ 0x44444444, |
| 343 | /* .SZ.. */ 0x22222222, |
| 344 | /* .SZ.C */ 0x22222222, |
| 345 | /* .SZV. */ 0x22222222, |
| 346 | /* .SZVC */ 0x22222222, |
| 347 | /* U.... */ 0x44444444, |
| 348 | /* U...C */ 0x44444444, |
| 349 | /* U..V. */ 0x88888888, |
| 350 | /* U..VC */ 0x88888888, |
| 351 | /* U.Z.. */ 0x22222222, |
| 352 | /* U.Z.C */ 0x22222222, |
| 353 | /* U.ZV. */ 0x22222222, |
| 354 | /* U.ZVC */ 0x22222222, |
| 355 | /* US... */ 0x88888888, |
| 356 | /* US..C */ 0x88888888, |
| 357 | /* US.V. */ 0x44444444, |
| 358 | /* US.VC */ 0x44444444, |
| 359 | /* USZ.. */ 0x22222222, |
| 360 | /* USZ.C */ 0x22222222, |
| 361 | /* USZV. */ 0x22222222, |
| 362 | /* USZVC */ 0x22222222 |
| 363 | }; |
| 347 | 364 | |
| 348 | | static int ppc_icount; |
| 349 | | static int ppc_tb_base_icount; |
| 350 | | static int ppc_dec_base_icount; |
| 351 | | static int ppc_dec_trigger_cycle; |
| 352 | | static int bus_freq_multiplier = 1; |
| 353 | | static int ppc_fit_trigger_cycle; |
| 354 | | static PPC_REGS ppc; |
| 355 | | static UINT32 ppc_rotate_mask[32][32]; |
| 365 | /* flag lookup table for CMPL */ |
| 366 | static const UINT32 cmpl_cr_table_source[32] = |
| 367 | { |
| 368 | /* ..... */ 0x44444444, |
| 369 | /* ....C */ 0x88888888, |
| 370 | /* ...V. */ 0x44444444, |
| 371 | /* ...VC */ 0x88888888, |
| 372 | /* ..Z.. */ 0x22222222, |
| 373 | /* ..Z.C */ 0x22222222, |
| 374 | /* ..ZV. */ 0x22222222, |
| 375 | /* ..ZVC */ 0x22222222, |
| 376 | /* .S... */ 0x44444444, |
| 377 | /* .S..C */ 0x88888888, |
| 378 | /* .S.V. */ 0x44444444, |
| 379 | /* .S.VC */ 0x88888888, |
| 380 | /* .SZ.. */ 0x22222222, |
| 381 | /* .SZ.C */ 0x22222222, |
| 382 | /* .SZV. */ 0x22222222, |
| 383 | /* .SZVC */ 0x22222222, |
| 384 | /* U.... */ 0x44444444, |
| 385 | /* U...C */ 0x88888888, |
| 386 | /* U..V. */ 0x44444444, |
| 387 | /* U..VC */ 0x88888888, |
| 388 | /* U.Z.. */ 0x22222222, |
| 389 | /* U.Z.C */ 0x22222222, |
| 390 | /* U.ZV. */ 0x22222222, |
| 391 | /* U.ZVC */ 0x22222222, |
| 392 | /* US... */ 0x44444444, |
| 393 | /* US..C */ 0x88888888, |
| 394 | /* US.V. */ 0x44444444, |
| 395 | /* US.VC */ 0x88888888, |
| 396 | /* USZ.. */ 0x22222222, |
| 397 | /* USZ.C */ 0x22222222, |
| 398 | /* USZV. */ 0x22222222, |
| 399 | /* USZVC */ 0x22222222 |
| 400 | }; |
| 356 | 401 | |
| 357 | | #define ROPCODE(pc) cpu_readop32(pc) |
| 358 | | #define ROPCODE64(pc) cpu_readop64(DWORD_XOR_BE(pc)) |
| 359 | | |
| 360 | | INLINE void SET_CR0(INT32 rd) |
| 402 | /* flag lookup table for FCMP */ |
| 403 | static const UINT32 fcmp_cr_table_source[32] = |
| 361 | 404 | { |
| 362 | | if( rd < 0 ) { |
| 363 | | CR(0) = 0x8; |
| 364 | | } else if( rd > 0 ) { |
| 365 | | CR(0) = 0x4; |
| 366 | | } else { |
| 367 | | CR(0) = 0x2; |
| 368 | | } |
| 405 | /* ..... */ 0x44444444, |
| 406 | /* ....C */ 0x88888888, |
| 407 | /* ...V. */ 0x44444444, |
| 408 | /* ...VC */ 0x88888888, |
| 409 | /* ..Z.. */ 0x22222222, |
| 410 | /* ..Z.C */ 0xaaaaaaaa, |
| 411 | /* ..ZV. */ 0x22222222, |
| 412 | /* ..ZVC */ 0xaaaaaaaa, |
| 413 | /* .S... */ 0x44444444, |
| 414 | /* .S..C */ 0x88888888, |
| 415 | /* .S.V. */ 0x44444444, |
| 416 | /* .S.VC */ 0x88888888, |
| 417 | /* .SZ.. */ 0x22222222, |
| 418 | /* .SZ.C */ 0xaaaaaaaa, |
| 419 | /* .SZV. */ 0x22222222, |
| 420 | /* .SZVC */ 0xaaaaaaaa, |
| 421 | /* U.... */ 0x55555555, |
| 422 | /* U...C */ 0x99999999, |
| 423 | /* U..V. */ 0x55555555, |
| 424 | /* U..VC */ 0x99999999, |
| 425 | /* U.Z.. */ 0x33333333, |
| 426 | /* U.Z.C */ 0xbbbbbbbb, |
| 427 | /* U.ZV. */ 0x33333333, |
| 428 | /* U.ZVC */ 0xbbbbbbbb, |
| 429 | /* US... */ 0x55555555, |
| 430 | /* US..C */ 0x99999999, |
| 431 | /* US.V. */ 0x55555555, |
| 432 | /* US.VC */ 0x99999999, |
| 433 | /* USZ.. */ 0x33333333, |
| 434 | /* USZ.C */ 0xbbbbbbbb, |
| 435 | /* USZV. */ 0x33333333, |
| 436 | /* USZVC */ 0xbbbbbbbb |
| 437 | }; |
| 369 | 438 | |
| 370 | | if( XER & XER_SO ) |
| 371 | | CR(0) |= 0x1; |
| 372 | | } |
| 373 | 439 | |
| 374 | | INLINE void SET_CR1(void) |
| 440 | |
| 441 | /*************************************************************************** |
| 442 | INLINE FUNCTIONS |
| 443 | ***************************************************************************/ |
| 444 | |
| 445 | /*------------------------------------------------- |
| 446 | alloc_handle - allocate a handle if not |
| 447 | already allocated |
| 448 | -------------------------------------------------*/ |
| 449 | |
| 450 | INLINE void alloc_handle(drcuml_state *drcuml, drcuml_codehandle **handleptr, const char *name) |
| 375 | 451 | { |
| 376 | | CR(1) = (ppc.fpscr >> 28) & 0xf; |
| 452 | if (*handleptr == NULL) |
| 453 | *handleptr = drcuml_handle_alloc(drcuml, name); |
| 377 | 454 | } |
| 378 | 455 | |
| 379 | | INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) |
| 456 | |
| 457 | /*------------------------------------------------- |
| 458 | load_fast_iregs - load any fast integer |
| 459 | registers |
| 460 | -------------------------------------------------*/ |
| 461 | |
| 462 | INLINE void load_fast_iregs(drcuml_block *block) |
| 380 | 463 | { |
| 381 | | if( ADD_OV(rd, ra, rb) ) |
| 382 | | XER |= XER_SO | XER_OV; |
| 383 | | else |
| 384 | | XER &= ~XER_OV; |
| 464 | int regnum; |
| 465 | |
| 466 | for (regnum = 0; regnum < ARRAY_LENGTH(ppc->impstate->regmap); regnum++) |
| 467 | if (ppc->impstate->regmap[regnum].type == DRCUML_PTYPE_INT_REGISTER) |
| 468 | UML_MOV(block, IREG(ppc->impstate->regmap[regnum].value - DRCUML_REG_I0), MEM(&ppc->r[regnum])); |
| 385 | 469 | } |
| 386 | 470 | |
| 387 | | INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) |
| 471 | |
| 472 | /*------------------------------------------------- |
| 473 | save_fast_iregs - save any fast integer |
| 474 | registers |
| 475 | -------------------------------------------------*/ |
| 476 | |
| 477 | INLINE void save_fast_iregs(drcuml_block *block) |
| 388 | 478 | { |
| 389 | | if( SUB_OV(rd, ra, rb) ) |
| 390 | | XER |= XER_SO | XER_OV; |
| 391 | | else |
| 392 | | XER &= ~XER_OV; |
| 479 | int regnum; |
| 480 | |
| 481 | for (regnum = 0; regnum < ARRAY_LENGTH(ppc->impstate->regmap); regnum++) |
| 482 | if (ppc->impstate->regmap[regnum].type == DRCUML_PTYPE_INT_REGISTER) |
| 483 | UML_MOV(block, MEM(&ppc->r[regnum]), IREG(ppc->impstate->regmap[regnum].value - DRCUML_REG_I0)); |
| 393 | 484 | } |
| 394 | 485 | |
| 395 | | INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) |
| 486 | |
| 487 | /*------------------------------------------------- |
| 488 | compute_rlw_mask - compute the 32-bit mask |
| 489 | for an rlw* instruction |
| 490 | -------------------------------------------------*/ |
| 491 | |
| 492 | INLINE UINT32 compute_rlw_mask(UINT8 mb, UINT8 me) |
| 396 | 493 | { |
| 397 | | if( ADD_CA(rd, ra, rb) ) |
| 398 | | XER |= XER_CA; |
| 494 | if (mb <= me) |
| 495 | return (0xffffffff >> mb) & (0xffffffff << (31 - me)); |
| 399 | 496 | else |
| 400 | | XER &= ~XER_CA; |
| 497 | return (0xffffffff >> mb) | (0xffffffff << (31 - me)); |
| 401 | 498 | } |
| 402 | 499 | |
| 403 | | INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) |
| 500 | |
| 501 | /*------------------------------------------------- |
| 502 | compute_crf_mask - compute the 32-bit mask |
| 503 | for a mtcrf/mfcrf instruction |
| 504 | -------------------------------------------------*/ |
| 505 | |
| 506 | INLINE UINT32 compute_crf_mask(UINT8 crm) |
| 404 | 507 | { |
| 405 | | if( SUB_CA(rd, ra, rb) ) |
| 406 | | XER |= XER_CA; |
| 407 | | else |
| 408 | | XER &= ~XER_CA; |
| 508 | UINT32 mask = 0; |
| 509 | if (crm & 0x80) mask |= 0xf0000000; |
| 510 | if (crm & 0x40) mask |= 0x0f000000; |
| 511 | if (crm & 0x20) mask |= 0x00f00000; |
| 512 | if (crm & 0x10) mask |= 0x000f0000; |
| 513 | if (crm & 0x08) mask |= 0x0000f000; |
| 514 | if (crm & 0x04) mask |= 0x00000f00; |
| 515 | if (crm & 0x02) mask |= 0x000000f0; |
| 516 | if (crm & 0x01) mask |= 0x0000000f; |
| 517 | return mask; |
| 409 | 518 | } |
| 410 | 519 | |
| 411 | | INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) |
| 520 | |
| 521 | /*------------------------------------------------- |
| 522 | compute_spr - compute the SPR index from the |
| 523 | SPR field of an opcode |
| 524 | -------------------------------------------------*/ |
| 525 | |
| 526 | INLINE UINT32 compute_spr(UINT32 spr) |
| 412 | 527 | { |
| 413 | | UINT32 ctr_ok; |
| 414 | | UINT32 condition_ok; |
| 415 | | UINT32 bo0 = (bo & 0x10) ? 1 : 0; |
| 416 | | UINT32 bo1 = (bo & 0x08) ? 1 : 0; |
| 417 | | UINT32 bo2 = (bo & 0x04) ? 1 : 0; |
| 418 | | UINT32 bo3 = (bo & 0x02) ? 1 : 0; |
| 528 | return ((spr >> 5) | (spr << 5)) & 0x3ff; |
| 529 | } |
| 419 | 530 | |
| 420 | | if( bo2 == 0 ) |
| 421 | | --CTR; |
| 422 | 531 | |
| 423 | | ctr_ok = bo2 | ((CTR != 0) ^ bo3); |
| 424 | | condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); |
| 425 | 532 | |
| 426 | | return ctr_ok && condition_ok; |
| 427 | | } |
| 533 | /*************************************************************************** |
| 534 | CORE CALLBACKS |
| 535 | ***************************************************************************/ |
| 428 | 536 | |
| 429 | | INLINE UINT64 ppc_read_timebase(void) |
| 537 | /*------------------------------------------------- |
| 538 | ppcdrc_init - initialize the processor |
| 539 | -------------------------------------------------*/ |
| 540 | |
| 541 | static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int)) |
| 430 | 542 | { |
| 431 | | int cycles = ppc_tb_base_icount - ppc_icount; |
| 543 | drcfe_config feconfig = |
| 544 | { |
| 545 | COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ |
| 546 | COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ |
| 547 | COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ |
| 548 | ppcfe_describe /* callback to describe a single instruction */ |
| 549 | }; |
| 550 | drcbe_info beinfo; |
| 551 | UINT32 flags = 0; |
| 552 | size_t extrasize; |
| 553 | drccache *cache; |
| 554 | void *extramem; |
| 555 | int regnum; |
| 432 | 556 | |
| 433 | | if (ppc.is603 || ppc.is602) |
| 557 | /* determine how much memory beyond the core size we need */ |
| 558 | extrasize = ppccom_init(NULL, flavor, cap, tb_divisor, clock, config, irqcallback, NULL); |
| 559 | |
| 560 | /* allocate enough space for the cache and the core */ |
| 561 | cache = drccache_alloc(CACHE_SIZE + sizeof(*ppc) + extrasize); |
| 562 | if (cache == NULL) |
| 563 | fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*ppc) + extrasize)); |
| 564 | |
| 565 | /* allocate the core from the near cache, and the extra memory from the full cache */ |
| 566 | ppc = drccache_memory_alloc_near(cache, sizeof(*ppc)); |
| 567 | memset(ppc, 0, sizeof(*ppc)); |
| 568 | extramem = drccache_memory_alloc(cache, extrasize); |
| 569 | memset(extramem, 0, extrasize); |
| 570 | |
| 571 | /* initialize the core */ |
| 572 | ppccom_init(ppc, flavor, cap, tb_divisor, clock, config, irqcallback, extramem); |
| 573 | |
| 574 | /* allocate the implementation-specific state from the full cache */ |
| 575 | ppc->impstate = drccache_memory_alloc_near(cache, sizeof(*ppc->impstate)); |
| 576 | memset(ppc->impstate, 0, sizeof(*ppc->impstate)); |
| 577 | ppc->impstate->cache = cache; |
| 578 | |
| 579 | /* initialize the UML generator */ |
| 580 | if (FORCE_C_BACKEND) |
| 581 | flags |= DRCUML_OPTION_USE_C; |
| 582 | if (LOG_UML) |
| 583 | flags |= DRCUML_OPTION_LOG_UML; |
| 584 | if (LOG_NATIVE) |
| 585 | flags |= DRCUML_OPTION_LOG_NATIVE; |
| 586 | ppc->impstate->drcuml = drcuml_alloc(cache, flags, 8, 32, 2); |
| 587 | if (ppc->impstate->drcuml == NULL) |
| 588 | fatalerror("Error initializing the UML"); |
| 589 | |
| 590 | /* initialize the front-end helper */ |
| 591 | if (SINGLE_INSTRUCTION_MODE) |
| 592 | feconfig.max_sequence = 1; |
| 593 | ppc->impstate->drcfe = drcfe_init(&feconfig, ppc); |
| 594 | |
| 595 | /* initialize the implementation state tables */ |
| 596 | memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); |
| 597 | memcpy(ppc->impstate->sz_cr_table, sz_cr_table_source, sizeof(sz_cr_table_source)); |
| 598 | memcpy(ppc->impstate->cmp_cr_table, cmp_cr_table_source, sizeof(cmp_cr_table_source)); |
| 599 | memcpy(ppc->impstate->cmpl_cr_table, cmpl_cr_table_source, sizeof(cmpl_cr_table_source)); |
| 600 | memcpy(ppc->impstate->fcmp_cr_table, fcmp_cr_table_source, sizeof(fcmp_cr_table_source)); |
| 601 | |
| 602 | /* compute the register parameters */ |
| 603 | for (regnum = 0; regnum < 32; regnum++) |
| 434 | 604 | { |
| 435 | | // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly |
| 436 | | return ppc.tb + (cycles / 4); |
| 605 | ppc->impstate->regmap[regnum].type = DRCUML_PTYPE_MEMORY; |
| 606 | ppc->impstate->regmap[regnum].value = (FPTR)&ppc->r[regnum]; |
| 607 | ppc->impstate->fsregmap[regnum].type = DRCUML_PTYPE_MEMORY; |
| 608 | ppc->impstate->fsregmap[regnum].value = (FPTR)((UINT32 *)&ppc->f[regnum] + BYTE_XOR_LE(0)); |
| 609 | ppc->impstate->fdregmap[regnum].type = DRCUML_PTYPE_MEMORY; |
| 610 | ppc->impstate->fdregmap[regnum].value = (FPTR)&ppc->f[regnum]; |
| 437 | 611 | } |
| 438 | | else |
| 612 | |
| 613 | /* if we have registers to spare, assign r0, r1, r2 to leftovers */ |
| 614 | if (!DISABLE_FAST_REGISTERS) |
| 439 | 615 | { |
| 440 | | // timebase is incremented once every core cycle on PPC403 |
| 441 | | return ppc.tb + cycles; |
| 616 | drcuml_get_backend_info(ppc->impstate->drcuml, &beinfo); |
| 617 | if (beinfo.direct_iregs > 5) |
| 618 | { |
| 619 | ppc->impstate->regmap[0].type = DRCUML_PTYPE_INT_REGISTER; |
| 620 | ppc->impstate->regmap[0].value = DRCUML_REG_I5; |
| 621 | } |
| 622 | if (beinfo.direct_iregs > 6) |
| 623 | { |
| 624 | ppc->impstate->regmap[1].type = DRCUML_PTYPE_INT_REGISTER; |
| 625 | ppc->impstate->regmap[1].value = DRCUML_REG_I6; |
| 626 | } |
| 627 | if (beinfo.direct_iregs > 7) |
| 628 | { |
| 629 | ppc->impstate->regmap[2].type = DRCUML_PTYPE_INT_REGISTER; |
| 630 | ppc->impstate->regmap[2].value = DRCUML_REG_I7; |
| 631 | } |
| 442 | 632 | } |
| 633 | |
| 634 | /* mark the cache dirty so it is updated on next execute */ |
| 635 | ppc->impstate->cache_dirty = TRUE; |
| 443 | 636 | } |
| 444 | 637 | |
| 445 | | INLINE void ppc_write_timebase_l(UINT32 tbl) |
| 638 | |
| 639 | /*------------------------------------------------- |
| 640 | ppcdrc_reset - reset the processor |
| 641 | -------------------------------------------------*/ |
| 642 | |
| 643 | static void ppcdrc_reset(void) |
| 446 | 644 | { |
| 447 | | ppc_tb_base_icount = ppc_icount; |
| 448 | | |
| 449 | | ppc.tb &= ~0xffffffff; |
| 450 | | ppc.tb |= tbl; |
| 645 | /* reset the common code and mark the cache dirty */ |
| 646 | ppccom_reset(ppc); |
| 647 | ppc->impstate->mode = 0; |
| 648 | ppc->impstate->cache_dirty = TRUE; |
| 451 | 649 | } |
| 452 | 650 | |
| 453 | | INLINE void ppc_write_timebase_h(UINT32 tbh) |
| 651 | |
| 652 | /*------------------------------------------------- |
| 653 | ppcdrc_execute - execute the CPU for the |
| 654 | specified number of cycles |
| 655 | -------------------------------------------------*/ |
| 656 | |
| 657 | static int ppcdrc_execute(int cycles) |
| 454 | 658 | { |
| 455 | | ppc_tb_base_icount = ppc_icount; |
| 659 | drcuml_state *drcuml = ppc->impstate->drcuml; |
| 660 | int execute_result; |
| 456 | 661 | |
| 457 | | ppc.tb &= 0xffffffff; |
| 458 | | ppc.tb |= (UINT64)(tbh) << 32; |
| 662 | /* reset the cache if dirty */ |
| 663 | if (ppc->impstate->cache_dirty) |
| 664 | code_flush_cache(drcuml); |
| 665 | ppc->impstate->cache_dirty = FALSE; |
| 666 | |
| 667 | /* execute */ |
| 668 | ppc->icount = cycles; |
| 669 | do |
| 670 | { |
| 671 | /* run as much as we can */ |
| 672 | execute_result = drcuml_execute(drcuml, ppc->impstate->entry); |
| 673 | |
| 674 | /* if we need to recompile, do it */ |
| 675 | if (execute_result == EXECUTE_MISSING_CODE) |
| 676 | code_compile_block(drcuml, ppc->impstate->mode, ppc->pc); |
| 677 | else if (execute_result == EXECUTE_UNMAPPED_CODE) |
| 678 | fatalerror("Attempted to execute unmapped code at PC=%08X\n", ppc->pc); |
| 679 | else if (execute_result == EXECUTE_RESET_CACHE) |
| 680 | code_flush_cache(drcuml); |
| 681 | |
| 682 | } while (execute_result != EXECUTE_OUT_OF_CYCLES); |
| 683 | |
| 684 | /* return the number of cycles executed */ |
| 685 | return cycles - ppc->icount; |
| 459 | 686 | } |
| 460 | 687 | |
| 461 | | INLINE UINT32 read_decrementer(void) |
| 688 | |
| 689 | /*------------------------------------------------- |
| 690 | ppcdrc_exit - cleanup from execution |
| 691 | -------------------------------------------------*/ |
| 692 | |
| 693 | static void ppcdrc_exit(void) |
| 462 | 694 | { |
| 463 | | int cycles = ppc_dec_base_icount - ppc_icount; |
| 464 | | |
| 465 | | // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly |
| 466 | | return DEC - (cycles / (bus_freq_multiplier * 2)); |
| 695 | /* clean up the DRC */ |
| 696 | drcfe_exit(ppc->impstate->drcfe); |
| 697 | drcuml_free(ppc->impstate->drcuml); |
| 698 | drccache_free(ppc->impstate->cache); |
| 467 | 699 | } |
| 468 | 700 | |
| 469 | | INLINE void write_decrementer(UINT32 value) |
| 701 | |
| 702 | /*------------------------------------------------- |
| 703 | ppcdrc_get_context - return a copy of the |
| 704 | current context |
| 705 | -------------------------------------------------*/ |
| 706 | |
| 707 | static void ppcdrc_get_context(void *dst) |
| 470 | 708 | { |
| 471 | | ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2); |
| 709 | if (dst != NULL) |
| 710 | *(powerpc_state **)dst = ppc; |
| 711 | } |
| 472 | 712 | |
| 473 | | DEC = value; |
| 474 | 713 | |
| 475 | | // check if decrementer exception occurs during execution |
| 476 | | if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) |
| 477 | | { |
| 478 | | ppc_dec_trigger_cycle = ppc_icount - DEC; |
| 479 | | } |
| 480 | | else |
| 481 | | { |
| 482 | | ppc_dec_trigger_cycle = 0x7fffffff; |
| 483 | | } |
| 714 | /*------------------------------------------------- |
| 715 | ppcdrc_set_context - copy the current context |
| 716 | into the global state |
| 717 | -------------------------------------------------*/ |
| 718 | |
| 719 | static void ppcdrc_set_context(void *src) |
| 720 | { |
| 721 | if (src != NULL) |
| 722 | ppc = *(powerpc_state **)src; |
| 484 | 723 | } |
| 485 | 724 | |
| 486 | | /*********************************************************************/ |
| 487 | 725 | |
| 488 | | INLINE void ppc_exception(int exception_type) |
| 726 | /*------------------------------------------------- |
| 727 | ppcdrc_translate - perform virtual-to-physical |
| 728 | address translation |
| 729 | -------------------------------------------------*/ |
| 730 | |
| 731 | static int ppcdrc_translate(int space, int intention, offs_t *address) |
| 489 | 732 | { |
| 490 | | void *exception_code = NULL; |
| 491 | | void (*invoke_exception_handler)(void *handler); |
| 733 | return ppccom_translate_address(ppc, space, intention, address); |
| 734 | } |
| 492 | 735 | |
| 493 | | switch(exception_type) |
| 494 | | { |
| 495 | | case EXCEPTION_DECREMENTER: |
| 496 | | exception_code = ppc.generate_decrementer_exception; |
| 497 | | break; |
| 498 | | case EXCEPTION_DSI: |
| 499 | | exception_code = ppc.generate_dsi_exception; |
| 500 | | break; |
| 501 | | case EXCEPTION_ISI: |
| 502 | | exception_code = ppc.generate_isi_exception; |
| 503 | | break; |
| 504 | | default: |
| 505 | | fatalerror("Unknown exception %d", exception_type); |
| 506 | | break; |
| 507 | | } |
| 508 | 736 | |
| 509 | | memcpy(&invoke_exception_handler, &ppc.invoke_exception_handler, sizeof(invoke_exception_handler)); |
| 510 | | invoke_exception_handler(exception_code); |
| 737 | /*------------------------------------------------- |
| 738 | ppcdrc_dasm - disassemble an instruction |
| 739 | -------------------------------------------------*/ |
| 740 | |
| 741 | #ifdef ENABLE_DEBUGGER |
| 742 | static offs_t ppcdrc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) |
| 743 | { |
| 744 | return ppccom_dasm(ppc, buffer, pc, oprom, opram); |
| 511 | 745 | } |
| 746 | #endif /* ENABLE_DEBUGGER */ |
| 512 | 747 | |
| 513 | | /*********************************************************************/ |
| 514 | 748 | |
| 515 | | INLINE void ppc_set_spr(int spr, UINT32 value) |
| 749 | /*------------------------------------------------- |
| 750 | ppcdrc_set_info - set information about a given |
| 751 | CPU instance |
| 752 | -------------------------------------------------*/ |
| 753 | |
| 754 | static void ppcdrc_set_info(UINT32 state, cpuinfo *info) |
| 516 | 755 | { |
| 517 | | switch (spr) |
| 756 | switch (state) |
| 518 | 757 | { |
| 519 | | case SPR_LR: LR = value; return; |
| 520 | | case SPR_CTR: CTR = value; return; |
| 521 | | case SPR_XER: XER = value; return; |
| 522 | | case SPR_SRR0: ppc.srr0 = value; return; |
| 523 | | case SPR_SRR1: ppc.srr1 = value; return; |
| 524 | | case SPR_SPRG0: ppc.sprg[0] = value; return; |
| 525 | | case SPR_SPRG1: ppc.sprg[1] = value; return; |
| 526 | | case SPR_SPRG2: ppc.sprg[2] = value; return; |
| 527 | | case SPR_SPRG3: ppc.sprg[3] = value; return; |
| 528 | | case SPR_PVR: return; |
| 529 | | } |
| 758 | /* --- the following bits of info are set as 64-bit signed integers --- */ |
| 759 | case CPUINFO_INT_PPC_DRC_OPTIONS: ppc->impstate->drcoptions = info->i; break; |
| 530 | 760 | |
| 531 | | #if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601 || HAS_PPC604) |
| 532 | | if(ppc.is603 || ppc.is602) { |
| 533 | | switch(spr) |
| 534 | | { |
| 535 | | case SPR603E_DEC: |
| 536 | | if((value & 0x80000000) && !(DEC & 0x80000000)) |
| 537 | | { |
| 538 | | /* trigger interrupt */ |
| 539 | | if( MSR & MSR_EE ) |
| 540 | | ppc_exception(EXCEPTION_DECREMENTER); |
| 541 | | } |
| 542 | | write_decrementer(value); |
| 543 | | return; |
| 761 | case CPUINFO_INT_PPC_FASTRAM_SELECT: if (info->i >= 0 && info->i < PPC_MAX_FASTRAM) ppc->impstate->fastram_select = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 762 | case CPUINFO_INT_PPC_FASTRAM_START: ppc->impstate->fastram[ppc->impstate->fastram_select].start = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 763 | case CPUINFO_INT_PPC_FASTRAM_END: ppc->impstate->fastram[ppc->impstate->fastram_select].end = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 764 | case CPUINFO_INT_PPC_FASTRAM_READONLY: ppc->impstate->fastram[ppc->impstate->fastram_select].readonly = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 544 | 765 | |
| 545 | | case SPR603E_TBL_W: |
| 546 | | case SPR603E_TBL_R: // special 603e case |
| 547 | | ppc_write_timebase_l(value); |
| 548 | | return; |
| 766 | case CPUINFO_INT_PPC_HOTSPOT_SELECT: if (info->i >= 0 && info->i < PPC_MAX_HOTSPOTS) ppc->impstate->hotspot_select = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 767 | case CPUINFO_INT_PPC_HOTSPOT_PC: ppc->impstate->hotspot[ppc->impstate->hotspot_select].pc = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 768 | case CPUINFO_INT_PPC_HOTSPOT_OPCODE: ppc->impstate->hotspot[ppc->impstate->hotspot_select].opcode = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 769 | case CPUINFO_INT_PPC_HOTSPOT_CYCLES: ppc->impstate->hotspot[ppc->impstate->hotspot_select].cycles = info->i; ppc->impstate->cache_dirty = TRUE; break; |
| 549 | 770 | |
| 550 | | case SPR603E_TBU_R: |
| 551 | | case SPR603E_TBU_W: // special 603e case |
| 552 | | ppc_write_timebase_h(value); |
| 553 | | return; |
| 771 | /* --- the following bits of info are set as pointers to data or functions --- */ |
| 772 | case CPUINFO_PTR_PPC_FASTRAM_BASE: ppc->impstate->fastram[ppc->impstate->fastram_select].base = info->p; break; |
| 554 | 773 | |
| 555 | | case SPR603E_HID0: |
| 556 | | ppc.hid0 = value; |
| 557 | | return; |
| 774 | /* --- everything else is handled generically --- */ |
| 775 | default: ppccom_set_info(ppc, state, info); break; |
| 776 | } |
| 777 | } |
| 558 | 778 | |
| 559 | | case SPR603E_HID1: |
| 560 | | ppc.hid1 = value; |
| 561 | | return; |
| 562 | 779 | |
| 563 | | case SPR603E_HID2: |
| 564 | | ppc.hid1 = value; |
| 565 | | return; |
| 780 | /*------------------------------------------------- |
| 781 | ppcdrc_get_info - return information about a given |
| 782 | CPU instance |
| 783 | -------------------------------------------------*/ |
| 566 | 784 | |
| 567 | | case SPR603E_DSISR: ppc.dsisr = value; return; |
| 568 | | case SPR603E_DAR: ppc.dar = value; return; |
| 569 | | case SPR603E_EAR: ppc.ear = value; return; |
| 570 | | case SPR603E_DMISS: ppc.dmiss = value; return; |
| 571 | | case SPR603E_DCMP: ppc.dcmp = value; return; |
| 572 | | case SPR603E_HASH1: ppc.hash1 = value; return; |
| 573 | | case SPR603E_HASH2: ppc.hash2 = value; return; |
| 574 | | case SPR603E_IMISS: ppc.imiss = value; return; |
| 575 | | case SPR603E_ICMP: ppc.icmp = value; return; |
| 576 | | case SPR603E_RPA: ppc.rpa = value; return; |
| 785 | static void ppcdrc_get_info(UINT32 state, cpuinfo *info) |
| 786 | { |
| 787 | switch (state) |
| 788 | { |
| 789 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 790 | case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break; |
| 791 | case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; |
| 577 | 792 | |
| 578 | | case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; |
| 579 | | case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; |
| 580 | | case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; |
| 581 | | case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; |
| 582 | | case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; |
| 583 | | case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; |
| 584 | | case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; |
| 585 | | case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; |
| 586 | | case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; |
| 587 | | case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; |
| 588 | | case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; |
| 589 | | case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; |
| 590 | | case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; |
| 591 | | case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; |
| 592 | | case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; |
| 593 | | case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; |
| 793 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 794 | case CPUINFO_PTR_SET_INFO: info->setinfo = ppcdrc_set_info; break; |
| 795 | case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppcdrc_get_context; break; |
| 796 | case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppcdrc_set_context; break; |
| 797 | case CPUINFO_PTR_INIT: /* provided per-CPU */ break; |
| 798 | case CPUINFO_PTR_RESET: info->reset = ppcdrc_reset; break; |
| 799 | case CPUINFO_PTR_EXIT: info->exit = ppcdrc_exit; break; |
| 800 | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc_execute; break; |
| 801 | #ifdef ENABLE_DEBUGGER |
| 802 | case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppcdrc_dasm; break; |
| 803 | #endif /* ENABLE_DEBUGGER */ |
| 804 | case CPUINFO_PTR_TRANSLATE: info->translate = ppcdrc_translate; break; |
| 805 | case CPUINFO_PTR_CONTEXT: info->p = ppc; break; |
| 594 | 806 | |
| 595 | | case SPR603E_SDR1: |
| 596 | | ppc.sdr1 = value; |
| 597 | | return; |
| 807 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 808 | case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; |
| 598 | 809 | |
| 599 | | case SPR603E_IABR: ppc.iabr = value; return; |
| 600 | | } |
| 810 | /* --- everything else is handled generically --- */ |
| 811 | default: ppccom_get_info(ppc, state, info); break; |
| 601 | 812 | } |
| 602 | | #endif |
| 813 | } |
| 603 | 814 | |
| 604 | | #if (HAS_PPC602) |
| 605 | | if (ppc.is602) { |
| 606 | | switch(spr) |
| 607 | | { |
| 608 | | case SPR602_LT: ppc.lt = value; return; |
| 609 | | case SPR602_IBR: ppc.ibr = value; return; |
| 610 | | case SPR602_SP: ppc.sp = value; return; |
| 611 | | case SPR602_SEBR: ppc.sebr = value; return; |
| 612 | | case SPR602_SER: ppc.ser = value; return; |
| 613 | | case SPR602_TCR: ppc.tcr = value; return; |
| 614 | | } |
| 615 | | } |
| 616 | | #endif |
| 617 | 815 | |
| 618 | | #if (HAS_PPC403) |
| 619 | | if (!ppc.is603 && !ppc.is602) { |
| 620 | | switch(spr) |
| 621 | | { |
| 622 | | case SPR403_TBHI: ppc_write_timebase_h(value); return; |
| 623 | | case SPR403_TBLO: ppc_write_timebase_l(value); return; |
| 624 | 816 | |
| 625 | | case SPR403_TSR: |
| 626 | | ppc.tsr &= ~value; // 1 clears, 0 does nothing |
| 627 | | return; |
| 817 | /*************************************************************************** |
| 818 | CACHE MANAGEMENT |
| 819 | ***************************************************************************/ |
| 628 | 820 | |
| 629 | | case SPR403_TCR: |
| 630 | | switch((value >> 24) & 0x3) |
| 631 | | { |
| 632 | | case 0: ppc.fit_bit = 1 << 8; break; |
| 633 | | case 1: ppc.fit_bit = 1 << 12; break; |
| 634 | | case 2: ppc.fit_bit = 1 << 16; break; |
| 635 | | case 3: ppc.fit_bit = 1 << 20; break; |
| 636 | | } |
| 637 | | switch((value >> 30) & 0x3) |
| 638 | | { |
| 639 | | case 0: ppc.wdt_bit = 1 << 16; break; |
| 640 | | case 1: ppc.wdt_bit = 1 << 20; break; |
| 641 | | case 2: ppc.wdt_bit = 1 << 24; break; |
| 642 | | case 3: ppc.wdt_bit = 1 << 28; break; |
| 643 | | } |
| 644 | | ppc.fit_int_enable = (value >> 23) & 0x1; |
| 645 | | ppc.wdt_int_enable = (value >> 27) & 0x1; |
| 646 | | ppc.tcr = value; |
| 821 | /*------------------------------------------------- |
| 822 | code_flush_cache - flush the cache and |
| 823 | regenerate static code |
| 824 | -------------------------------------------------*/ |
| 647 | 825 | |
| 648 | | if (!ppc.fit_int_enable) |
| 649 | | { |
| 650 | | ppc.exception_pending &= ~0x4; |
| 651 | | } |
| 652 | | return; |
| 826 | static void code_flush_cache(drcuml_state *drcuml) |
| 827 | { |
| 828 | int mode; |
| 653 | 829 | |
| 654 | | case SPR403_ESR: ppc.esr = value; return; |
| 655 | | case SPR403_ICCR: ppc.iccr = value; return; |
| 656 | | case SPR403_DCCR: ppc.dccr = value; return; |
| 657 | | case SPR403_EVPR: EVPR = value & 0xffff0000; return; |
| 658 | | case SPR403_PIT: ppc.pit = value; return; |
| 659 | | case SPR403_SGR: ppc.sgr = value; return; |
| 660 | | case SPR403_DBSR: ppc.dbsr = value; return; |
| 661 | | case SPR403_DCWR: return; |
| 662 | | case SPR403_PID: ppc.pid = value; return; |
| 663 | | case SPR403_PBL1: ppc.pbl1 = value; return; |
| 664 | | case SPR403_PBU1: ppc.pbu1 = value; return; |
| 665 | | case SPR403_PBL2: ppc.pbl2 = value; return; |
| 666 | | case SPR403_PBU2: ppc.pbu2 = value; return; |
| 667 | | case SPR403_SRR2: ppc.srr2 = value; return; |
| 668 | | case SPR403_SRR3: ppc.srr3 = value; return; |
| 669 | | case SPR403_DAC1: ppc.dac1 = value; return; |
| 670 | | case SPR403_DAC2: ppc.dac2 = value; return; |
| 671 | | case SPR403_IAC1: ppc.iac1 = value; return; |
| 672 | | case SPR403_IAC2: ppc.iac2 = value; return; |
| 673 | | } |
| 674 | | } |
| 675 | | #endif |
| 830 | /* empty the transient cache contents */ |
| 831 | drcuml_reset(drcuml); |
| 676 | 832 | |
| 677 | | fatalerror("ppc: set_spr: unknown spr %d (%03X) !", spr, spr); |
| 678 | | } |
| 833 | /* generate the entry point and out-of-cycles handlers */ |
| 834 | static_generate_entry_point(drcuml); |
| 835 | static_generate_nocode_handler(drcuml); |
| 836 | static_generate_out_of_cycles(drcuml); |
| 837 | static_generate_tlb_mismatch(drcuml); |
| 838 | if (ppc->cap & PPCCAP_603_MMU) |
| 839 | static_generate_swap_tgpr(drcuml); |
| 679 | 840 | |
| 680 | | INLINE UINT32 ppc_get_spr(int spr) |
| 681 | | { |
| 682 | | switch(spr) |
| 841 | /* append exception handlers for various types */ |
| 842 | static_generate_exception(drcuml, EXCEPTION_RESET, TRUE, "exception_reset"); |
| 843 | static_generate_exception(drcuml, EXCEPTION_MACHCHECK, TRUE, "exception_machine_check"); |
| 844 | static_generate_exception(drcuml, EXCEPTION_DSI, TRUE, "exception_dsi"); |
| 845 | static_generate_exception(drcuml, EXCEPTION_ISI, TRUE, "exception_isi"); |
| 846 | static_generate_exception(drcuml, EXCEPTION_EI, TRUE, "exception_ei"); |
| 847 | static_generate_exception(drcuml, EXCEPTION_EI, FALSE, "exception_ei_norecover"); |
| 848 | static_generate_exception(drcuml, EXCEPTION_ALIGN, TRUE, "exception_align"); |
| 849 | static_generate_exception(drcuml, EXCEPTION_PROGRAM, TRUE, "exception_program"); |
| 850 | static_generate_exception(drcuml, EXCEPTION_NOFPU, TRUE, "exception_fpu_unavailable"); |
| 851 | static_generate_exception(drcuml, EXCEPTION_DECREMENT, TRUE, "exception_decrementer"); |
| 852 | static_generate_exception(drcuml, EXCEPTION_SYSCALL, TRUE, "exception_syscall"); |
| 853 | static_generate_exception(drcuml, EXCEPTION_TRACE, TRUE, "exception_trace"); |
| 854 | static_generate_exception(drcuml, EXCEPTION_FPASSIST, TRUE, "exception_floating_point_assist"); |
| 855 | if (ppc->cap & PPCCAP_603_MMU) |
| 683 | 856 | { |
| 684 | | case SPR_LR: return LR; |
| 685 | | case SPR_CTR: return CTR; |
| 686 | | case SPR_XER: return XER; |
| 687 | | case SPR_SRR0: return ppc.srr0; |
| 688 | | case SPR_SRR1: return ppc.srr1; |
| 689 | | case SPR_SPRG0: return ppc.sprg[0]; |
| 690 | | case SPR_SPRG1: return ppc.sprg[1]; |
| 691 | | case SPR_SPRG2: return ppc.sprg[2]; |
| 692 | | case SPR_SPRG3: return ppc.sprg[3]; |
| 693 | | case SPR_PVR: return ppc.pvr; |
| 857 | static_generate_exception(drcuml, EXCEPTION_ITLBMISS, TRUE, "exception_itlb_miss"); |
| 858 | static_generate_exception(drcuml, EXCEPTION_DTLBMISSL, TRUE, "exception_dtlb_miss_load"); |
| 859 | static_generate_exception(drcuml, EXCEPTION_DTLBMISSS, TRUE, "exception_dtlb_miss_store"); |
| 694 | 860 | } |
| 695 | 861 | |
| 696 | | #if (HAS_PPC403) |
| 697 | | if (!ppc.is603 && !ppc.is602) |
| 862 | /* add subroutines for memory accesses */ |
| 863 | for (mode = 0; mode < 4; mode++) |
| 698 | 864 | { |
| 699 | | switch (spr) |
| 700 | | { |
| 701 | | case SPR403_TBLU: |
| 702 | | case SPR403_TBLO: return (UINT32)(ppc_read_timebase()); |
| 703 | | case SPR403_TBHU: |
| 704 | | case SPR403_TBHI: return (UINT32)(ppc_read_timebase() >> 32); |
| 705 | | |
| 706 | | case SPR403_EVPR: return EVPR; |
| 707 | | case SPR403_ESR: return ppc.esr; |
| 708 | | case SPR403_TCR: return ppc.tcr; |
| 709 | | case SPR403_ICCR: return ppc.iccr; |
| 710 | | case SPR403_DCCR: return ppc.dccr; |
| 711 | | case SPR403_PIT: return ppc.pit; |
| 712 | | case SPR403_DBSR: return ppc.dbsr; |
| 713 | | case SPR403_SGR: return ppc.sgr; |
| 714 | | case SPR403_TSR: return ppc.tsr; |
| 715 | | case SPR403_PBL1: return ppc.pbl1; |
| 716 | | case SPR403_PBU1: return ppc.pbu1; |
| 717 | | case SPR403_PBL2: return ppc.pbl2; |
| 718 | | case SPR403_PBU2: return ppc.pbu2; |
| 719 | | case SPR403_SRR2: return ppc.srr2; |
| 720 | | case SPR403_SRR3: return ppc.srr3; |
| 721 | | case SPR403_DAC1: return ppc.dac1; |
| 722 | | case SPR403_DAC2: return ppc.dac2; |
| 723 | | case SPR403_IAC1: return ppc.iac1; |
| 724 | | case SPR403_IAC2: return ppc.iac2; |
| 725 | | } |
| 865 | static_generate_memory_accessor(drcuml, mode, 1, FALSE, FALSE, "read8", &ppc->impstate->read8[mode], NULL); |
| 866 | static_generate_memory_accessor(drcuml, mode, 1, TRUE, FALSE, "write8", &ppc->impstate->write8[mode], NULL); |
| 867 | static_generate_memory_accessor(drcuml, mode, 2, FALSE, TRUE, "read16mask", &ppc->impstate->read16mask[mode], NULL); |
| 868 | static_generate_memory_accessor(drcuml, mode, 2, FALSE, FALSE, "read16", &ppc->impstate->read16[mode], ppc->impstate->read16mask[mode]); |
| 869 | static_generate_memory_accessor(drcuml, mode, 2, TRUE, TRUE, "write16mask", &ppc->impstate->write16mask[mode], NULL); |
| 870 | static_generate_memory_accessor(drcuml, mode, 2, TRUE, FALSE, "write16", &ppc->impstate->write16[mode], ppc->impstate->write16mask[mode]); |
| 871 | static_generate_memory_accessor(drcuml, mode, 4, FALSE, TRUE, "read32mask", &ppc->impstate->read32mask[mode], NULL); |
| 872 | static_generate_memory_accessor(drcuml, mode, 4, FALSE, FALSE, "read32align", &ppc->impstate->read32align[mode], NULL); |
| 873 | static_generate_memory_accessor(drcuml, mode, 4, FALSE, FALSE, "read32", &ppc->impstate->read32[mode], ppc->impstate->read32mask[mode]); |
| 874 | static_generate_memory_accessor(drcuml, mode, 4, TRUE, TRUE, "write32mask", &ppc->impstate->write32mask[mode], NULL); |
| 875 | static_generate_memory_accessor(drcuml, mode, 4, TRUE, FALSE, "write32align",&ppc->impstate->write32align[mode],NULL); |
| 876 | static_generate_memory_accessor(drcuml, mode, 4, TRUE, FALSE, "write32", &ppc->impstate->write32[mode], ppc->impstate->write32mask[mode]); |
| 877 | static_generate_memory_accessor(drcuml, mode, 8, FALSE, TRUE, "read64mask", &ppc->impstate->read64mask[mode], NULL); |
| 878 | static_generate_memory_accessor(drcuml, mode, 8, FALSE, FALSE, "read64", &ppc->impstate->read64[mode], ppc->impstate->read64mask[mode]); |
| 879 | static_generate_memory_accessor(drcuml, mode, 8, TRUE, TRUE, "write64mask", &ppc->impstate->write64mask[mode], NULL); |
| 880 | static_generate_memory_accessor(drcuml, mode, 8, TRUE, FALSE, "write64", &ppc->impstate->write64[mode], ppc->impstate->write64mask[mode]); |
| 726 | 881 | } |
| 727 | | #endif |
| 882 | } |
| 728 | 883 | |
| 729 | | #if (HAS_PPC602) |
| 730 | | if (ppc.is602) { |
| 731 | | switch(spr) |
| 732 | | { |
| 733 | | case SPR602_LT: return ppc.lt; |
| 734 | | case SPR602_IBR: return ppc.ibr; |
| 735 | | case SPR602_ESASRR: return ppc.esasrr; |
| 736 | | case SPR602_SEBR: return ppc.sebr; |
| 737 | | case SPR602_SER: return ppc.ser; |
| 738 | | case SPR602_SP: return ppc.sp; |
| 739 | | case SPR602_TCR: return ppc.tcr; |
| 740 | | } |
| 741 | | } |
| 742 | | #endif |
| 743 | 884 | |
| 744 | | #if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601 || HAS_PPC604) |
| 745 | | if (ppc.is603 || ppc.is602) |
| 746 | | { |
| 747 | | switch (spr) |
| 748 | | { |
| 749 | | case SPR603E_TBL_R: |
| 750 | | fatalerror("ppc: get_spr: TBL_R "); |
| 751 | | break; |
| 885 | /*------------------------------------------------- |
| 886 | code_compile_block - compile a block of the |
| 887 | given mode at the specified pc |
| 888 | -------------------------------------------------*/ |
| 752 | 889 | |
| 753 | | case SPR603E_TBU_R: |
| 754 | | fatalerror("ppc: get_spr: TBU_R "); |
| 755 | | break; |
| 890 | static void code_compile_block(drcuml_state *drcuml, UINT8 mode, offs_t pc) |
| 891 | { |
| 892 | compiler_state compiler = { 0 }; |
| 893 | const opcode_desc *seqhead, *seqlast; |
| 894 | const opcode_desc *desclist; |
| 895 | int override = FALSE; |
| 896 | drcuml_block *block; |
| 897 | jmp_buf errorbuf; |
| 756 | 898 | |
| 757 | | case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); |
| 758 | | case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); |
| 759 | | case SPR603E_HID0: return ppc.hid0; |
| 760 | | case SPR603E_HID1: return ppc.hid1; |
| 761 | | case SPR603E_HID2: return ppc.hid2; |
| 762 | | case SPR603E_DEC: return read_decrementer(); |
| 763 | | case SPR603E_SDR1: return ppc.sdr1; |
| 764 | | case SPR603E_DSISR: return ppc.dsisr; |
| 765 | | case SPR603E_DAR: return ppc.dar; |
| 766 | | case SPR603E_EAR: return ppc.ear; |
| 767 | | case SPR603E_IBAT0L: return ppc.ibat[0].l; |
| 768 | | case SPR603E_IBAT0U: return ppc.ibat[0].u; |
| 769 | | case SPR603E_IBAT1L: return ppc.ibat[1].l; |
| 770 | | case SPR603E_IBAT1U: return ppc.ibat[1].u; |
| 771 | | case SPR603E_IBAT2L: return ppc.ibat[2].l; |
| 772 | | case SPR603E_IBAT2U: return ppc.ibat[2].u; |
| 773 | | case SPR603E_IBAT3L: return ppc.ibat[3].l; |
| 774 | | case SPR603E_IBAT3U: return ppc.ibat[3].u; |
| 775 | | case SPR603E_DBAT0L: return ppc.dbat[0].l; |
| 776 | | case SPR603E_DBAT0U: return ppc.dbat[0].u; |
| 777 | | case SPR603E_DBAT1L: return ppc.dbat[1].l; |
| 778 | | case SPR603E_DBAT1U: return ppc.dbat[1].u; |
| 779 | | case SPR603E_DBAT2L: return ppc.dbat[2].l; |
| 780 | | case SPR603E_DBAT2U: return ppc.dbat[2].u; |
| 781 | | case SPR603E_DBAT3L: return ppc.dbat[3].l; |
| 782 | | case SPR603E_DBAT3U: return ppc.dbat[3].u; |
| 783 | | } |
| 784 | | } |
| 785 | | #endif |
| 899 | /* get a description of this sequence */ |
| 900 | desclist = drcfe_describe_code(ppc->impstate->drcfe, pc); |
| 901 | if (LOG_UML || LOG_NATIVE) |
| 902 | log_opcode_desc(drcuml, desclist, 0); |
| 786 | 903 | |
| 787 | | fatalerror("ppc: get_spr: unknown spr %d (%03X) !", spr, spr); |
| 788 | | return 0; |
| 789 | | } |
| 904 | /* if we get an error back, flush the cache and try again */ |
| 905 | if (setjmp(errorbuf) != 0) |
| 906 | code_flush_cache(drcuml); |
| 790 | 907 | |
| 791 | | static UINT8 ppc_read8_translated(offs_t address); |
| 792 | | static UINT16 ppc_read16_translated(offs_t address); |
| 793 | | static UINT32 ppc_read32_translated(offs_t address); |
| 794 | | static UINT64 ppc_read64_translated(offs_t address); |
| 795 | | static void ppc_write8_translated(offs_t address, UINT8 data); |
| 796 | | static void ppc_write16_translated(offs_t address, UINT16 data); |
| 797 | | static void ppc_write32_translated(offs_t address, UINT32 data); |
| 798 | | static void ppc_write64_translated(offs_t address, UINT64 data); |
| 908 | /* start the block */ |
| 909 | block = drcuml_block_begin(drcuml, 4096, &errorbuf); |
| 799 | 910 | |
| 800 | | INLINE void ppc_set_msr(UINT32 value) |
| 801 | | { |
| 802 | | if( value & (MSR_ILE | MSR_LE) ) |
| 803 | | fatalerror("ppc: set_msr: little_endian mode not supported !"); |
| 911 | /* loop until we get through all instruction sequences */ |
| 912 | for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next) |
| 913 | { |
| 914 | const opcode_desc *curdesc; |
| 915 | UINT32 nextpc; |
| 804 | 916 | |
| 805 | | MSR = value; |
| 917 | /* add a code log entry */ |
| 918 | if (LOG_UML) |
| 919 | UML_COMMENT(block, "-------------------------"); // comment |
| 806 | 920 | |
| 807 | | if (ppc.is603 || ppc.is602) |
| 808 | | { |
| 809 | | if (!(MSR & MSR_DR)) |
| 921 | /* determine the last instruction in this sequence */ |
| 922 | for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next) |
| 923 | if (seqlast->flags & OPFLAG_END_SEQUENCE) |
| 924 | break; |
| 925 | assert(seqlast != NULL); |
| 926 | |
| 927 | /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ |
| 928 | if (override || !drcuml_hash_exists(drcuml, mode, seqhead->pc)) |
| 929 | UML_HASH(block, mode, seqhead->pc); // hash mode,pc |
| 930 | |
| 931 | /* if we already have a hash, and this is the first sequence, assume that we */ |
| 932 | /* are recompiling due to being out of sync and allow future overrides */ |
| 933 | else if (seqhead == desclist) |
| 810 | 934 | { |
| 811 | | ppc.read8 = program_read_byte_64be; |
| 812 | | ppc.read16 = program_read_word_64be; |
| 813 | | ppc.read32 = program_read_dword_64be; |
| 814 | | ppc.read64 = program_read_qword_64be; |
| 815 | | ppc.write8 = program_write_byte_64be; |
| 816 | | ppc.write16 = program_write_word_64be; |
| 817 | | ppc.write32 = program_write_dword_64be; |
| 818 | | ppc.write64 = program_write_qword_64be; |
| 935 | override = TRUE; |
| 936 | UML_HASH(block, mode, seqhead->pc); // hash mode,pc |
| 819 | 937 | } |
| 938 | |
| 939 | /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ |
| 820 | 940 | else |
| 821 | 941 | { |
| 822 | | ppc.read8 = ppc_read8_translated; |
| 823 | | ppc.read16 = ppc_read16_translated; |
| 824 | | ppc.read32 = ppc_read32_translated; |
| 825 | | ppc.read64 = ppc_read64_translated; |
| 826 | | ppc.write8 = ppc_write8_translated; |
| 827 | | ppc.write16 = ppc_write16_translated; |
| 828 | | ppc.write32 = ppc_write32_translated; |
| 829 | | ppc.write64 = ppc_write64_translated; |
| 942 | UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 |
| 943 | UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(seqhead->pc), ppc->impstate->nocode); |
| 944 | // hashjmp <mode>,seqhead->pc,nocode |
| 945 | continue; |
| 830 | 946 | } |
| 947 | |
| 948 | /* validate this code block if we're not pointing into ROM */ |
| 949 | if (memory_get_write_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, seqhead->physpc) != NULL) |
| 950 | generate_checksum_block(block, &compiler, seqhead, seqlast); // <checksum> |
| 951 | |
| 952 | /* label this instruction, if it may be jumped to locally */ |
| 953 | if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) |
| 954 | UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 |
| 955 | |
| 956 | /* iterate over instructions in the sequence and compile them */ |
| 957 | for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) |
| 958 | generate_sequence_instruction(block, &compiler, curdesc); // <instruction> |
| 959 | |
| 960 | /* if we need to return to the start, do it */ |
| 961 | if (seqlast->flags & OPFLAG_RETURN_TO_START) |
| 962 | nextpc = pc; |
| 963 | |
| 964 | /* otherwise we just go to the next instruction */ |
| 965 | else |
| 966 | nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; |
| 967 | |
| 968 | /* count off cycles and go there */ |
| 969 | generate_update_cycles(block, &compiler, IMM(nextpc), TRUE); // <subtract cycles> |
| 970 | |
| 971 | /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ |
| 972 | if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) |
| 973 | UML_HASHJMP(block, MEM(&ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode |
| 974 | else if (seqlast->next == NULL || seqlast->next->pc != nextpc) |
| 975 | UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode |
| 831 | 976 | } |
| 977 | |
| 978 | /* end the sequence */ |
| 979 | drcuml_block_end(block); |
| 832 | 980 | } |
| 833 | 981 | |
| 834 | | INLINE UINT32 ppc_get_msr(void) |
| 982 | |
| 983 | |
| 984 | /*************************************************************************** |
| 985 | C FUNCTION CALLBACKS |
| 986 | ***************************************************************************/ |
| 987 | |
| 988 | /*------------------------------------------------- |
| 989 | cfunc_printf_exception - log any exceptions that |
| 990 | aren't interrupts |
| 991 | -------------------------------------------------*/ |
| 992 | |
| 993 | static void cfunc_printf_exception(void *param) |
| 835 | 994 | { |
| 836 | | return MSR; |
| 995 | printf("Exception: type=%2d EPC=%08X MSR=%08X\n", ppc->param0, ppc->spr[SPROEA_SRR0], ppc->spr[SPROEA_SRR1]); |
| 996 | cfunc_printf_probe((void *)(FPTR)ppc->spr[SPROEA_SRR0]); |
| 837 | 997 | } |
| 838 | 998 | |
| 839 | | INLINE void ppc_set_cr(UINT32 value) |
| 999 | |
| 1000 | /*------------------------------------------------- |
| 1001 | cfunc_printf_debug - generic printf for |
| 1002 | debugging |
| 1003 | -------------------------------------------------*/ |
| 1004 | |
| 1005 | static void cfunc_printf_debug(void *param) |
| 840 | 1006 | { |
| 841 | | CR(0) = (value >> 28) & 0xf; |
| 842 | | CR(1) = (value >> 24) & 0xf; |
| 843 | | CR(2) = (value >> 20) & 0xf; |
| 844 | | CR(3) = (value >> 16) & 0xf; |
| 845 | | CR(4) = (value >> 12) & 0xf; |
| 846 | | CR(5) = (value >> 8) & 0xf; |
| 847 | | CR(6) = (value >> 4) & 0xf; |
| 848 | | CR(7) = (value >> 0) & 0xf; |
| 1007 | const char *format = param; |
| 1008 | printf(format, ppc->impstate->arg0, ppc->impstate->arg1); |
| 849 | 1009 | } |
| 850 | 1010 | |
| 851 | | INLINE UINT32 ppc_get_cr(void) |
| 1011 | |
| 1012 | /*------------------------------------------------- |
| 1013 | cfunc_printf_probe - print the current CPU |
| 1014 | state and return |
| 1015 | -------------------------------------------------*/ |
| 1016 | |
| 1017 | static void cfunc_printf_probe(void *param) |
| 852 | 1018 | { |
| 853 | | return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); |
| 1019 | UINT32 pc = (UINT32)(FPTR)param; |
| 1020 | |
| 1021 | printf(" PC=%08X\n", pc); |
| 1022 | printf(" r0=%08X r1=%08X r2=%08X r3=%08X\n", |
| 1023 | ppc->r[0], ppc->r[1], ppc->r[2], ppc->r[3]); |
| 1024 | printf(" r4=%08X r5=%08X r6=%08X r7=%08X\n", |
| 1025 | ppc->r[4], ppc->r[5], ppc->r[6], ppc->r[7]); |
| 1026 | printf(" r8=%08X r9=%08X r10=%08X r11=%08X\n", |
| 1027 | ppc->r[8], ppc->r[9], ppc->r[10], ppc->r[11]); |
| 1028 | printf("r12=%08X r13=%08X r14=%08X r15=%08X\n", |
| 1029 | ppc->r[12], ppc->r[13], ppc->r[14], ppc->r[15]); |
| 1030 | printf("r16=%08X r17=%08X r18=%08X r19=%08X\n", |
| 1031 | ppc->r[16], ppc->r[17], ppc->r[18], ppc->r[19]); |
| 1032 | printf("r20=%08X r21=%08X r22=%08X r23=%08X\n", |
| 1033 | ppc->r[20], ppc->r[21], ppc->r[22], ppc->r[23]); |
| 1034 | printf("r24=%08X r25=%08X r26=%08X r27=%08X\n", |
| 1035 | ppc->r[24], ppc->r[25], ppc->r[26], ppc->r[27]); |
| 1036 | printf("r28=%08X r29=%08X r30=%08X r31=%08X\n", |
| 1037 | ppc->r[28], ppc->r[29], ppc->r[30], ppc->r[31]); |
| 854 | 1038 | } |
| 855 | 1039 | |
| 856 | | #ifdef UNUSED_FUNCTION |
| 857 | | static void log_code(drc_core *drc) |
| 1040 | |
| 1041 | /*------------------------------------------------- |
| 1042 | cfunc_unimplemented - handler for |
| 1043 | unimplemented opcdes |
| 1044 | -------------------------------------------------*/ |
| 1045 | |
| 1046 | static void cfunc_unimplemented(void *param) |
| 858 | 1047 | { |
| 859 | | #if LOG_CODE |
| 860 | | FILE *temp; |
| 861 | | temp = fopen("code.bin", "wb"); |
| 862 | | fwrite(drc->cache_base, 1, drc->cache_top - drc->cache_base, temp); |
| 863 | | fclose(temp); |
| 864 | | #endif |
| 1048 | UINT32 opcode = (FPTR)param; |
| 1049 | fatalerror("PC=%08X: Unimplemented op %08X", ppc->pc, opcode); |
| 865 | 1050 | } |
| 866 | | #endif |
| 867 | 1051 | |
| 868 | | /***********************************************************************/ |
| 869 | 1052 | |
| 870 | | #include "ppc_mem.c" |
| 871 | 1053 | |
| 872 | | #if (HAS_PPC403) |
| 873 | | #include "ppc403.c" |
| 874 | | #endif |
| 875 | | |
| 876 | | #if (HAS_PPC602) |
| 877 | | #include "ppc602.c" |
| 878 | | #endif |
| 879 | | |
| 880 | 1054 | /*************************************************************************** |
| 881 | | CODE LOGGING |
| 1055 | STATIC CODEGEN |
| 882 | 1056 | ***************************************************************************/ |
| 883 | 1057 | |
| 884 | | #if LOG_CODE |
| 1058 | /*------------------------------------------------- |
| 1059 | static_generate_entry_point - generate a |
| 1060 | static entry point |
| 1061 | -------------------------------------------------*/ |
| 885 | 1062 | |
| 886 | | static code_log_entry code_log_buffer[MAX_INSTRUCTIONS*2]; |
| 887 | | static int code_log_index; |
| 888 | | static FILE *logfile; |
| 1063 | static void static_generate_entry_point(drcuml_state *drcuml) |
| 1064 | { |
| 1065 | drcuml_codelabel skip = 1; |
| 1066 | drcuml_block *block; |
| 1067 | jmp_buf errorbuf; |
| 889 | 1068 | |
| 1069 | /* if we get an error back, we're screwed */ |
| 1070 | if (setjmp(errorbuf) != 0) |
| 1071 | fatalerror("Unrecoverable error in static_generate_entry_point"); |
| 890 | 1072 | |
| 1073 | /* begin generating */ |
| 1074 | block = drcuml_block_begin(drcuml, 20, &errorbuf); |
| 1075 | |
| 1076 | /* forward references */ |
| 1077 | alloc_handle(drcuml, &ppc->impstate->nocode, "nocode"); |
| 1078 | alloc_handle(drcuml, &ppc->impstate->exception_norecover[EXCEPTION_EI], "exception_ei_norecover"); |
| 1079 | |
| 1080 | alloc_handle(drcuml, &ppc->impstate->entry, "entry"); |
| 1081 | UML_HANDLE(block, ppc->impstate->entry); // handle entry |
| 1082 | |
| 1083 | /* reset the FPU mode */ |
| 1084 | UML_AND(block, IREG(0), FPSCR32, IMM(3)); // and i0,fpscr,3 |
| 1085 | UML_LOAD(block, IREG(0), &ppc->impstate->fpmode[0], IREG(0), BYTE); // load i0,fpmode,i0,byte |
| 1086 | UML_SETFMOD(block, IREG(0)); // setfmod i0 |
| 1087 | |
| 1088 | /* load fast integer registers */ |
| 1089 | load_fast_iregs(block); // <load fastregs> |
| 1090 | |
| 1091 | /* check for interrupts */ |
| 1092 | UML_TEST(block, MEM(&ppc->irq_pending), IMM(~0)); // test [irq_pending],0 |
| 1093 | UML_JMPc(block, IF_Z, skip); // jmp skip,Z |
| 1094 | UML_TEST(block, MSR32, IMM(MSR_EE)); // test msr,MSR_EE |
| 1095 | UML_JMPc(block, IF_Z, skip); // jmp skip,Z |
| 1096 | UML_MOV(block, IREG(0), MEM(&ppc->pc)); // mov i0,pc |
| 1097 | UML_MOV(block, IREG(1), IMM(0)); // mov i1,0 |
| 1098 | UML_CALLH(block, ppc->impstate->exception_norecover[EXCEPTION_EI]); // callh exception_norecover |
| 1099 | UML_LABEL(block, skip); // skip: |
| 1100 | |
| 1101 | /* generate a hash jump via the current mode and PC */ |
| 1102 | UML_HASHJMP(block, MEM(&ppc->impstate->mode), MEM(&ppc->pc), ppc->impstate->nocode); // hashjmp <mode>,<pc>,nocode |
| 1103 | |
| 1104 | drcuml_block_end(block); |
| 1105 | } |
| 1106 | |
| 1107 | |
| 891 | 1108 | /*------------------------------------------------- |
| 892 | | open_logfile - open the log file if it is |
| 893 | | not already opened |
| 1109 | static_generate_nocode_handler - generate an |
| 1110 | exception handler for "out of code" |
| 894 | 1111 | -------------------------------------------------*/ |
| 895 | 1112 | |
| 896 | | INLINE int open_logfile(void) |
| 1113 | static void static_generate_nocode_handler(drcuml_state *drcuml) |
| 897 | 1114 | { |
| 898 | | if (logfile == NULL) |
| 899 | | logfile = fopen("ppcdrc.asm", "w"); |
| 900 | | return (logfile != NULL); |
| 1115 | drcuml_block *block; |
| 1116 | jmp_buf errorbuf; |
| 1117 | |
| 1118 | /* if we get an error back, we're screwed */ |
| 1119 | if (setjmp(errorbuf) != 0) |
| 1120 | fatalerror("Unrecoverable error in static_generate_nocode_handler"); |
| 1121 | |
| 1122 | /* begin generating */ |
| 1123 | block = drcuml_block_begin(drcuml, 10, &errorbuf); |
| 1124 | |
| 1125 | /* generate a hash jump via the current mode and PC */ |
| 1126 | alloc_handle(drcuml, &ppc->impstate->nocode, "nocode"); |
| 1127 | UML_HANDLE(block, ppc->impstate->nocode); // handle nocode |
| 1128 | UML_GETEXP(block, IREG(0)); // getexp i0 |
| 1129 | UML_MOV(block, MEM(&ppc->pc), IREG(0)); // mov [pc],i0 |
| 1130 | save_fast_iregs(block); // <save fastregs> |
| 1131 | UML_EXIT(block, IMM(EXECUTE_MISSING_CODE)); // exit EXECUTE_MISSING_CODE |
| 1132 | |
| 1133 | drcuml_block_end(block); |
| 901 | 1134 | } |
| 902 | 1135 | |
| 903 | 1136 | |
| 904 | 1137 | /*------------------------------------------------- |
| 905 | | code_log_reset - reset the logging index |
| 1138 | static_generate_out_of_cycles - generate an |
| 1139 | out of cycles exception handler |
| 906 | 1140 | -------------------------------------------------*/ |
| 907 | 1141 | |
| 908 | | INLINE void code_log_reset(void) |
| 1142 | static void static_generate_out_of_cycles(drcuml_state *drcuml) |
| 909 | 1143 | { |
| 910 | | code_log_index = 0; |
| 1144 | drcuml_block *block; |
| 1145 | jmp_buf errorbuf; |
| 1146 | |
| 1147 | /* if we get an error back, we're screwed */ |
| 1148 | if (setjmp(errorbuf) != 0) |
| 1149 | fatalerror("Unrecoverable error in static_generate_out_of_cycles"); |
| 1150 | |
| 1151 | /* begin generating */ |
| 1152 | block = drcuml_block_begin(drcuml, 10, &errorbuf); |
| 1153 | |
| 1154 | /* generate a hash jump via the current mode and PC */ |
| 1155 | alloc_handle(drcuml, &ppc->impstate->out_of_cycles, "out_of_cycles"); |
| 1156 | UML_HANDLE(block, ppc->impstate->out_of_cycles); // handle out_of_cycles |
| 1157 | UML_GETEXP(block, IREG(0)); // getexp i0 |
| 1158 | UML_MOV(block, MEM(&ppc->pc), IREG(0)); // mov <pc>,i0 |
| 1159 | save_fast_iregs(block); // <save fastregs> |
| 1160 | UML_EXIT(block, IMM(EXECUTE_OUT_OF_CYCLES)); // exit EXECUTE_OUT_OF_CYCLES |
| 1161 | |
| 1162 | drcuml_block_end(block); |
| 911 | 1163 | } |
| 912 | 1164 | |
| 913 | 1165 | |
| 914 | 1166 | /*------------------------------------------------- |
| 915 | | code_log_add_entry - add an entry to the log |
| 1167 | static_generate_tlb_mismatch - generate a |
| 1168 | TLB mismatch handler |
| 916 | 1169 | -------------------------------------------------*/ |
| 917 | 1170 | |
| 918 | | INLINE void code_log_add_entry(UINT32 pc, UINT32 op, void *base) |
| 1171 | static void static_generate_tlb_mismatch(drcuml_state *drcuml) |
| 919 | 1172 | { |
| 920 | | code_log_buffer[code_log_index].pc = pc; |
| 921 | | code_log_buffer[code_log_index].op = op; |
| 922 | | code_log_buffer[code_log_index].base = base; |
| 923 | | code_log_index++; |
| 1173 | drcuml_block *block; |
| 1174 | jmp_buf errorbuf; |
| 1175 | int isi, label = 1; |
| 1176 | |
| 1177 | /* if we get an error back, we're screwed */ |
| 1178 | if (setjmp(errorbuf) != 0) |
| 1179 | fatalerror("Unrecoverable error in static_generate_tlb_mismatch"); |
| 1180 | |
| 1181 | /* forward references */ |
| 1182 | alloc_handle(drcuml, &ppc->impstate->exception[EXCEPTION_ISI], "exception_isi"); |
| 1183 | if (ppc->cap & PPCCAP_603_MMU) |
| 1184 | alloc_handle(drcuml, &ppc->impstate->exception[EXCEPTION_ITLBMISS], "exception_itlb_miss"); |
| 1185 | |
| 1186 | /* begin generating */ |
| 1187 | block = drcuml_block_begin(drcuml, 20, &errorbuf); |
| 1188 | |
| 1189 | /* generate a hash jump via the current mode and PC */ |
| 1190 | alloc_handle(drcuml, &ppc->impstate->tlb_mismatch, "tlb_mismatch"); |
| 1191 | UML_HANDLE(block, ppc->impstate->tlb_mismatch); // handle tlb_mismatch |
| 1192 | UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC |
| 1193 | UML_MOV(block, MEM(&ppc->param0), IREG(0)); // mov [param0],i0 |
| 1194 | UML_MOV(block, MEM(&ppc->param1), IMM(TRANSLATE_FETCH)); // mov [param1],TRANSLATE_FETCH |
| 1195 | UML_CALLC(block, ppccom_tlb_fill, ppc); // callc tlbfill,ppc |
| 1196 | UML_CMP(block, MEM(&ppc->param0), IMM(1)); // cmp [param0],1 |
| 1197 | UML_JMPc(block, IF_A, isi = label++); // jmp isi,A |
| 1198 | save_fast_iregs(block); // <save fastregs> |
| 1199 | UML_EXIT(block, IMM(EXECUTE_MISSING_CODE)); // exit EXECUTE_MISSING_CODE |
| 1200 | UML_LABEL(block, isi); // isi: |
| 1201 | if (!(ppc->cap & PPCCAP_603_MMU)) |
| 1202 | { |
| 1203 | UML_MOV(block, SPR32(SPROEA_DSISR), MEM(&ppc->param0)); // mov [dsisr],[param0] |
| 1204 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_ISI], IREG(0)); // exh isi,i0 |
| 1205 | } |
| 1206 | else |
| 1207 | { |
| 1208 | UML_MOV(block, SPR32(SPR603_IMISS), IREG(0)); // mov [imiss],i0 |
| 1209 | UML_MOV(block, SPR32(SPR603_ICMP), MEM(&ppc->mmu603_cmp)); // mov [icmp],[mmu603_cmp] |
| 1210 | UML_MOV(block, SPR32(SPR603_HASH1), MEM(&ppc->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] |
| 1211 | UML_MOV(block, SPR32(SPR603_HASH2), MEM(&ppc->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] |
| 1212 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_ITLBMISS], IREG(0)); // exh itlbmiss,i0 |
| 1213 | } |
| 1214 | |
| 1215 | drcuml_block_end(block); |
| 924 | 1216 | } |
| 925 | 1217 | |
| 926 | 1218 | |
| 927 | 1219 | /*------------------------------------------------- |
| 928 | | code_log - actually log some code |
| 1220 | static_generate_exception - generate a static |
| 1221 | exception handler |
| 929 | 1222 | -------------------------------------------------*/ |
| 930 | 1223 | |
| 931 | | static void code_log(const char *label, x86code *start, x86code *stop) |
| 1224 | static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int recover, const char *name) |
| 932 | 1225 | { |
| 933 | | extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode); |
| 934 | | offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); |
| 935 | | UINT8 *cur = start; |
| 1226 | drcuml_codehandle **exception_handle = recover ? &ppc->impstate->exception[exception] : &ppc->impstate->exception_norecover[exception]; |
| 1227 | UINT32 vector = exception << 8; |
| 1228 | drcuml_codelabel label = 1; |
| 1229 | drcuml_block *block; |
| 1230 | jmp_buf errorbuf; |
| 936 | 1231 | |
| 937 | | /* open the file, creating it if necessary */ |
| 938 | | if (!open_logfile()) |
| 939 | | return; |
| 940 | | fprintf(logfile, "\n%s\n", label); |
| 1232 | /* if we get an error back, we're screwed */ |
| 1233 | if (setjmp(errorbuf) != 0) |
| 1234 | fatalerror("Unrecoverable error in static_generate_exception"); |
| 941 | 1235 | |
| 942 | | /* loop from the start until the cache top */ |
| 943 | | while (cur < stop) |
| 1236 | /* begin generating */ |
| 1237 | block = drcuml_block_begin(drcuml, 1024, &errorbuf); |
| 1238 | |
| 1239 | /* add a global entry for this */ |
| 1240 | alloc_handle(drcuml, exception_handle, name); |
| 1241 | UML_HANDLE(block, *exception_handle); // handle name |
| 1242 | |
| 1243 | /* exception parameter is expected to be the fault address in this case */ |
| 1244 | if (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI) |
| 944 | 1245 | { |
| 945 | | char buffer[100]; |
| 946 | | int bytes; |
| 947 | | int op; |
| 1246 | UML_GETEXP(block, IREG(0)); // getexp i0 |
| 1247 | UML_MOV(block, SPR32(SPROEA_DAR), IREG(0)); // mov [dar],i0 |
| 1248 | } |
| 948 | 1249 | |
| 949 | | /* skip filler opcodes */ |
| 950 | | if (*cur == 0xcc) |
| 1250 | /* fetch the PC and uncounted cycles */ |
| 1251 | if (recover) |
| 1252 | { |
| 1253 | UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC |
| 1254 | UML_RECOVER(block, IREG(1), MAPVAR_CYCLES); // recover i1,CYCLES |
| 1255 | } |
| 1256 | |
| 1257 | /* OEA handling of SRR exceptions */ |
| 1258 | if (ppc->cap & PPCCAP_OEA) |
| 1259 | { |
| 1260 | 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; |
| 1261 | UINT32 msrormask = 0; |
| 1262 | |
| 1263 | /* check registers to see the real source of our exception (EI exceptions only) */ |
| 1264 | UML_MOV(block, IREG(3), IMM(vector)); // mov i3,vector |
| 1265 | if (exception == EXCEPTION_EI) |
| 951 | 1266 | { |
| 952 | | cur++; |
| 953 | | continue; |
| 1267 | drcuml_codelabel not_decrementer; |
| 1268 | |
| 1269 | UML_TEST(block, MEM(&ppc->irq_pending), IMM(0x01)); // test [irq_pending],0x01 |
| 1270 | UML_JMPc(block, IF_NZ, not_decrementer = label++); // jmp not_decrementer,nz |
| 1271 | UML_MOV(block, IREG(3), IMM(EXCEPTION_DECREMENT << 8)); // mov i3,EXCEPTION_DECREMENT << 8 |
| 1272 | UML_AND(block, MEM(&ppc->irq_pending), MEM(&ppc->irq_pending), IMM(~0x02)); // and [irq_pending],[irq_pending],~0x02 |
| 1273 | UML_LABEL(block, not_decrementer); // not_decrementer: |
| 954 | 1274 | } |
| 955 | 1275 | |
| 956 | | /* disassemble this instruction */ |
| 957 | | #ifdef PTR64 |
| 958 | | bytes = i386_dasm_one(buffer, (UINT32)(FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK; |
| 959 | | #else |
| 960 | | bytes = i386_dasm_one(buffer, (UINT32)cur, cur, 32) & DASMFLAG_LENGTHMASK; |
| 961 | | #endif |
| 1276 | /* exception PC goes into SRR0 */ |
| 1277 | UML_MOV(block, SPR32(SPROEA_SRR0), IREG(0)); // mov [srr0],i0 |
| 962 | 1278 | |
| 963 | | /* look for a match in the registered opcodes */ |
| 964 | | for (op = 0; op < code_log_index; op++) |
| 965 | | if (code_log_buffer[op].base == (void *)cur) |
| 966 | | break; |
| 1279 | /* MSR bits go into SRR1, along with some exception-specific data */ |
| 1280 | UML_AND(block, SPR32(SPROEA_SRR1), MSR32, IMM(0x87c0ffff)); // and [srr1],[msr],0x87c0ffff |
| 1281 | if (exception == EXCEPTION_PROGRAM) |
| 1282 | { |
| 1283 | UML_GETEXP(block, IREG(1)); // getexp i1 |
| 1284 | UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), IREG(1)); // or [srr1],[srr1],i1 |
| 1285 | } |
| 1286 | if (ppc->cap & PPCCAP_603_MMU) |
| 1287 | { |
| 1288 | if (exception == EXCEPTION_ITLBMISS) |
| 1289 | UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), IMM(0x00040000)); // or [srr1],0x00040000 |
| 1290 | else if (exception == EXCEPTION_DTLBMISSL) |
| 1291 | UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), IMM(0x00010000)); // or [srr1],0x00010000 |
| 1292 | if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) |
| 1293 | UML_ROLINS(block, SPR32(SPROEA_SRR1), CR32, IMM(0), IMM(CRMASK(0))); // rolins [srr1],[cr],0,crmask(0) |
| 1294 | } |
| 967 | 1295 | |
| 968 | | /* if no match, just output the current instruction */ |
| 969 | | if (op == code_log_index) |
| 970 | | fprintf(logfile, "%p: %s\n", cur, buffer); |
| 1296 | /* update MSR */ |
| 1297 | if (ppc->cap & PPCCAP_603_MMU) |
| 1298 | { |
| 1299 | if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) |
| 1300 | msrormask |= MSR603_TGPR; |
| 1301 | else |
| 1302 | msrandmask |= MSR603_TGPR; |
| 1303 | UML_MOV(block, IREG(0), MSR32); // mov i0,[msr] |
| 1304 | } |
| 1305 | UML_AND(block, IREG(2), MSR32, IMM(~msrandmask)); // and i2,[msr],~andmask |
| 1306 | UML_OR(block, IREG(2), IREG(2), IMM(msrormask)); // or i2,i2,ormask |
| 1307 | UML_ROLINS(block, IREG(2), IREG(2), IMM(16), IMM(MSR_LE)); // rolins i2,u2,16,MSR_LE |
| 1308 | UML_MOV(block, MSR32, IREG(2)); // mov [msr],i2 |
| 1309 | if (ppc->cap & PPCCAP_603_MMU) |
| 1310 | { |
| 1311 | UML_XOR(block, IREG(0), IREG(0), IREG(2)); // xor i0,i0,i2 |
| 1312 | UML_TEST(block, IREG(0), IMM(MSR603_TGPR)); // test i0,tgpr |
| 1313 | UML_CALLHc(block, IF_NZ, ppc->impstate->swap_tgpr); // callh swap_tgpr,nz |
| 1314 | } |
| 1315 | generate_update_mode(block); // <update mode> |
| 971 | 1316 | |
| 972 | | /* otherwise, output with the original instruction to the right */ |
| 1317 | /* determine our target PC */ |
| 1318 | UML_MOV(block, IREG(0), IMM(0x00000000)); // mov i0,0x00000000 |
| 1319 | UML_TEST(block, MSR32, IMM(MSROEA_IP)); // test [msr],IP |
| 1320 | UML_MOVc(block, IF_NZ, IREG(0), IMM(0xfff00000)); // mov i0,0xfff00000,nz |
| 1321 | UML_OR(block, IREG(0), IREG(0), IREG(3)); // or i0,i0,i3 |
| 1322 | } |
| 1323 | |
| 1324 | /* 4XX handling of exceptions */ |
| 1325 | if (ppc->cap & PPCCAP_4XX) |
| 1326 | { |
| 1327 | /* check registers to see the real source of our exception (EI exceptions only) */ |
| 1328 | UML_MOV(block, IREG(3), IMM(vector)); // mov i3,vector |
| 1329 | if (exception == EXCEPTION_EI) |
| 1330 | { |
| 1331 | drcuml_codelabel notwdog, common; |
| 1332 | |
| 1333 | UML_TEST(block, SPR32(SPR4XX_TSR), IMM(PPC4XX_TSR_PIS)); // test [tsr],PIS |
| 1334 | UML_MOVc(block, IF_NZ, IREG(3), IMM(0x1000)); // mov i3,0x1000,NZ |
| 1335 | UML_TEST(block, SPR32(SPR4XX_TSR), IMM(PPC4XX_TSR_FIS)); // test [tsr],FIS |
| 1336 | UML_MOVc(block, IF_NZ, IREG(3), IMM(0x1010)); // mov i3,0x1010,NZ |
| 1337 | UML_TEST(block, SPR32(DCR4XX_EXISR), SPR32(DCR4XX_EXIER)); // test [exisr],[exier] |
| 1338 | UML_MOVc(block, IF_NZ, IREG(3), IMM(vector)); // mov i3,vector,NZ |
| 1339 | UML_TEST(block, SPR32(SPR4XX_TSR), IMM(PPC4XX_TSR_WIS)); // test [tsr],WIS |
| 1340 | UML_JMPc(block, IF_Z, notwdog = label++); // jz notwdog |
| 1341 | UML_MOV(block, IREG(3), IMM(0x1020)); // mov i3,0x1020 |
| 1342 | |
| 1343 | /* exception PC goes into SRR2, MSR goes to SRR3 */ |
| 1344 | UML_MOV(block, SPR32(SPR4XX_SRR2), IREG(0)); // mov [srr2],i0 |
| 1345 | UML_MOV(block, SPR32(SPR4XX_SRR3), MSR32); // mov [srr3],[msr] |
| 1346 | UML_AND(block, IREG(2), MSR32, IMM(~(MSR4XX_WE | MSR_PR | MSR4XX_CE | MSR_EE | MSR4XX_DE | MSR4XX_PE))); |
| 1347 | UML_JMP(block, common = label++); // jmp common |
| 1348 | |
| 1349 | /* exception PC goes into SRR0, MSR goes to SRR1 */ |
| 1350 | UML_LABEL(block, notwdog); // notwdog: |
| 1351 | UML_MOV(block, SPR32(SPR4XX_SRR0), IREG(0)); // mov [srr0],i0 |
| 1352 | UML_MOV(block, SPR32(SPR4XX_SRR1), MSR32); // mov [srr1],[msr] |
| 1353 | UML_AND(block, IREG(2), MSR32, IMM(~(MSR4XX_WE | MSR_PR | MSR_EE | MSR4XX_PE)));// and i2,[msr],~(bunch-o-flags) |
| 1354 | UML_LABEL(block, common); // common: |
| 1355 | } |
| 973 | 1356 | else |
| 974 | 1357 | { |
| 975 | | char buffer2[100]; |
| 976 | | ppc_dasm_one(buffer2, code_log_buffer[op].pc, code_log_buffer[op].op); |
| 977 | | fprintf(logfile, "%p: %-50s %08X: %s\n", cur, buffer, code_log_buffer[op].pc, buffer2); |
| 1358 | /* exception PC goes into SRR0, MSR goes to SRR1 */ |
| 1359 | UML_MOV(block, SPR32(SPR4XX_SRR0), IREG(0)); // mov [srr0],i0 |
| 1360 | UML_MOV(block, SPR32(SPR4XX_SRR1), MSR32); // mov [srr1],[msr] |
| 1361 | UML_AND(block, IREG(2), MSR32, IMM(~(MSR4XX_WE | MSR_PR | MSR_EE | MSR4XX_PE)));// and i2,[msr],~(bunch-o-flags) |
| 978 | 1362 | } |
| 979 | 1363 | |
| 980 | | /* advance past this instruction */ |
| 981 | | cur += bytes; |
| 1364 | /* finish updating MSR */ |
| 1365 | UML_ROLINS(block, IREG(2), IREG(2), IMM(16), IMM(MSR_LE)); // rolins i2,u2,16,MSR_LE |
| 1366 | UML_MOV(block, MSR32, IREG(2)); // mov [msr],i2 |
| 1367 | generate_update_mode(block); // <update mode> |
| 1368 | |
| 1369 | /* program exception flags go to ESR */ |
| 1370 | if (exception == EXCEPTION_PROGRAM) |
| 1371 | { |
| 1372 | UML_GETEXP(block, IREG(1)); // getexp i1 |
| 1373 | UML_SHL(block, SPR32(SPR4XX_ESR), IREG(1), IMM(8)); // shl [esr],i1,8 |
| 1374 | } |
| 1375 | |
| 1376 | /* determine our target PC */ |
| 1377 | UML_ROLINS(block, IREG(3), SPR32(SPR4XX_EVPR), IMM(0), IMM(0xffff0000)); // rolins i3,[evpr],0,0xffff0000 |
| 1378 | UML_MOV(block, IREG(0), IREG(3)); // mov i0,i3 |
| 982 | 1379 | } |
| 983 | 1380 | |
| 984 | | /* flush the file */ |
| 985 | | fflush(logfile); |
| 1381 | /* optionally print exceptions */ |
| 1382 | if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_EI && exception != EXCEPTION_SYSCALL) || |
| 1383 | (PRINTF_MMU && (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI))) |
| 1384 | { |
| 1385 | UML_MOV(block, MEM(&ppc->param0), IMM(exception)); // mov [param0],exception |
| 1386 | UML_CALLC(block, cfunc_printf_exception, NULL); // callc cfunc_printf_exception,NULL |
| 1387 | } |
| 1388 | |
| 1389 | /* adjust cycles */ |
| 1390 | UML_SUBf(block, MEM(&ppc->icount), MEM(&ppc->icount), IREG(1), FLAGS_S); // sub icount,icount,cycles,S |
| 1391 | UML_EXHc(block, IF_S, ppc->impstate->out_of_cycles, IREG(0)); // exh out_of_cycles,i0 |
| 1392 | UML_HASHJMP(block, MEM(&ppc->impstate->mode), IREG(0), ppc->impstate->nocode); // hashjmp <mode>,i0,nocode |
| 1393 | |
| 1394 | drcuml_block_end(block); |
| 986 | 1395 | } |
| 987 | 1396 | |
| 988 | | #else |
| 989 | 1397 | |
| 990 | | #define code_log_reset() |
| 991 | | #define code_log_add_entry(a,b,c) |
| 992 | | #define code_log(a,b,c) |
| 1398 | /*------------------------------------------------------------------ |
| 1399 | static_generate_memory_accessor |
| 1400 | ------------------------------------------------------------------*/ |
| 993 | 1401 | |
| 994 | | #endif |
| 1402 | static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr, drcuml_codehandle *masked) |
| 1403 | { |
| 1404 | /* on entry, address is in I0; data for writes is in I1; masks are in I2 */ |
| 1405 | /* on exit, read result is in I0 */ |
| 1406 | /* routine trashes I0-I3 */ |
| 1407 | int fastxor = BYTE8_XOR_BE(0) >> (activecpu_databus_width(ADDRESS_SPACE_PROGRAM) < 64); |
| 1408 | drcuml_block *block; |
| 1409 | jmp_buf errorbuf; |
| 1410 | int tlbreturn = 0; |
| 1411 | int unaligned = 0; |
| 1412 | int alignex = 0; |
| 1413 | int tlbmiss = 0; |
| 1414 | int label = 1; |
| 1415 | int ramnum; |
| 995 | 1416 | |
| 1417 | /* if we get an error back, we're screwed */ |
| 1418 | if (setjmp(errorbuf) != 0) |
| 1419 | fatalerror("Unrecoverable error in static_generate_exception"); |
| 996 | 1420 | |
| 997 | | /********************************************************************/ |
| 1421 | /* begin generating */ |
| 1422 | block = drcuml_block_begin(drcuml, 1024, &errorbuf); |
| 998 | 1423 | |
| 999 | | #include "ppc_ops.c" |
| 1000 | | #include "drc_ops.c" |
| 1001 | | #include "drc_ops.h" |
| 1424 | /* add a global entry for this */ |
| 1425 | alloc_handle(drcuml, handleptr, name); |
| 1426 | UML_HANDLE(block, *handleptr); // handle *handleptr |
| 1002 | 1427 | |
| 1003 | | /* Initialization and shutdown */ |
| 1428 | /* check for unaligned accesses and break into two */ |
| 1429 | if (!ismasked && size != 1) |
| 1430 | { |
| 1431 | /* in little-endian mode, anything misaligned generates an exception */ |
| 1432 | if ((mode & MODE_LITTLE_ENDIAN) || masked == NULL || !(ppc->cap & PPCCAP_MISALIGNED)) |
| 1433 | { |
| 1434 | UML_TEST(block, IREG(0), IMM(size - 1)); // test i0,size-1 |
| 1435 | UML_JMPc(block, IF_NZ, alignex = label++); // jmp alignex,nz |
| 1436 | } |
| 1004 | 1437 | |
| 1005 | | static void ppc_init(void) |
| 1006 | | { |
| 1007 | | int i,j; |
| 1438 | /* in big-endian mode, it's more complicated */ |
| 1439 | else |
| 1440 | { |
| 1441 | /* 8-byte accesses must be word-aligned */ |
| 1442 | if (size == 8) |
| 1443 | { |
| 1444 | UML_TEST(block, IREG(0), IMM(3)); // test i0,3 |
| 1445 | UML_JMPc(block, IF_NZ, alignex = label++); // jmp alignex,nz |
| 1446 | } |
| 1008 | 1447 | |
| 1009 | | for( i=0; i < 64; i++ ) { |
| 1010 | | ppc.optable[i] = recompile_invalid; |
| 1448 | /* unaligned 2 and 4 byte accesses need to be broken up */ |
| 1449 | else |
| 1450 | { |
| 1451 | UML_TEST(block, IREG(0), IMM(size - 1)); // test i0,size-1 |
| 1452 | UML_JMPc(block, IF_NZ, unaligned = label++); // jmp unaligned,nz |
| 1453 | } |
| 1454 | } |
| 1011 | 1455 | } |
| 1012 | | for( i=0; i < 1024; i++ ) { |
| 1013 | | ppc.optable19[i] = recompile_invalid; |
| 1014 | | ppc.optable31[i] = recompile_invalid; |
| 1015 | | ppc.optable59[i] = recompile_invalid; |
| 1016 | | ppc.optable63[i] = recompile_invalid; |
| 1456 | |
| 1457 | /* general case: assume paging and perform a translation */ |
| 1458 | if ((ppc->cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) |
| 1459 | { |
| 1460 | UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12 |
| 1461 | UML_LOAD(block, IREG(3), ppc->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword |
| 1462 | UML_TEST(block, IREG(3), IMM(iswrite ? TLB_WRITE : TLB_READ)); // test i3,iswrite ? TLB_WRITE : TLB_READ |
| 1463 | UML_JMPc(block, IF_Z, tlbmiss = label++); // jmp tlbmiss,z |
| 1464 | UML_LABEL(block, tlbreturn = label++); // tlbreturn: |
| 1465 | UML_ROLINS(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // rolins i0,i3,0,0xfffff000 |
| 1017 | 1466 | } |
| 1467 | UML_XOR(block, IREG(0), IREG(0), IMM((mode & MODE_LITTLE_ENDIAN) ? (8 - size) : 0)); // xor i0,i0,8-size |
| 1018 | 1468 | |
| 1019 | | /* Fill the opcode tables */ |
| 1020 | | for( i=0; i < (sizeof(ppcdrc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) { |
| 1021 | | |
| 1022 | | switch(ppcdrc_opcode_common[i].code) |
| 1469 | for (ramnum = 0; ramnum < PPC_MAX_FASTRAM; ramnum++) |
| 1470 | if (!Machine->debug_mode && ppc->impstate->fastram[ramnum].base != NULL && (!iswrite || !ppc->impstate->fastram[ramnum].readonly)) |
| 1023 | 1471 | { |
| 1024 | | case 19: |
| 1025 | | ppc.optable19[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler; |
| 1026 | | break; |
| 1472 | void *fastbase = (UINT8 *)ppc->impstate->fastram[ramnum].base - ppc->impstate->fastram[ramnum].start; |
| 1473 | UINT32 skip = label++; |
| 1027 | 1474 | |
| 1028 | | case 31: |
| 1029 | | ppc.optable31[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler; |
| 1030 | | break; |
| 1475 | if (ppc->impstate->fastram[ramnum].end != 0xffffffff) |
| 1476 | { |
| 1477 | UML_CMP(block, IREG(0), IMM(ppc->impstate->fastram[ramnum].end)); // cmp i0,end |
| 1478 | UML_JMPc(block, IF_A, skip); // ja skip |
| 1479 | } |
| 1480 | if (ppc->impstate->fastram[ramnum].start != 0x00000000) |
| 1481 | { |
| 1482 | UML_CMP(block, IREG(0), IMM(ppc->impstate->fastram[ramnum].start)); // cmp i0,fastram_start |
| 1483 | UML_JMPc(block, IF_B, skip); // jb skip |
| 1484 | } |
| 1031 | 1485 | |
| 1032 | | case 59: |
| 1033 | | case 63: |
| 1034 | | break; |
| 1486 | if (!iswrite) |
| 1487 | { |
| 1488 | if (size == 1) |
| 1489 | { |
| 1490 | UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 0)); // xor i0,i0,fastxor >> 0 |
| 1491 | UML_LOAD(block, IREG(0), fastbase, IREG(0), BYTE); // load i0,fastbase,i0,byte |
| 1492 | } |
| 1493 | else if (size == 2) |
| 1494 | { |
| 1495 | UML_SHR(block, IREG(0), IREG(0), IMM(1)); // shr i0,i0,1 |
| 1496 | UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 1)); // xor i0,i0,fastxor >> 1 |
| 1497 | UML_LOAD(block, IREG(0), fastbase, IREG(0), WORD); // load i0,fastbase,i0,word |
| 1498 | } |
| 1499 | else if (size == 4) |
| 1500 | { |
| 1501 | UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2 |
| 1502 | UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 2)); // xor i0,i0,fastxor >> 2 |
| 1503 | UML_LOAD(block, IREG(0), fastbase, IREG(0), DWORD); // load i0,fastbase,i0,dword |
| 1504 | } |
| 1505 | else if (size == 8) |
| 1506 | { |
| 1507 | UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3 |
| 1508 | UML_DLOAD(block, IREG(0), fastbase, IREG(0), QWORD); // dload i0,fastbase,i0,qword |
| 1509 | } |
| 1510 | UML_RET(block); // ret |
| 1511 | } |
| 1512 | else |
| 1513 | { |
| 1514 | if (size == 1) |
| 1515 | { |
| 1516 | UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 0)); // xor i0,i0,fastxor >> 0 |
| 1517 | UML_STORE(block, fastbase, IREG(0), IREG(1), BYTE); // store fastbase,i0,i1,byte |
| 1518 | } |
| 1519 | else if (size == 2) |
| 1520 | { |
| 1521 | UML_SHR(block, IREG(0), IREG(0), IMM(1)); // shr i0,i0,1 |
| 1522 | UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 1)); // xor i0,i0,fastxor >> 1 |
| 1523 | UML_STORE(block, fastbase, IREG(0), IREG(1), WORD); // store fastbase,i0,i1,word |
| 1524 | } |
| 1525 | else if (size == 4) |
| 1526 | { |
| 1527 | UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2 |
| 1528 | UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 2)); // xor i0,i0,fastxor >> 2 |
| 1529 | if (ismasked) |
| 1530 | { |
| 1531 | UML_LOAD(block, IREG(3), fastbase, IREG(0), DWORD); // load i3,fastbase,i0,dword |
| 1532 | UML_AND(block, IREG(1), IREG(1), IREG(2)); // and i1,i1,i2 |
| 1533 | UML_XOR(block, IREG(2), IREG(2), IMM(0xffffffff)); // xor i2,i2,0xfffffffff |
| 1534 | UML_AND(block, IREG(3), IREG(3), IREG(2)); // and i3,i3,i2 |
| 1535 | UML_OR(block, IREG(1), IREG(1), IREG(3)); // or i1,i1,i3 |
| 1536 | } |
| 1537 | UML_STORE(block, fastbase, IREG(0), IREG(1), DWORD); // store fastbase,i0,i1,dword |
| 1538 | } |
| 1539 | else if (size == 8) |
| 1540 | { |
| 1541 | UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3 |
| 1542 | if (ismasked) |
| 1543 | { |
| 1544 | UML_DLOAD(block, IREG(3), fastbase, IREG(0), QWORD); // dload i3,fastbase,i0,qword |
| 1545 | UML_DAND(block, IREG(1), IREG(1), IREG(2)); // dand i1,i1,i2 |
| 1546 | UML_DXOR(block, IREG(2), IREG(2), IMM(U64(0xffffffffffffffff))); // dxor i2,i2,0xfffffffffffffffff |
| 1547 | UML_DAND(block, IREG(3), IREG(3), IREG(2)); // dand i3,i3,i2 |
| 1548 | UML_DOR(block, IREG(1), IREG(1), IREG(3)); // dor i1,i1,i3 |
| 1549 | } |
| 1550 | UML_DSTORE(block, fastbase, IREG(0), IREG(1), QWORD); // dstore fastbase,i0,i1,qword |
| 1551 | } |
| 1552 | UML_RET(block); // ret |
| 1553 | } |
| 1035 | 1554 | |
| 1036 | | default: |
| 1037 | | ppc.optable[ppcdrc_opcode_common[i].code] = ppcdrc_opcode_common[i].handler; |
| 1555 | UML_LABEL(block, skip); // skip: |
| 1038 | 1556 | } |
| 1039 | 1557 | |
| 1558 | switch (size) |
| 1559 | { |
| 1560 | case 1: |
| 1561 | if (iswrite) |
| 1562 | UML_WRITE(block, IREG(0), IREG(1), PROGRAM_BYTE); // write i0,i1,program_byte |
| 1563 | else |
| 1564 | UML_READ(block, IREG(0), IREG(0), PROGRAM_BYTE); // read i0,i0,program_byte |
| 1565 | break; |
| 1566 | |
| 1567 | case 2: |
| 1568 | if (iswrite) |
| 1569 | { |
| 1570 | if (!ismasked) |
| 1571 | UML_WRITE(block, IREG(0), IREG(1), PROGRAM_WORD); // write i0,i1,program_word |
| 1572 | else |
| 1573 | UML_WRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_WORD); // writem i0,i2,i1,program_word |
| 1574 | } |
| 1575 | else |
| 1576 | { |
| 1577 | if (!ismasked) |
| 1578 | UML_READ(block, IREG(0), IREG(0), PROGRAM_WORD); // read i0,i0,program_word |
| 1579 | else |
| 1580 | UML_READM(block, IREG(0), IREG(0), IREG(2), PROGRAM_WORD); // readm i0,i0,i2,program_word |
| 1581 | } |
| 1582 | break; |
| 1583 | |
| 1584 | case 4: |
| 1585 | if (iswrite) |
| 1586 | { |
| 1587 | if (!ismasked) |
| 1588 | UML_WRITE(block, IREG(0), IREG(1), PROGRAM_DWORD); // write i0,i1,program_dword |
| 1589 | else |
| 1590 | UML_WRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_DWORD); // writem i0,i2,i1,program_dword |
| 1591 | } |
| 1592 | else |
| 1593 | { |
| 1594 | if (!ismasked) |
| 1595 | UML_READ(block, IREG(0), IREG(0), PROGRAM_DWORD); // read i0,i0,program_dword |
| 1596 | else |
| 1597 | UML_READM(block, IREG(0), IREG(0), IREG(2), PROGRAM_DWORD); // readm i0,i0,i2,program_dword |
| 1598 | } |
| 1599 | break; |
| 1600 | |
| 1601 | case 8: |
| 1602 | if (iswrite) |
| 1603 | { |
| 1604 | if (!ismasked) |
| 1605 | UML_DWRITE(block, IREG(0), IREG(1), PROGRAM_QWORD); // dwrite i0,i1,program_qword |
| 1606 | else |
| 1607 | UML_DWRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_QWORD); // dwritem i0,i2,i1,program_qword |
| 1608 | } |
| 1609 | else |
| 1610 | { |
| 1611 | if (!ismasked) |
| 1612 | UML_DREAD(block, IREG(0), IREG(0), PROGRAM_QWORD); // dread i0,i0,program_qword |
| 1613 | else |
| 1614 | UML_DREADM(block, IREG(0), IREG(0), IREG(2), PROGRAM_QWORD); // dreadm i0,i0,i2,program_qword |
| 1615 | } |
| 1616 | break; |
| 1040 | 1617 | } |
| 1618 | UML_RET(block); // ret |
| 1041 | 1619 | |
| 1042 | | /* Calculate rotate mask table */ |
| 1043 | | for( i=0; i < 32; i++ ) { |
| 1044 | | for( j=0; j < 32; j++ ) { |
| 1045 | | UINT32 mask; |
| 1046 | | int mb = i; |
| 1047 | | int me = j; |
| 1048 | | mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); |
| 1049 | | if( mb > me ) |
| 1050 | | mask = ~mask; |
| 1620 | /* handle unaligned accesses */ |
| 1621 | if (unaligned != 0) |
| 1622 | { |
| 1623 | UML_LABEL(block, unaligned); // unaligned: |
| 1624 | if (size == 2) |
| 1625 | { |
| 1626 | if (iswrite) |
| 1627 | { |
| 1628 | UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 |
| 1629 | UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(1)); // mov [tempdata],i1 |
| 1630 | UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 |
| 1631 | UML_SHR(block, IREG(1), IREG(1), IMM(8)); // shr i1,i1,8 |
| 1632 | UML_MOV(block, IREG(2), IMM(0x00ff)); // mov i2,0x00ff |
| 1633 | UML_CALLH(block, masked); // callh masked |
| 1634 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 |
| 1635 | UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(8)); // shl i1,[tempdata],8 |
| 1636 | UML_MOV(block, IREG(2), IMM(0xff00)); // mov i2,0xff00 |
| 1637 | UML_CALLH(block, masked); // callh masked |
| 1638 | } |
| 1639 | else |
| 1640 | { |
| 1641 | UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 |
| 1642 | UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 |
| 1643 | UML_MOV(block, IREG(2), IMM(0x00ff)); // mov i2,0x00ff |
| 1644 | UML_CALLH(block, masked); // callh masked |
| 1645 | UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(8)); // shl [tempdata],i0,8 |
| 1646 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 |
| 1647 | UML_MOV(block, IREG(2), IMM(0xff00)); // mov i2,0xff00 |
| 1648 | UML_CALLH(block, masked); // callh masked |
| 1649 | UML_SHR(block, IREG(0), IREG(0), IMM(8)); // shr i0,i0,8 |
| 1650 | UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] |
| 1651 | } |
| 1652 | } |
| 1653 | else if (size == 4) |
| 1654 | { |
| 1655 | int offs2, offs3; |
| 1656 | if (iswrite) |
| 1657 | { |
| 1658 | UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 |
| 1659 | UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(1)); // mov [tempdata],i1 |
| 1660 | UML_TEST(block, IREG(0), IMM(2)); // test i0,i0,2 |
| 1661 | UML_JMPc(block, IF_NZ, offs2 = label++); // jnz offs2 |
| 1662 | UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 |
| 1663 | UML_SHR(block, IREG(1), IREG(1), IMM(8)); // shr i1,i1,8 |
| 1664 | UML_MOV(block, IREG(2), IMM(0x00ffffff)); // mov i2,0x00ffffff |
| 1665 | UML_CALLH(block, masked); // callh masked |
| 1666 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(3)); // add i0,[tempaddr],3 |
| 1667 | UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(24)); // shl i1,[tempdata],24 |
| 1668 | UML_MOV(block, IREG(2), IMM(0xff000000)); // mov i2,0xff000000 |
| 1669 | UML_CALLH(block, masked); // callh masked |
| 1670 | UML_RET(block); // ret |
| 1671 | UML_LABEL(block, offs2); // offs2: |
| 1672 | UML_TEST(block, IREG(0), IMM(1)); // test i0,i0,1 |
| 1673 | UML_JMPc(block, IF_NZ, offs3 = label++); // jnz offs3 |
| 1674 | UML_SUB(block, IREG(0), IREG(0), IMM(2)); // sub i0,i0,2 |
| 1675 | UML_SHR(block, IREG(1), IREG(1), IMM(16)); // shr i1,i1,16 |
| 1676 | UML_MOV(block, IREG(2), IMM(0x0000ffff)); // mov i2,0x0000ffff |
| 1677 | UML_CALLH(block, masked); // callh masked |
| 1678 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(2)); // add i0,[tempaddr],2 |
| 1679 | UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(16)); // shl i1,[tempdata],16 |
| 1680 | UML_MOV(block, IREG(2), IMM(0xffff0000)); // mov i2,0xffff0000 |
| 1681 | UML_CALLH(block, masked); // callh masked |
| 1682 | UML_RET(block); // ret |
| 1683 | UML_LABEL(block, offs3); // offs3: |
| 1684 | UML_SUB(block, IREG(0), IREG(0), IMM(3)); // sub i0,i0,3 |
| 1685 | UML_SHR(block, IREG(1), IREG(1), IMM(24)); // shr i1,i1,24 |
| 1686 | UML_MOV(block, IREG(2), IMM(0x000000ff)); // mov i2,0x000000ff |
| 1687 | UML_CALLH(block, masked); // callh masked |
| 1688 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 |
| 1689 | UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(8)); // shl i1,[tempdata],8 |
| 1690 | UML_MOV(block, IREG(2), IMM(0xffffff00)); // mov i2,0xffffff00 |
| 1691 | UML_CALLH(block, masked); // callh masked |
| 1692 | } |
| 1693 | else |
| 1694 | { |
| 1695 | UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 |
| 1696 | UML_TEST(block, IREG(0), IMM(2)); // test i0,i0,2 |
| 1697 | UML_JMPc(block, IF_NZ, offs2 = label++); // jnz offs2 |
| 1698 | UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 |
| 1699 | UML_MOV(block, IREG(2), IMM(0x00ffffff)); // mov i2,0x00ffffff |
| 1700 | UML_CALLH(block, masked); // callh masked |
| 1701 | UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(8)); // shl [tempdata],i0,8 |
| 1702 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(3)); // add i0,[tempaddr],3 |
| 1703 | UML_MOV(block, IREG(2), IMM(0xff000000)); // mov i2,0xff000000 |
| 1704 | UML_CALLH(block, masked); // callh masked |
| 1705 | UML_SHR(block, IREG(0), IREG(0), IMM(24)); // shr i0,i0,24 |
| 1706 | UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] |
| 1707 | UML_RET(block); // ret |
| 1708 | UML_LABEL(block, offs2); // offs2: |
| 1709 | UML_TEST(block, IREG(0), IMM(1)); // test i0,i0,1 |
| 1710 | UML_JMPc(block, IF_NZ, offs3 = label++); // jnz offs3 |
| 1711 | UML_SUB(block, IREG(0), IREG(0), IMM(2)); // sub i0,i0,2 |
| 1712 | UML_MOV(block, IREG(2), IMM(0x0000ffff)); // mov i2,0x0000ffff |
| 1713 | UML_CALLH(block, masked); // callh masked |
| 1714 | UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(16)); // shl [tempdata],i0,16 |
| 1715 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(2)); // add i0,[tempaddr],2 |
| 1716 | UML_MOV(block, IREG(2), IMM(0xffff0000)); // mov i2,0xffff0000 |
| 1717 | UML_CALLH(block, masked); // callh masked |
| 1718 | UML_SHR(block, IREG(0), IREG(0), IMM(16)); // shr i0,i0,16 |
| 1719 | UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] |
| 1720 | UML_RET(block); // ret |
| 1721 | UML_LABEL(block, offs3); // offs3: |
| 1722 | UML_SUB(block, IREG(0), IREG(0), IMM(3)); // sub i0,i0,3 |
| 1723 | UML_MOV(block, IREG(2), IMM(0x000000ff)); // mov i2,0x000000ff |
| 1724 | UML_CALLH(block, masked); // callh masked |
| 1725 | UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(24)); // shl [tempdata],i0,24 |
| 1726 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 |
| 1727 | UML_MOV(block, IREG(2), IMM(0xffffff00)); // mov i2,0xffffff00 |
| 1728 | UML_CALLH(block, masked); // callh masked |
| 1729 | UML_SHR(block, IREG(0), IREG(0), IMM(8)); // shr i0,i0,8 |
| 1730 | UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] |
| 1731 | } |
| 1732 | } |
| 1733 | UML_RET(block); // ret |
| 1734 | } |
| 1051 | 1735 | |
| 1052 | | ppc_rotate_mask[i][j] = mask; |
| 1736 | /* handle an alignment exception */ |
| 1737 | if (alignex != 0) |
| 1738 | { |
| 1739 | UML_LABEL(block, alignex); // alignex: |
| 1740 | UML_RECOVER(block, SPR32(SPROEA_DSISR), MAPVAR_DSISR); // recover [dsisr],DSISR |
| 1741 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_ALIGN], IREG(0)); // exh align,i0 |
| 1742 | } |
| 1743 | |
| 1744 | /* handle a TLB miss */ |
| 1745 | if (tlbmiss != 0) |
| 1746 | { |
| 1747 | int dsi; |
| 1748 | |
| 1749 | UML_LABEL(block, tlbmiss); // tlbmiss: |
| 1750 | UML_MOV(block, MEM(&ppc->param0), IREG(0)); // mov [param0],i0 |
| 1751 | UML_MOV(block, MEM(&ppc->param1), IMM(iswrite ? TRANSLATE_WRITE : TRANSLATE_READ)); // mov [param1],TRANSLATE_READ/WRITE |
| 1752 | UML_CALLC(block, ppccom_tlb_fill, ppc); // callc tlbfill,ppc |
| 1753 | UML_CMP(block, MEM(&ppc->param0), IMM(1)); // cmp [param0],1 |
| 1754 | UML_JMPc(block, IF_A, dsi = label++); // jmp dsi,A |
| 1755 | UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12 |
| 1756 | UML_LOAD(block, IREG(3), ppc->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword |
| 1757 | UML_JMP(block, tlbreturn); // jmp tlbreturn |
| 1758 | UML_LABEL(block, dsi); // dsi: |
| 1759 | if (!(ppc->cap & PPCCAP_603_MMU)) |
| 1760 | { |
| 1761 | UML_MOV(block, SPR32(SPROEA_DSISR), MEM(&ppc->param0)); // mov [dsisr],[param0] |
| 1762 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_DSI], IREG(0)); // exh dsi,i0 |
| 1053 | 1763 | } |
| 1764 | else |
| 1765 | { |
| 1766 | UML_MOV(block, SPR32(SPR603_DMISS), IREG(0)); // mov [dmiss],i0 |
| 1767 | UML_MOV(block, SPR32(SPR603_DCMP), MEM(&ppc->mmu603_cmp)); // mov [dcmp],[mmu603_cmp] |
| 1768 | UML_MOV(block, SPR32(SPR603_HASH1), MEM(&ppc->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] |
| 1769 | UML_MOV(block, SPR32(SPR603_HASH2), MEM(&ppc->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] |
| 1770 | if (iswrite) |
| 1771 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_DTLBMISSS], IREG(0)); // exh dtlbmisss,i0 |
| 1772 | else |
| 1773 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_DTLBMISSL], IREG(0)); // exh dtlbmissl,i0 |
| 1774 | } |
| 1054 | 1775 | } |
| 1776 | |
| 1777 | drcuml_block_end(block); |
| 1055 | 1778 | } |
| 1056 | 1779 | |
| 1057 | | #if (HAS_PPC403) |
| 1058 | | static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1780 | |
| 1781 | /*------------------------------------------------- |
| 1782 | static_generate_swap_tgpr - generate a |
| 1783 | subroutine to swap GPR0-3 with TGPR0-3 |
| 1784 | -------------------------------------------------*/ |
| 1785 | |
| 1786 | static void static_generate_swap_tgpr(drcuml_state *drcuml) |
| 1059 | 1787 | { |
| 1060 | | const ppc_config *config = _config; |
| 1788 | drcuml_block *block; |
| 1789 | jmp_buf errorbuf; |
| 1790 | int regnum; |
| 1061 | 1791 | |
| 1062 | | ppc_init(); |
| 1063 | | ppcdrc_init(); |
| 1792 | /* if we get an error back, we're screwed */ |
| 1793 | if (setjmp(errorbuf) != 0) |
| 1794 | fatalerror("Unrecoverable error in static_generate_swap_tgpr"); |
| 1064 | 1795 | |
| 1065 | | /* PPC403 specific opcodes */ |
| 1066 | | ppc.optable31[454] = recompile_dccci; |
| 1067 | | ppc.optable31[486] = recompile_dcread; |
| 1068 | | ppc.optable31[262] = recompile_icbt; |
| 1069 | | ppc.optable31[966] = recompile_iccci; |
| 1070 | | ppc.optable31[998] = recompile_icread; |
| 1071 | | ppc.optable31[323] = recompile_mfdcr; |
| 1072 | | ppc.optable31[451] = recompile_mtdcr; |
| 1073 | | ppc.optable31[131] = recompile_wrtee; |
| 1074 | | ppc.optable31[163] = recompile_wrteei; |
| 1075 | | ppc.optable19[51] = recompile_rfci; |
| 1796 | /* begin generating */ |
| 1797 | block = drcuml_block_begin(drcuml, 30, &errorbuf); |
| 1076 | 1798 | |
| 1077 | | ppc.spu.rx_timer = timer_alloc(ppc403_spu_rx_callback, NULL); |
| 1078 | | ppc.spu.tx_timer = timer_alloc(ppc403_spu_tx_callback, NULL); |
| 1799 | /* generate a hash jump via the current mode and PC */ |
| 1800 | alloc_handle(drcuml, &ppc->impstate->swap_tgpr, "swap_tgpr"); |
| 1801 | UML_HANDLE(block, ppc->impstate->swap_tgpr); // handle swap_tgpr |
| 1802 | for (regnum = 0; regnum < 4; regnum++) |
| 1803 | { |
| 1804 | UML_MOV(block, IREG(1), R32(regnum)); // mov i1,r[regnum] |
| 1805 | UML_MOV(block, R32(regnum), MEM(&ppc->mmu603_r[regnum])); // mov r[regnum],mmu603_r[regnum] |
| 1806 | UML_MOV(block, MEM(&ppc->mmu603_r[regnum]), IREG(1)); // mov mmu603_r[regnum],i1 |
| 1807 | } |
| 1808 | UML_RET(block); // ret |
| 1079 | 1809 | |
| 1080 | | ppc.is603 = 0; |
| 1081 | | ppc.is602 = 0; |
| 1810 | drcuml_block_end(block); |
| 1811 | } |
| 1082 | 1812 | |
| 1083 | | ppc.read8 = ppc403_read8; |
| 1084 | | ppc.read16 = ppc403_read16; |
| 1085 | | ppc.read32 = ppc403_read32; |
| 1086 | | ppc.write8 = ppc403_write8; |
| 1087 | | ppc.write16 = ppc403_write16; |
| 1088 | | ppc.write32 = ppc403_write32; |
| 1089 | | ppc.read16_unaligned = ppc403_read16_unaligned; |
| 1090 | | ppc.read32_unaligned = ppc403_read32_unaligned; |
| 1091 | | ppc.write16_unaligned = ppc403_write16_unaligned; |
| 1092 | | ppc.write32_unaligned = ppc403_write32_unaligned; |
| 1093 | 1813 | |
| 1094 | | ppc.irq_callback = irqcallback; |
| 1095 | 1814 | |
| 1096 | | ppc.pvr = config->pvr; |
| 1097 | | } |
| 1815 | /*************************************************************************** |
| 1816 | CODE GENERATION |
| 1817 | ***************************************************************************/ |
| 1098 | 1818 | |
| 1099 | | static void ppcdrc403_exit(void) |
| 1819 | /*------------------------------------------------- |
| 1820 | generate_update_mode - update the mode based |
| 1821 | on the MSR |
| 1822 | -------------------------------------------------*/ |
| 1823 | |
| 1824 | static void generate_update_mode(drcuml_block *block) |
| 1100 | 1825 | { |
| 1101 | | #if LOG_CODE |
| 1102 | | //if (symfile) fclose(symfile); |
| 1103 | | #endif |
| 1104 | | ppcdrc_exit(); |
| 1826 | UML_AND(block, IREG(0), MSR32, IMM(MSR_LE)); // and i0,msr,MSR_LE |
| 1827 | UML_AND(block, IREG(1), MSR32, IMM(MSROEA_DR)); // and i1,msr,MSR_DR |
| 1828 | UML_SHR(block, IREG(1), IREG(1), IMM(3)); // shr i1,i1,3 |
| 1829 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 |
| 1830 | UML_AND(block, IREG(1), MSR32, IMM(MSR_PR)); // and i1,msr,MSR_PR |
| 1831 | UML_SHR(block, IREG(1), IREG(1), IMM(12)); // shr i1,i1,12 |
| 1832 | UML_OR(block, MEM(&ppc->impstate->mode), IREG(0), IREG(1)); // or [mode],i0,i1 |
| 1105 | 1833 | } |
| 1106 | 1834 | |
| 1107 | | static void ppcdrc403_reset(void) |
| 1835 | |
| 1836 | /*------------------------------------------------- |
| 1837 | generate_update_cycles - generate code to |
| 1838 | subtract cycles from the icount and generate |
| 1839 | an exception if out |
| 1840 | -------------------------------------------------*/ |
| 1841 | |
| 1842 | static void generate_update_cycles(drcuml_block *block, compiler_state *compiler, drcuml_ptype ptype, UINT64 pvalue, int allow_exception) |
| 1108 | 1843 | { |
| 1109 | | ppc.pc = ppc.npc = 0xfffffffc; |
| 1844 | /* check full interrupts if pending */ |
| 1845 | if (compiler->checkints) |
| 1846 | { |
| 1847 | drcuml_codelabel skip; |
| 1110 | 1848 | |
| 1111 | | ppc_set_msr(0); |
| 1112 | | change_pc(ppc.pc); |
| 1849 | compiler->checkints = FALSE; |
| 1850 | UML_TEST(block, MEM(&ppc->irq_pending), IMM(~0)); // test [irq_pending],0 |
| 1851 | UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z |
| 1852 | UML_TEST(block, MSR32, IMM(MSR_EE)); // test [msr],MSR_EE |
| 1853 | UML_JMPc(block, IF_Z, skip); // jmp skip,Z |
| 1854 | UML_MOV(block, IREG(0), PARAM(ptype, pvalue)); // mov i0,nextpc |
| 1855 | UML_MOV(block, IREG(1), IMM(compiler->cycles)); // mov i1,cycles |
| 1856 | UML_CALLH(block, ppc->impstate->exception_norecover[EXCEPTION_EI]); // callh interrupt_norecover |
| 1857 | UML_LABEL(block, skip); // skip: |
| 1858 | } |
| 1113 | 1859 | |
| 1114 | | /* reset the DRC */ |
| 1115 | | drc_cache_reset(ppc.drc); |
| 1860 | /* account for cycles */ |
| 1861 | if (compiler->cycles > 0) |
| 1862 | { |
| 1863 | UML_SUBf(block, MEM(&ppc->icount), MEM(&ppc->icount), MAPVAR_CYCLES, allow_exception ? FLAGS_S : 0); |
| 1864 | // sub icount,icount,cycles,S |
| 1865 | UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 |
| 1866 | if (allow_exception) |
| 1867 | UML_EXHc(block, IF_S, ppc->impstate->out_of_cycles, PARAM(ptype, pvalue)); // exh out_of_cycles,nextpc |
| 1868 | } |
| 1869 | compiler->cycles = 0; |
| 1116 | 1870 | } |
| 1117 | 1871 | |
| 1118 | | static int ppcdrc403_execute(int cycles) |
| 1872 | |
| 1873 | /*------------------------------------------------- |
| 1874 | generate_checksum_block - generate code to |
| 1875 | validate a sequence of opcodes |
| 1876 | -------------------------------------------------*/ |
| 1877 | |
| 1878 | static void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) |
| 1119 | 1879 | { |
| 1120 | | /* count cycles and interrupt cycles */ |
| 1121 | | ppc_icount = cycles; |
| 1122 | | ppc_tb_base_icount = cycles; |
| 1880 | const opcode_desc *curdesc; |
| 1881 | if (LOG_UML) |
| 1882 | UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment |
| 1123 | 1883 | |
| 1124 | | ppc_fit_trigger_cycle = 0x7fffffff; |
| 1884 | /* loose verify or single instruction: just compare and fail */ |
| 1885 | if (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next == NULL) |
| 1886 | { |
| 1887 | if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1888 | { |
| 1889 | UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,dword |
| 1890 | UML_CMP(block, IREG(0), IMM(*seqhead->opptr.l)); // cmp i0,*opptr |
| 1891 | UML_EXHc(block, IF_NE, ppc->impstate->nocode, IMM(seqhead->pc)); // exne nocode,seqhead->pc |
| 1892 | } |
| 1893 | } |
| 1125 | 1894 | |
| 1126 | | if (ppc.fit_int_enable) |
| 1895 | /* full verification; sum up everything */ |
| 1896 | else |
| 1127 | 1897 | { |
| 1128 | | UINT32 tb = (UINT32)ppc.tb; |
| 1129 | | UINT32 fit_cycles = 0; |
| 1898 | #if 0 |
| 1899 | for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) |
| 1900 | if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1901 | { |
| 1902 | UML_LOAD(block, IREG(0), curdesc->opptr.l, IMM(0), DWORD); // load i0,*opptr,dword |
| 1903 | UML_CMP(block, IREG(0), IMM(*curdesc->opptr.l)); // cmp i0,*opptr |
| 1904 | UML_EXHc(block, IF_NE, ppc->impstate->nocode, IMM(seqhead->pc)); // exne nocode,seqhead->pc |
| 1905 | } |
| 1906 | #else |
| 1907 | UINT32 sum = 0; |
| 1908 | UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,dword |
| 1909 | sum += *seqhead->opptr.l; |
| 1910 | for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) |
| 1911 | if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1912 | { |
| 1913 | UML_LOAD(block, IREG(1), curdesc->opptr.l, IMM(0), DWORD); // load i1,*opptr,dword |
| 1914 | UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1 |
| 1915 | sum += *curdesc->opptr.l; |
| 1916 | } |
| 1917 | UML_CMP(block, IREG(0), IMM(sum)); // cmp i0,sum |
| 1918 | UML_EXHc(block, IF_NE, ppc->impstate->nocode, IMM(seqhead->pc)); // exne nocode,seqhead->pc |
| 1919 | #endif |
| 1920 | } |
| 1921 | } |
| 1130 | 1922 | |
| 1131 | | if (ppc.tb & ppc.fit_bit) |
| 1923 | |
| 1924 | /*------------------------------------------------- |
| 1925 | generate_sequence_instruction - generate code |
| 1926 | for a single instruction in a sequence |
| 1927 | -------------------------------------------------*/ |
| 1928 | |
| 1929 | static void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 1930 | { |
| 1931 | int hotnum; |
| 1932 | |
| 1933 | /* add an entry for the log */ |
| 1934 | if (LOG_UML && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1935 | log_add_disasm_comment(block, desc->pc, *desc->opptr.l); |
| 1936 | |
| 1937 | /* set the PC map variable */ |
| 1938 | UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc |
| 1939 | |
| 1940 | /* accumulate total cycles */ |
| 1941 | compiler->cycles += desc->cycles; |
| 1942 | |
| 1943 | /* is this a hotspot? */ |
| 1944 | for (hotnum = 0; hotnum < PPC_MAX_HOTSPOTS; hotnum++) |
| 1945 | if (ppc->impstate->hotspot[hotnum].pc != 0 && desc->pc == ppc->impstate->hotspot[hotnum].pc && *desc->opptr.l == ppc->impstate->hotspot[hotnum].opcode) |
| 1132 | 1946 | { |
| 1133 | | fit_cycles += ppc.fit_bit; |
| 1134 | | tb += fit_cycles; |
| 1947 | compiler->cycles += ppc->impstate->hotspot[hotnum].cycles; |
| 1948 | break; |
| 1135 | 1949 | } |
| 1136 | 1950 | |
| 1137 | | fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1)); |
| 1951 | /* update the icount map variable */ |
| 1952 | UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles |
| 1138 | 1953 | |
| 1139 | | ppc_fit_trigger_cycle = ppc_icount - fit_cycles; |
| 1954 | /* if we want a probe, add it here */ |
| 1955 | if (desc->pc == PROBE_ADDRESS) |
| 1956 | UML_CALLC(block, cfunc_printf_probe, desc->pc); // callc cfunc_printf_probe,desc->pc |
| 1957 | |
| 1958 | /* if we are debugging, call the debugger */ |
| 1959 | if (Machine->debug_mode) |
| 1960 | { |
| 1961 | UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc |
| 1962 | save_fast_iregs(block); // <save fastregs> |
| 1963 | UML_DEBUG(block, IMM(desc->pc)); // debug desc->pc |
| 1140 | 1964 | } |
| 1141 | 1965 | |
| 1142 | | drc_execute(ppc.drc); |
| 1966 | /* if we hit an unmapped address, fatal error */ |
| 1967 | if (desc->flags & OPFLAG_COMPILER_UNMAPPED) |
| 1968 | { |
| 1969 | UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc |
| 1970 | save_fast_iregs(block); // <save fastregs> |
| 1971 | UML_EXIT(block, IMM(EXECUTE_UNMAPPED_CODE)); // exit EXECUTE_UNMAPPED_CODE |
| 1972 | } |
| 1143 | 1973 | |
| 1144 | | // update timebase |
| 1145 | | ppc.tb += (ppc_tb_base_icount - ppc_icount); |
| 1974 | /* if we hit a compiler page fault, it's just like a TLB mismatch */ |
| 1975 | if (desc->flags & OPFLAG_COMPILER_PAGE_FAULT) |
| 1976 | { |
| 1977 | if (PRINTF_MMU) |
| 1978 | { |
| 1979 | UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc |
| 1980 | UML_CALLC(block, cfunc_printf_debug, "Compiler page fault @ %08X\n"); // callc printf_debug |
| 1981 | } |
| 1982 | UML_EXH(block, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0 |
| 1983 | } |
| 1146 | 1984 | |
| 1147 | | return cycles - ppc_icount; |
| 1148 | | } |
| 1149 | | |
| 1150 | | static void ppcdrc403_set_irq_line(int irqline, int state) |
| 1151 | | { |
| 1152 | | if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4) |
| 1985 | /* validate our TLB entry at this PC; if we fail, we need to handle it */ |
| 1986 | if ((desc->flags & OPFLAG_VALIDATE_TLB) && (ppc->impstate->mode & MODE_DATA_TRANSLATION)) |
| 1153 | 1987 | { |
| 1154 | | UINT32 mask = (1 << (4 - irqline)); |
| 1155 | | if( state == ASSERT_LINE) { |
| 1156 | | if (EXIER & mask) |
| 1988 | /* if we currently have a valid TLB read entry, we just verify */ |
| 1989 | if (ppc->tlb_table[desc->pc >> 12] != 0) |
| 1990 | { |
| 1991 | if (PRINTF_MMU) |
| 1157 | 1992 | { |
| 1158 | | ppc.exisr |= mask; |
| 1159 | | ppc.exception_pending |= 0x1; |
| 1160 | | |
| 1161 | | if (ppc.irq_callback) |
| 1162 | | { |
| 1163 | | ppc.irq_callback(irqline); |
| 1164 | | } |
| 1993 | UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc |
| 1994 | UML_CALLC(block, cfunc_printf_debug, "Checking TLB at @ %08X\n"); // callc printf_debug |
| 1165 | 1995 | } |
| 1996 | UML_LOAD(block, IREG(0), &ppc->tlb_table[desc->pc >> 12], IMM(0), DWORD); // load i0,tlb_table[desc->pc >> 12],dword |
| 1997 | UML_CMP(block, IREG(0), IMM(ppc->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry |
| 1998 | UML_EXHc(block, IF_NE, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE |
| 1166 | 1999 | } |
| 1167 | | // clear line is used to clear the interrupt when the interrupts are level-sensitive |
| 1168 | | else if (state == CLEAR_LINE) |
| 2000 | |
| 2001 | /* otherwise, we generate an unconditional exception */ |
| 2002 | else |
| 1169 | 2003 | { |
| 1170 | | ppc.exisr &= ~mask; |
| 1171 | | } |
| 1172 | | } |
| 1173 | | else if (irqline == PPC403_SPU_RX) |
| 1174 | | { |
| 1175 | | UINT32 mask = 0x08000000; |
| 1176 | | if (state) { |
| 1177 | | if( EXIER & mask ) { |
| 1178 | | ppc.exisr |= mask; |
| 1179 | | ppc.exception_pending |= 0x1; |
| 2004 | if (PRINTF_MMU) |
| 2005 | { |
| 2006 | UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc |
| 2007 | UML_CALLC(block, cfunc_printf_debug, "No valid TLB @ %08X\n"); // callc printf_debug |
| 1180 | 2008 | } |
| 2009 | UML_EXH(block, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0 |
| 1181 | 2010 | } |
| 1182 | 2011 | } |
| 1183 | | else if (irqline == PPC403_SPU_TX) |
| 2012 | |
| 2013 | /* if this is an invalid opcode, generate the exception now */ |
| 2014 | if (desc->flags & OPFLAG_INVALID_OPCODE) |
| 2015 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x80000)); // exh exception_program,0x80000 |
| 2016 | |
| 2017 | /* if this is a privileged opcode in user mode, generate the exception */ |
| 2018 | else if ((desc->flags & OPFLAG_PRIVILEGED) && (ppc->impstate->mode & MODE_USER)) |
| 2019 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x40000)); // exh exception_program,0x40000 |
| 2020 | |
| 2021 | /* otherwise, unless this is a virtual no-op, it's a regular instruction */ |
| 2022 | else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1184 | 2023 | { |
| 1185 | | UINT32 mask = 0x04000000; |
| 1186 | | if (state) { |
| 1187 | | if( EXIER & mask ) { |
| 1188 | | ppc.exisr |= mask; |
| 1189 | | ppc.exception_pending |= 0x1; |
| 1190 | | } |
| 2024 | /* compile the instruction */ |
| 2025 | if (!generate_opcode(block, compiler, desc)) |
| 2026 | { |
| 2027 | UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc |
| 2028 | UML_CALLC(block, cfunc_unimplemented, (void *)(FPTR)*desc->opptr.l); // callc cfunc_unimplemented |
| 1191 | 2029 | } |
| 1192 | 2030 | } |
| 1193 | | else |
| 1194 | | { |
| 1195 | | fatalerror("PPC: Unknown IRQ line %d", irqline); |
| 1196 | | } |
| 1197 | 2031 | } |
| 1198 | | #endif |
| 1199 | 2032 | |
| 1200 | | #if (HAS_PPC603) |
| 1201 | | static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1202 | | { |
| 1203 | | int pll_config = 0; |
| 1204 | | float multiplier; |
| 1205 | | const ppc_config *config = _config; |
| 1206 | | int i; |
| 1207 | 2033 | |
| 1208 | | ppc_init(); |
| 1209 | | ppcdrc_init(); |
| 2034 | /*------------------------------------------------------------------ |
| 2035 | generate_compute_flags - compute CR0 and/or XER flags |
| 2036 | ------------------------------------------------------------------*/ |
| 1210 | 2037 | |
| 1211 | | ppc.optable[48] = recompile_lfs; |
| 1212 | | ppc.optable[49] = recompile_lfsu; |
| 1213 | | ppc.optable[50] = recompile_lfd; |
| 1214 | | ppc.optable[51] = recompile_lfdu; |
| 1215 | | ppc.optable[52] = recompile_stfs; |
| 1216 | | ppc.optable[53] = recompile_stfsu; |
| 1217 | | ppc.optable[54] = recompile_stfd; |
| 1218 | | ppc.optable[55] = recompile_stfdu; |
| 1219 | | ppc.optable31[631] = recompile_lfdux; |
| 1220 | | ppc.optable31[599] = recompile_lfdx; |
| 1221 | | ppc.optable31[567] = recompile_lfsux; |
| 1222 | | ppc.optable31[535] = recompile_lfsx; |
| 1223 | | ppc.optable31[595] = recompile_mfsr; |
| 1224 | | ppc.optable31[659] = recompile_mfsrin; |
| 1225 | | ppc.optable31[371] = recompile_mftb; |
| 1226 | | ppc.optable31[210] = recompile_mtsr; |
| 1227 | | ppc.optable31[242] = recompile_mtsrin; |
| 1228 | | ppc.optable31[758] = recompile_dcba; |
| 1229 | | ppc.optable31[759] = recompile_stfdux; |
| 1230 | | ppc.optable31[727] = recompile_stfdx; |
| 1231 | | ppc.optable31[983] = recompile_stfiwx; |
| 1232 | | ppc.optable31[695] = recompile_stfsux; |
| 1233 | | ppc.optable31[663] = recompile_stfsx; |
| 1234 | | ppc.optable31[370] = recompile_tlbia; |
| 1235 | | ppc.optable31[306] = recompile_tlbie; |
| 1236 | | ppc.optable31[566] = recompile_tlbsync; |
| 1237 | | ppc.optable31[310] = recompile_eciwx; |
| 1238 | | ppc.optable31[438] = recompile_ecowx; |
| 2038 | static void generate_compute_flags(drcuml_block *block, int updatecr, UINT32 xermask, int invertcarry) |
| 2039 | { |
| 2040 | int xerflags = ((xermask & XER_OV) ? DRCUML_FLAG_V : 0) | ((xermask & XER_CA) ? DRCUML_FLAG_C : 0); |
| 2041 | UINT32 xermask_so = xermask | ((xermask & XER_OV) ? XER_SO : 0); |
| 1239 | 2042 | |
| 1240 | | ppc.optable63[264] = recompile_fabsx; |
| 1241 | | ppc.optable63[21] = recompile_faddx; |
| 1242 | | ppc.optable63[32] = recompile_fcmpo; |
| 1243 | | ppc.optable63[0] = recompile_fcmpu; |
| 1244 | | ppc.optable63[14] = recompile_fctiwx; |
| 1245 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1246 | | ppc.optable63[18] = recompile_fdivx; |
| 1247 | | ppc.optable63[72] = recompile_fmrx; |
| 1248 | | ppc.optable63[136] = recompile_fnabsx; |
| 1249 | | ppc.optable63[40] = recompile_fnegx; |
| 1250 | | ppc.optable63[12] = recompile_frspx; |
| 1251 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1252 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1253 | | ppc.optable63[20] = recompile_fsubx; |
| 1254 | | ppc.optable63[583] = recompile_mffsx; |
| 1255 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1256 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1257 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1258 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1259 | | ppc.optable63[64] = recompile_mcrfs; |
| 2043 | /* easy case: nothing to do */ |
| 2044 | if (!updatecr && xermask == 0) |
| 2045 | return; |
| 1260 | 2046 | |
| 1261 | | ppc.optable59[21] = recompile_faddsx; |
| 1262 | | ppc.optable59[18] = recompile_fdivsx; |
| 1263 | | ppc.optable59[24] = recompile_fresx; |
| 1264 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1265 | | ppc.optable59[20] = recompile_fsubsx; |
| 1266 | | |
| 1267 | | for(i = 0; i < 32; i++) |
| 2047 | /* semi-easy case: crfield only */ |
| 2048 | if (xermask == 0) |
| 1268 | 2049 | { |
| 1269 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1270 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1271 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1272 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1273 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1274 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 1275 | | |
| 1276 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1277 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1278 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1279 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1280 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 2050 | UML_MOV(block, IREG(0), CR32); // mov i0,cr32 |
| 2051 | UML_GETFLGS(block, IREG(1), DRCUML_FLAG_S | DRCUML_FLAG_Z); // getflgs i1,sz |
| 2052 | UML_LOAD(block, IREG(1), ppc->impstate->sz_cr_table, IREG(1), DWORD); // load i1,sz_cr_table,i1,dword |
| 2053 | UML_ROLINS(block, IREG(0), IREG(1), IMM(0), IMM(CRMASK(0))); // rolins i0,i1,0,crmask(field) |
| 2054 | UML_AND(block, IREG(1), SPR32(SPR_XER), IMM(XER_SO)); // and i1,[xer],XER_SO |
| 2055 | UML_SHR(block, IREG(1), IREG(1), IMM(3)); // shr i1,i1,3 |
| 2056 | UML_OR(block, CR32, IREG(0), IREG(1)); // or [cr],i0,i1 |
| 2057 | return; |
| 1281 | 2058 | } |
| 1282 | 2059 | |
| 1283 | | #if (HAS_PPC602 || HAS_MPC8240) |
| 1284 | | ppc.optable31[978] = recompile_tlbld; |
| 1285 | | #endif /* (HAS_PPC602 || HAS_MPC8240) */ |
| 1286 | | |
| 1287 | | for(i = 0; i < 256; i++) |
| 2060 | /* semi-easy case: xer only */ |
| 2061 | if (!updatecr) |
| 1288 | 2062 | { |
| 1289 | | ppc_field_xlat[i] = |
| 1290 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1291 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1292 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1293 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1294 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1295 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1296 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1297 | | ((i & 0x01) ? 0x0000000F : 0); |
| 2063 | if (xermask & XER_OV) |
| 2064 | { |
| 2065 | UML_MOV(block, IREG(0), SPR32(SPR_XER)); // mov i0,[xer] |
| 2066 | UML_GETFLGS(block, IREG(1), xerflags); // getflgs i1,xerflags |
| 2067 | if (invertcarry && (xermask & XER_CA)) |
| 2068 | UML_XOR(block, IREG(1), IREG(1), IMM(DRCUML_FLAG_C)); // xor i1,i1,FLAG_C |
| 2069 | UML_ROLINS(block, IREG(0), IREG(1), IMM(29), IMM(xermask)); // rolins i0,i1,29,crmask(xermask) |
| 2070 | UML_AND(block, IREG(1), SPR32(SPR_XER), IMM(XER_OV)); // and i1,[xer],XER_OV |
| 2071 | UML_SHL(block, IREG(1), IREG(1), IMM(1)); // shl i1,i1,1 |
| 2072 | UML_OR(block, SPR32(SPR_XER), IREG(0), IREG(1)); // or [xer],i0,i1 |
| 2073 | } |
| 2074 | else |
| 2075 | { |
| 2076 | UML_SETc(block, invertcarry ? IF_NC : IF_C, IREG(0)); // setc i0,nc/c |
| 2077 | UML_ROLINS(block, SPR32(SPR_XER), IREG(0), IMM(29), IMM(XER_CA)); // rolins [xer],i0,29,XER_CA |
| 2078 | } |
| 2079 | return; |
| 1298 | 2080 | } |
| 1299 | 2081 | |
| 1300 | | ppc.is603 = 1; |
| 2082 | /* tricky case: both */ |
| 2083 | UML_GETFLGS(block, IREG(0), DRCUML_FLAG_S | DRCUML_FLAG_Z | xerflags); // getflgs i0,sz|xerflags |
| 2084 | if (invertcarry) |
| 2085 | UML_XOR(block, IREG(2), IREG(2), IMM(DRCUML_FLAG_C)); // xor i2,i2,FLAG_C |
| 2086 | UML_LOAD(block, IREG(0), ppc->impstate->sz_cr_table, IREG(0), DWORD); // load i0,sz_cr_table,i0,dword |
| 2087 | UML_AND(block, IREG(1), SPR32(SPR_XER), IMM(~xermask)); // and i1,[xer],~xermask |
| 2088 | UML_SHL(block, IREG(2), IREG(0), IMM(4)); // shl i2,i0,4 |
| 2089 | if (xermask_so != (XER_CA | XER_OV | XER_SO)) |
| 2090 | UML_AND(block, IREG(2), IREG(2), IMM(xermask_so)); // and i2,i2,xermask |
| 2091 | UML_OR(block, IREG(1), IREG(1), IREG(2)); // or i1,i1,i2 |
| 2092 | UML_MOV(block, SPR32(SPR_XER), IREG(1)); // mov [xer],i1 |
| 2093 | UML_SHR(block, IREG(1), IREG(1), IMM(3)); // shr i1,i1,3 |
| 2094 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 |
| 2095 | UML_AND(block, IREG(1), CR32, IMM(~CRMASK(0))); // and i1,[cr],~crmask(0) |
| 2096 | UML_AND(block, IREG(0), IREG(0), IMM(CRMASK(0))); // and i0,i0,crmask(0) |
| 2097 | UML_OR(block, CR32, IREG(0), IREG(1)); // or cr32,i0,i1 |
| 2098 | } |
| 1301 | 2099 | |
| 1302 | | ppc.read8 = program_read_byte_64be; |
| 1303 | | ppc.read16 = program_read_word_64be; |
| 1304 | | ppc.read32 = program_read_dword_64be; |
| 1305 | | ppc.read64 = program_read_qword_64be; |
| 1306 | | ppc.write8 = program_write_byte_64be; |
| 1307 | | ppc.write16 = program_write_word_64be; |
| 1308 | | ppc.write32 = program_write_dword_64be; |
| 1309 | | ppc.write64 = program_write_qword_64be; |
| 1310 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1311 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1312 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1313 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1314 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1315 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1316 | 2100 | |
| 1317 | | ppc.irq_callback = irqcallback; |
| 2101 | /*------------------------------------------------- |
| 2102 | generate_branch - generate an unconditional |
| 2103 | branch |
| 2104 | -------------------------------------------------*/ |
| 1318 | 2105 | |
| 1319 | | ppc.pvr = config->pvr; |
| 2106 | static void generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int source, UINT8 link) |
| 2107 | { |
| 2108 | compiler_state compiler_temp = *compiler; |
| 1320 | 2109 | |
| 1321 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1322 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1323 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 2110 | /* set the link if needed */ |
| 2111 | if (link) |
| 2112 | UML_MOV(block, SPR32(SPR_LR), IMM(desc->pc + 4)); // mov [lr],desc->pc + 4 |
| 1324 | 2113 | |
| 1325 | | switch(config->pvr) |
| 2114 | /* update the cycles and jump through the hash table to the target */ |
| 2115 | if (desc->targetpc != BRANCH_TARGET_DYNAMIC) |
| 1326 | 2116 | { |
| 1327 | | case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1328 | | case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1329 | | case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1330 | | default: break; |
| 2117 | generate_update_cycles(block, &compiler_temp, IMM(desc->targetpc), TRUE); // <subtract cycles> |
| 2118 | if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) |
| 2119 | UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000 |
| 2120 | else |
| 2121 | UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(desc->targetpc), ppc->impstate->nocode); // hashjmp <mode>,desc->targetpc,nocode |
| 1331 | 2122 | } |
| 2123 | else |
| 2124 | { |
| 2125 | UML_CMP(block, SPR32(source), IMM(0xb032)); |
| 2126 | UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); |
| 2127 | UML_CALLCc(block, IF_E, cfunc_printf_debug, "b032 @ PC=%08X\n"); |
| 1332 | 2128 | |
| 1333 | | if (pll_config == -1) |
| 1334 | | { |
| 1335 | | fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); |
| 2129 | generate_update_cycles(block, &compiler_temp, SPR32(source), TRUE); // <subtract cycles> |
| 2130 | UML_HASHJMP(block, IMM(ppc->impstate->mode), SPR32(source), ppc->impstate->nocode); // hashjmp <mode>,<rsreg>,nocode |
| 1336 | 2131 | } |
| 1337 | 2132 | |
| 1338 | | ppc.hid1 = pll_config << 28; |
| 1339 | | } |
| 2133 | /* update the label */ |
| 2134 | compiler->labelnum = compiler_temp.labelnum; |
| 1340 | 2135 | |
| 1341 | | static void ppcdrc603_exit(void) |
| 1342 | | { |
| 1343 | | #if LOG_CODE |
| 1344 | | //if (symfile) fclose(symfile); |
| 1345 | | #endif |
| 1346 | | ppcdrc_exit(); |
| 2136 | /* reset the mapvar to the current cycles */ |
| 2137 | UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles |
| 1347 | 2138 | } |
| 1348 | | #endif |
| 1349 | 2139 | |
| 1350 | | #if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240 || HAS_PPC604) |
| 1351 | | static void ppcdrc603_reset(void) |
| 1352 | | { |
| 1353 | | ppc.pc = ppc.npc = 0xfff00100; |
| 1354 | 2140 | |
| 1355 | | ppc_set_msr(0x40); |
| 1356 | | change_pc(ppc.pc); |
| 2141 | /*------------------------------------------------- |
| 2142 | generate_branch_bo - generate a conditional |
| 2143 | branch based on the BO and BI fields |
| 2144 | -------------------------------------------------*/ |
| 1357 | 2145 | |
| 1358 | | /* reset the DRC */ |
| 1359 | | drc_cache_reset(ppc.drc); |
| 1360 | | } |
| 1361 | | |
| 1362 | | static int ppcdrc603_execute(int cycles) |
| 2146 | static void generate_branch_bo(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 bo, UINT32 bi, int source, int link) |
| 1363 | 2147 | { |
| 1364 | | /* count cycles and interrupt cycles */ |
| 1365 | | ppc_icount = cycles; |
| 1366 | | ppc_tb_base_icount = cycles; |
| 1367 | | ppc_dec_base_icount = cycles + ppc.dec_frac; |
| 2148 | int skip = compiler->labelnum++; |
| 1368 | 2149 | |
| 1369 | | // check if decrementer exception occurs during execution |
| 1370 | | if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) |
| 2150 | if (!(bo & 0x04)) |
| 1371 | 2151 | { |
| 1372 | | ppc_dec_trigger_cycle = ppc_icount - DEC; |
| 2152 | UML_SUBf(block, SPR32(SPR_CTR), SPR32(SPR_CTR), IMM(1), FLAGS_Z); // sub [ctr],[ctr],1,z |
| 2153 | UML_JMPc(block, (bo & 0x02) ? IF_NZ : IF_Z, skip); // jmp skip,nz/z |
| 1373 | 2154 | } |
| 1374 | | else |
| 2155 | if (!(bo & 0x10)) |
| 1375 | 2156 | { |
| 1376 | | ppc_dec_trigger_cycle = 0x7fffffff; |
| 2157 | UML_TEST(block, CR32, IMM(0x80000000 >> bi)); // test cr32,0x80000000 >> bi |
| 2158 | UML_JMPc(block, (bo & 0x08) ? IF_Z : IF_NZ, skip); // jmp skip,z/nz |
| 1377 | 2159 | } |
| 2160 | generate_branch(block, compiler, desc, source, link); // <branch> |
| 2161 | UML_LABEL(block, skip); // skip: |
| 2162 | } |
| 1378 | 2163 | |
| 1379 | | drc_execute(ppc.drc); |
| 1380 | 2164 | |
| 1381 | | // update timebase |
| 1382 | | // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly |
| 1383 | | ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); |
| 2165 | /*------------------------------------------------- |
| 2166 | generate_opcode - generate code for a specific |
| 2167 | opcode |
| 2168 | -------------------------------------------------*/ |
| 1384 | 2169 | |
| 1385 | | // update decrementer |
| 1386 | | ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2)); |
| 1387 | | DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); |
| 2170 | static int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 2171 | { |
| 2172 | UINT32 op = *desc->opptr.l; |
| 2173 | UINT32 opswitch = op >> 26; |
| 2174 | int regnum; |
| 1388 | 2175 | |
| 1389 | | return cycles - ppc_icount; |
| 1390 | | } |
| 2176 | switch (opswitch) |
| 2177 | { |
| 2178 | case 0x02: /* TDI - 64-bit only */ |
| 2179 | case 0x1e: /* 0x1e group - 64-bit only */ |
| 2180 | case 0x3a: /* 0x3a group - 64-bit only */ |
| 2181 | case 0x3e: /* 0x3e group - 64-bit only */ |
| 2182 | return FALSE; |
| 1391 | 2183 | |
| 1392 | | static void ppcdrc603_set_irq_line(int irqline, int state) |
| 1393 | | { |
| 1394 | | if( state ) { |
| 1395 | | ppc.exception_pending |= 0x1; |
| 1396 | | if (ppc.irq_callback) |
| 1397 | | { |
| 1398 | | ppc.irq_callback(irqline); |
| 1399 | | } |
| 1400 | | } |
| 1401 | | } |
| 1402 | | #endif |
| 2184 | case 0x03: /* TWI */ |
| 2185 | UML_CMP(block, R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // cmp ra,simm |
| 2186 | if (G_TO(op) & 0x10) |
| 2187 | UML_EXHc(block, IF_L, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,l |
| 2188 | if (G_TO(op) & 0x08) |
| 2189 | UML_EXHc(block, IF_G, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,g |
| 2190 | if (G_TO(op) & 0x04) |
| 2191 | UML_EXHc(block, IF_E, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,e |
| 2192 | if (G_TO(op) & 0x02) |
| 2193 | UML_EXHc(block, IF_B, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,b |
| 2194 | if (G_TO(op) & 0x01) |
| 2195 | UML_EXHc(block, IF_A, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,a |
| 2196 | return TRUE; |
| 1403 | 2197 | |
| 1404 | | #if (HAS_PPC602) |
| 1405 | | static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1406 | | { |
| 1407 | | float multiplier; |
| 1408 | | const ppc_config *config = _config; |
| 1409 | | int i; |
| 2198 | case 0x07: /* MULLI */ |
| 2199 | UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); |
| 2200 | // muls rd,rd,ra,simm |
| 2201 | return TRUE; |
| 1410 | 2202 | |
| 1411 | | ppc_init(); |
| 1412 | | ppcdrc_init(); |
| 2203 | case 0x0e: /* ADDI */ |
| 2204 | UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add rd,ra,simm |
| 2205 | return TRUE; |
| 1413 | 2206 | |
| 1414 | | ppc.optable[48] = recompile_lfs; |
| 1415 | | ppc.optable[49] = recompile_lfsu; |
| 1416 | | ppc.optable[50] = recompile_lfd; |
| 1417 | | ppc.optable[51] = recompile_lfdu; |
| 1418 | | ppc.optable[52] = recompile_stfs; |
| 1419 | | ppc.optable[53] = recompile_stfsu; |
| 1420 | | ppc.optable[54] = recompile_stfd; |
| 1421 | | ppc.optable[55] = recompile_stfdu; |
| 1422 | | ppc.optable31[631] = recompile_lfdux; |
| 1423 | | ppc.optable31[599] = recompile_lfdx; |
| 1424 | | ppc.optable31[567] = recompile_lfsux; |
| 1425 | | ppc.optable31[535] = recompile_lfsx; |
| 1426 | | ppc.optable31[595] = recompile_mfsr; |
| 1427 | | ppc.optable31[659] = recompile_mfsrin; |
| 1428 | | ppc.optable31[371] = recompile_mftb; |
| 1429 | | ppc.optable31[210] = recompile_mtsr; |
| 1430 | | ppc.optable31[242] = recompile_mtsrin; |
| 1431 | | ppc.optable31[758] = recompile_dcba; |
| 1432 | | ppc.optable31[759] = recompile_stfdux; |
| 1433 | | ppc.optable31[727] = recompile_stfdx; |
| 1434 | | ppc.optable31[983] = recompile_stfiwx; |
| 1435 | | ppc.optable31[695] = recompile_stfsux; |
| 1436 | | ppc.optable31[663] = recompile_stfsx; |
| 1437 | | ppc.optable31[370] = recompile_tlbia; |
| 1438 | | ppc.optable31[306] = recompile_tlbie; |
| 1439 | | ppc.optable31[566] = recompile_tlbsync; |
| 1440 | | ppc.optable31[310] = recompile_eciwx; |
| 1441 | | ppc.optable31[438] = recompile_ecowx; |
| 2207 | case 0x0f: /* ADDIS */ |
| 2208 | UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), IMM(G_SIMM(op) << 16)); // add rd,ra,simm << 16 |
| 2209 | return TRUE; |
| 1442 | 2210 | |
| 1443 | | ppc.optable63[264] = recompile_fabsx; |
| 1444 | | ppc.optable63[21] = recompile_faddx; |
| 1445 | | ppc.optable63[32] = recompile_fcmpo; |
| 1446 | | ppc.optable63[0] = recompile_fcmpu; |
| 1447 | | ppc.optable63[14] = recompile_fctiwx; |
| 1448 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1449 | | ppc.optable63[18] = recompile_fdivx; |
| 1450 | | ppc.optable63[72] = recompile_fmrx; |
| 1451 | | ppc.optable63[136] = recompile_fnabsx; |
| 1452 | | ppc.optable63[40] = recompile_fnegx; |
| 1453 | | ppc.optable63[12] = recompile_frspx; |
| 1454 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1455 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1456 | | ppc.optable63[20] = recompile_fsubx; |
| 1457 | | ppc.optable63[583] = recompile_mffsx; |
| 1458 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1459 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1460 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1461 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1462 | | ppc.optable63[64] = recompile_mcrfs; |
| 2211 | case 0x0a: /* CMPLI */ |
| 2212 | UML_CMP(block, R32(G_RA(op)), IMM(G_UIMM(op))); // cmp ra,uimm |
| 2213 | UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C); // getflgs i0,zc |
| 2214 | UML_LOAD(block, IREG(0), ppc->impstate->cmpl_cr_table, IREG(0), DWORD); // load i0,cmpl_cr_table,i0,dword |
| 2215 | UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] |
| 2216 | return TRUE; |
| 1463 | 2217 | |
| 1464 | | ppc.optable59[21] = recompile_faddsx; |
| 1465 | | ppc.optable59[18] = recompile_fdivsx; |
| 1466 | | ppc.optable59[24] = recompile_fresx; |
| 1467 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1468 | | ppc.optable59[20] = recompile_fsubsx; |
| 2218 | case 0x0b: /* CMPI */ |
| 2219 | UML_CMP(block, R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // cmp ra,uimm |
| 2220 | UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C | DRCUML_FLAG_S); // getflgs i0,zcs |
| 2221 | UML_LOAD(block, IREG(0), ppc->impstate->cmp_cr_table, IREG(0), DWORD); // load i0,cmp_cr_table,i0,dword |
| 2222 | UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] |
| 2223 | return TRUE; |
| 1469 | 2224 | |
| 1470 | | for(i = 0; i < 32; i++) |
| 1471 | | { |
| 1472 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1473 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1474 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1475 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1476 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1477 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 2225 | case 0x08: /* SUBFIC */ |
| 2226 | UML_SUBf(block, R32(G_RD(op)), IMM((INT16)G_SIMM(op)), R32(G_RA(op)), FLAGS_C); // sub rd,simm,ra,c |
| 2227 | generate_compute_flags(block, FALSE, XER_CA, TRUE); // <update flags> |
| 2228 | return TRUE; |
| 1478 | 2229 | |
| 1479 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1480 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1481 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1482 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1483 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1484 | | } |
| 2230 | case 0x0c: /* ADDIC */ |
| 2231 | UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), IMM((INT16)G_SIMM(op)), FLAGS_C); // add rd,ra,simm,c |
| 2232 | generate_compute_flags(block, FALSE, XER_CA, FALSE); // <update flags> |
| 2233 | return TRUE; |
| 1485 | 2234 | |
| 1486 | | for(i = 0; i < 256; i++) |
| 1487 | | { |
| 1488 | | ppc_field_xlat[i] = |
| 1489 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1490 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1491 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1492 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1493 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1494 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1495 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1496 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1497 | | } |
| 2235 | case 0x0d: /* ADDIC. */ |
| 2236 | UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), IMM((INT16)G_SIMM(op)), FLAGS_C); // add rd,ra,simm,c |
| 2237 | generate_compute_flags(block, TRUE, XER_CA, FALSE); // <update flags> |
| 2238 | return TRUE; |
| 1498 | 2239 | |
| 1499 | | // PPC602 specific opcodes |
| 1500 | | ppc.optable31[596] = recompile_esa; |
| 1501 | | ppc.optable31[628] = recompile_dsa; |
| 1502 | | ppc.optable31[1010] = recompile_tlbli; |
| 1503 | | ppc.optable31[978] = recompile_tlbld; |
| 2240 | case 0x10: /* BCx */ |
| 2241 | generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), 0, op & M_LK); // <branch conditional> |
| 2242 | return TRUE; |
| 1504 | 2243 | |
| 1505 | | ppc.is603 = 0; |
| 1506 | | ppc.is602 = 1; |
| 2244 | case 0x11: /* SC */ |
| 2245 | UML_EXH(block, ppc->impstate->exception[EXCEPTION_SYSCALL], IMM(0)); // exh syscall,0 |
| 2246 | return TRUE; |
| 1507 | 2247 | |
| 1508 | | ppc.read8 = program_read_byte_64be; |
| 1509 | | ppc.read16 = program_read_word_64be; |
| 1510 | | ppc.read32 = program_read_dword_64be; |
| 1511 | | ppc.read64 = program_read_qword_64be; |
| 1512 | | ppc.write8 = program_write_byte_64be; |
| 1513 | | ppc.write16 = program_write_word_64be; |
| 1514 | | ppc.write32 = program_write_dword_64be; |
| 1515 | | ppc.write64 = program_write_qword_64be; |
| 1516 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1517 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1518 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1519 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1520 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1521 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 2248 | case 0x12: /* Bx */ |
| 2249 | generate_branch(block, compiler, desc, 0, op & M_LK); // <branch> |
| 2250 | return TRUE; |
| 1522 | 2251 | |
| 1523 | | ppc.irq_callback = irqcallback; |
| 2252 | case 0x13: /* 0x13 group */ |
| 2253 | return generate_instruction_13(block, compiler, desc); // <group13> |
| 1524 | 2254 | |
| 1525 | | ppc.pvr = config->pvr; |
| 2255 | case 0x14: /* RLWIMIx */ |
| 2256 | UML_ROLINS(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_SH(op)), IMM(compute_rlw_mask(G_MB(op), G_ME(op)))); |
| 2257 | // rolins ra,rs,sh,mask |
| 2258 | if (op & M_RC) |
| 2259 | { |
| 2260 | UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 |
| 2261 | generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> |
| 2262 | } |
| 2263 | return TRUE; |
| 1526 | 2264 | |
| 1527 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1528 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1529 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1530 | | } |
| 2265 | case 0x15: /* RLWINMx */ |
| 2266 | UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_SH(op)), IMM(compute_rlw_mask(G_MB(op), G_ME(op)))); |
| 2267 | // roland ra,rs,sh,mask |
| 2268 | if (op & M_RC) |
| 2269 | { |
| 2270 | UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 |
| 2271 | generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> |
| 2272 | } |
| 2273 | return TRUE; |
| 1531 | 2274 | |
| 1532 | | static void ppcdrc602_exit(void) |
| 1533 | | { |
| 1534 | | #if LOG_CODE |
| 1535 | | //if (symfile) fclose(symfile); |
| 1536 | | #endif |
| 1537 | | ppcdrc_exit(); |
| 2275 | case 0x17: /* RLWNMx */ |
| 2276 | UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), IMM(compute_rlw_mask(G_MB(op), G_ME(op)))); |
| 2277 | // roland ra,rs,rb,mask |
| 2278 | if (op & M_RC) |
| 2279 | { |
| 2280 | UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 |
| 2281 | generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> |
| 2282 | } |
| 2283 | return TRUE; |
| 2284 | |
| 2285 | case 0x18: /* ORI */ |
| 2286 | UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op))); // or ra,rs,uimm |
| 2287 | return TRUE; |
| 2288 | |
| 2289 | case 0x19: /* ORIS */ |
| 2290 | UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op) << 16)); // or ra,rs,uimm << 16 |
| 2291 | return TRUE; |
| 2292 | |
| 2293 | case 0x1a: /* XORI */ |
| 2294 | UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op))); // xor ra,rs,uimm |
| 2295 | return TRUE; |
| 2296 | |
| 2297 | case 0x1b: /* XORIS */ |
| 2298 | UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op) << 16)); // xor ra,rs,uimm << 16 |
| 2299 | return TRUE; |
| 2300 | |
| 2301 | case 0x1c: /* ANDI. */ |
| 2302 | UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op)), FLAGS_RC(op)); // and ra,rs,uimm,FLAGS_RC |
| 2303 | generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> |
| 2304 | return TRUE; |
| 2305 | |
| 2306 | case 0x1d: /* ANDIS. */ |
| 2307 | UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op) << 16), FLAGS_RC(op));// and ra,rs,uimm << 16,FLAGS_RC |
| 2308 | generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> |
| 2309 | return TRUE; |
| 2310 | |
| 2311 | case 0x1f: /* 0x1f group */ |
| 2312 | return generate_instruction_1f(block, compiler, desc); // <group1f> |
| 2313 | |
| 2314 | case 0x22: /* LBZ */ |
| 2315 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2316 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2317 | UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 |
| 2318 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff |
| 2319 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2320 | return TRUE; |
| 2321 | |
| 2322 | case 0x28: /* LHZ */ |
| 2323 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2324 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2325 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 2326 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff |
| 2327 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2328 | return TRUE; |
| 2329 | |
| 2330 | case 0x2a: /* LHA */ |
| 2331 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2332 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2333 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 2334 | UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word |
| 2335 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2336 | return TRUE; |
| 2337 | |
| 2338 | case 0x20: /* LWZ */ |
| 2339 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2340 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2341 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 2342 | UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 |
| 2343 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2344 | return TRUE; |
| 2345 | |
| 2346 | case 0x23: /* LBZU */ |
| 2347 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2348 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2349 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2350 | UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 |
| 2351 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff |
| 2352 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2353 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2354 | return TRUE; |
| 2355 | |
| 2356 | case 0x29: /* LHZU */ |
| 2357 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2358 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2359 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2360 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 2361 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff |
| 2362 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2363 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2364 | return TRUE; |
| 2365 | |
| 2366 | case 0x2b: /* LHAU */ |
| 2367 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2368 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2369 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2370 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 2371 | UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word |
| 2372 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2373 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2374 | return TRUE; |
| 2375 | |
| 2376 | case 0x21: /* LWZU */ |
| 2377 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2378 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2379 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2380 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 2381 | UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 |
| 2382 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2383 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2384 | return TRUE; |
| 2385 | |
| 2386 | case 0x26: /* STB */ |
| 2387 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2388 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff |
| 2389 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2390 | UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 |
| 2391 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2392 | return TRUE; |
| 2393 | |
| 2394 | case 0x2c: /* STH */ |
| 2395 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2396 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff |
| 2397 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2398 | UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 |
| 2399 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2400 | return TRUE; |
| 2401 | |
| 2402 | case 0x24: /* STW */ |
| 2403 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2404 | UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs |
| 2405 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2406 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 2407 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2408 | return TRUE; |
| 2409 | |
| 2410 | case 0x27: /* STBU */ |
| 2411 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2412 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff |
| 2413 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2414 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2415 | UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 |
| 2416 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2417 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2418 | return TRUE; |
| 2419 | |
| 2420 | case 0x2d: /* STHU */ |
| 2421 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2422 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff |
| 2423 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2424 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2425 | UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 |
| 2426 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2427 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2428 | return TRUE; |
| 2429 | |
| 2430 | case 0x25: /* STWU */ |
| 2431 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2432 | UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs |
| 2433 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2434 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2435 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 2436 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2437 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2438 | return TRUE; |
| 2439 | |
| 2440 | case 0x2e: /* LMW */ |
| 2441 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2442 | for (regnum = G_RD(op); regnum < 32; regnum++) |
| 2443 | { |
| 2444 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op) + 4 * (regnum - G_RD(op)))); |
| 2445 | // add i0,ra,simm + 4*(regnum-rd) |
| 2446 | UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align |
| 2447 | UML_MOV(block, R32(regnum), IREG(0)); // mov regnum,i0 |
| 2448 | } |
| 2449 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2450 | return TRUE; |
| 2451 | |
| 2452 | case 0x2f: /* STMW */ |
| 2453 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2454 | for (regnum = G_RS(op); regnum < 32; regnum++) |
| 2455 | { |
| 2456 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op) + 4 * (regnum - G_RS(op)))); |
| 2457 | // add i0,ra,simm + 4*(regnum-rs) |
| 2458 | UML_MOV(block, IREG(1), R32(regnum)); // mov i1,regnum |
| 2459 | UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode & 3]); // callh write32align |
| 2460 | } |
| 2461 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2462 | return TRUE; |
| 2463 | |
| 2464 | case 0x30: /* LFS */ |
| 2465 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2466 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2467 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 2468 | UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 |
| 2469 | UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword |
| 2470 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2471 | return TRUE; |
| 2472 | |
| 2473 | case 0x32: /* LFD */ |
| 2474 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2475 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2476 | UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 |
| 2477 | UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 |
| 2478 | UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] |
| 2479 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2480 | return TRUE; |
| 2481 | |
| 2482 | case 0x31: /* LFSU */ |
| 2483 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2484 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2485 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2486 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 2487 | UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 |
| 2488 | UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword |
| 2489 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2490 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2491 | return TRUE; |
| 2492 | |
| 2493 | case 0x33: /* LFDU */ |
| 2494 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2495 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2496 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2497 | UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 |
| 2498 | UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 |
| 2499 | UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] |
| 2500 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2501 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2502 | return TRUE; |
| 2503 | |
| 2504 | case 0x34: /* STFS */ |
| 2505 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2506 | UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword |
| 2507 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] |
| 2508 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2509 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 2510 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2511 | return TRUE; |
| 2512 | |
| 2513 | case 0x36: /* STFD */ |
| 2514 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2515 | UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs |
| 2516 | UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] |
| 2517 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) |
| 2518 | UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 |
| 2519 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2520 | return TRUE; |
| 2521 | |
| 2522 | case 0x35: /* STFSU */ |
| 2523 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2524 | UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword |
| 2525 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] |
| 2526 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2527 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2528 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 2529 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2530 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2531 | return TRUE; |
| 2532 | |
| 2533 | case 0x37: /* STFDU */ |
| 2534 | UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm |
| 2535 | UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs |
| 2536 | UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] |
| 2537 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 2538 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) |
| 2539 | UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 |
| 2540 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 2541 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2542 | return TRUE; |
| 2543 | |
| 2544 | case 0x3b: /* 0x3b group */ |
| 2545 | return generate_instruction_3b(block, compiler, desc); // <group3b> |
| 2546 | |
| 2547 | case 0x3f: /* 0x3f group */ |
| 2548 | return generate_instruction_3f(block, compiler, desc); // <group3f> |
| 2549 | } |
| 2550 | |
| 2551 | return FALSE; |
| 1538 | 2552 | } |
| 1539 | 2553 | |
| 1540 | | static void ppcdrc602_reset(void) |
| 2554 | |
| 2555 | /*------------------------------------------------- |
| 2556 | generate_instruction_13 - compile opcodes in |
| 2557 | the 0x13 group |
| 2558 | -------------------------------------------------*/ |
| 2559 | |
| 2560 | static int generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 1541 | 2561 | { |
| 1542 | | ppc.pc = ppc.npc = 0xfff00100; |
| 2562 | UINT32 op = *desc->opptr.l; |
| 2563 | UINT32 opswitch = (op >> 1) & 0x3ff; |
| 1543 | 2564 | |
| 1544 | | ppc_set_msr(0x40); |
| 1545 | | change_pc(ppc.pc); |
| 2565 | switch (opswitch) |
| 2566 | { |
| 2567 | case 0x010: /* BCLRx */ |
| 2568 | generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_LR, op & M_LK);// <branch conditional> |
| 2569 | return TRUE; |
| 1546 | 2570 | |
| 1547 | | ppc.hid0 = 1; |
| 2571 | case 0x210: /* BCCTRx */ |
| 2572 | generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_CTR, op & M_LK); |
| 2573 | // <branch conditional> |
| 2574 | return TRUE; |
| 1548 | 2575 | |
| 1549 | | /* reset the DRC */ |
| 1550 | | drc_cache_reset(ppc.drc); |
| 2576 | case 0x000: /* MCRF */ |
| 2577 | UML_ROLINS(block, CR32, CR32, IMM(((G_CRFS(op) - G_CRFD(op)) & 7) * 4), IMM(CRMASK(G_CRFD(op)))); |
| 2578 | // rolins cr,cr,4*(crfs-crfd),crmask[crfd] |
| 2579 | return TRUE; |
| 2580 | |
| 2581 | case 0x101: /* CRAND */ |
| 2582 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2583 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2584 | UML_AND(block, IREG(0), IREG(0), IREG(1)); // and i0,i1 |
| 2585 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2586 | // rolins cr,i0,32-crbd,1<<crbd |
| 2587 | return TRUE; |
| 2588 | |
| 2589 | case 0x081: /* CRANDC */ |
| 2590 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2591 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2592 | UML_XOR(block, IREG(1), IREG(1), IMM(~0)); // xor i1,~0 |
| 2593 | UML_AND(block, IREG(0), IREG(0), IREG(1)); // and i0,i1 |
| 2594 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2595 | // rolins cr,i0,32-crbd,1<<crbd |
| 2596 | return TRUE; |
| 2597 | |
| 2598 | case 0x0e1: /* CRNAND */ |
| 2599 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2600 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2601 | UML_AND(block, IREG(0), IREG(0), IREG(1)); // and i0,i1 |
| 2602 | UML_XOR(block, IREG(0), IREG(0), IMM(~0)); // xor i0,~0 |
| 2603 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2604 | // rolins cr,i0,32-crbd,1<<crbd |
| 2605 | return TRUE; |
| 2606 | |
| 2607 | case 0x1c1: /* CROR */ |
| 2608 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2609 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2610 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i1 |
| 2611 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2612 | // rolins cr,i0,32-crbd,1<<crbd |
| 2613 | return TRUE; |
| 2614 | |
| 2615 | case 0x1a1: /* CRORC */ |
| 2616 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2617 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2618 | UML_XOR(block, IREG(1), IREG(1), IMM(~0)); // xor i1,~0 |
| 2619 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i1 |
| 2620 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2621 | // rolins cr,i0,32-crbd,1<<crbd |
| 2622 | return TRUE; |
| 2623 | |
| 2624 | case 0x021: /* CRNOR */ |
| 2625 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2626 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2627 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i1 |
| 2628 | UML_XOR(block, IREG(0), IREG(0), IMM(~0)); // xor i0,~0 |
| 2629 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2630 | // rolins cr,i0,32-crbd,1<<crbd |
| 2631 | return TRUE; |
| 2632 | |
| 2633 | case 0x0c1: /* CRXOR */ |
| 2634 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2635 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2636 | UML_XOR(block, IREG(0), IREG(0), IREG(1)); // xor i0,i1 |
| 2637 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2638 | // rolins cr,i0,32-crbd,1<<crbd |
| 2639 | return TRUE; |
| 2640 | |
| 2641 | case 0x121: /* CREQV */ |
| 2642 | UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) |
| 2643 | UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) |
| 2644 | UML_XOR(block, IREG(0), IREG(0), IREG(1)); // xor i0,i1 |
| 2645 | UML_XOR(block, IREG(0), IREG(0), IMM(~0)); // xor i0,~0 |
| 2646 | UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); |
| 2647 | // rolins cr,i0,32-crbd,1<<crbd |
| 2648 | return TRUE; |
| 2649 | |
| 2650 | case 0x032: /* RFI */ |
| 2651 | if (ppc->cap & PPCCAP_OEA) |
| 2652 | { |
| 2653 | if (!(ppc->cap & PPCCAP_603_MMU)) |
| 2654 | UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), IMM(0), IMM(0x87c0ffff)); // rolins [msr],[srr1],0,0x87c0ffff |
| 2655 | else |
| 2656 | { |
| 2657 | UML_MOV(block, IREG(0), MSR32); // mov i0,[msr] |
| 2658 | UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), IMM(0), IMM(0x87c0ffff | MSR603_TGPR)); |
| 2659 | // rolins [msr],[srr1],0,0x87c0ffff | MSR603_TGPR |
| 2660 | UML_XOR(block, IREG(0), IREG(0), MSR32); // xor i0,i0,[msr] |
| 2661 | UML_TEST(block, IREG(0), IMM(MSR603_TGPR)); // test i0,tgpr |
| 2662 | UML_CALLHc(block, IF_NZ, ppc->impstate->swap_tgpr); // callh swap_tgpr,nz |
| 2663 | } |
| 2664 | } |
| 2665 | else if (ppc->cap & PPCCAP_4XX) |
| 2666 | UML_MOV(block, MSR32, SPR32(SPR4XX_SRR1)); // mov [msr],[srr1] |
| 2667 | generate_update_mode(block); // <update mode> |
| 2668 | compiler->checkints = TRUE; |
| 2669 | generate_update_cycles(block, compiler, SPR32(SPROEA_SRR0), TRUE); // <subtract cycles> |
| 2670 | UML_HASHJMP(block, MEM(&ppc->impstate->mode), SPR32(SPROEA_SRR0), ppc->impstate->nocode); |
| 2671 | // hashjmp mode,[srr0],nocode |
| 2672 | return TRUE; |
| 2673 | |
| 2674 | case 0x033: /* RFCI */ |
| 2675 | assert(ppc->cap & PPCCAP_4XX); |
| 2676 | UML_MOV(block, MSR32, SPR32(SPR4XX_SRR3)); // mov [msr],[srr3] |
| 2677 | generate_update_mode(block); // <update mode> |
| 2678 | compiler->checkints = TRUE; |
| 2679 | generate_update_cycles(block, compiler, SPR32(SPR4XX_SRR2), TRUE); // <subtract cycles> |
| 2680 | UML_HASHJMP(block, MEM(&ppc->impstate->mode), SPR32(SPR4XX_SRR2), ppc->impstate->nocode); |
| 2681 | // hashjmp mode,[srr2],nocode |
| 2682 | return TRUE; |
| 2683 | |
| 2684 | case 0x096: /* ISYNC */ |
| 2685 | /* effective no-op */ |
| 2686 | return TRUE; |
| 2687 | } |
| 2688 | |
| 2689 | return FALSE; |
| 1551 | 2690 | } |
| 1552 | 2691 | |
| 1553 | | static int ppcdrc602_execute(int cycles) |
| 2692 | |
| 2693 | /*------------------------------------------------- |
| 2694 | generate_instruction_1f - compile opcodes in |
| 2695 | the 0x1f group |
| 2696 | -------------------------------------------------*/ |
| 2697 | |
| 2698 | static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 1554 | 2699 | { |
| 1555 | | /* count cycles and interrupt cycles */ |
| 1556 | | ppc_icount = cycles; |
| 1557 | | ppc_tb_base_icount = cycles; |
| 1558 | | ppc_dec_base_icount = cycles; |
| 2700 | UINT32 op = *desc->opptr.l; |
| 2701 | UINT32 opswitch = (op >> 1) & 0x3ff; |
| 2702 | drcuml_codelabel swloop, swloopend; |
| 2703 | int item; |
| 1559 | 2704 | |
| 1560 | | // check if decrementer exception occurs during execution |
| 1561 | | if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) |
| 2705 | switch (opswitch) |
| 1562 | 2706 | { |
| 1563 | | ppc_dec_trigger_cycle = ppc_icount - DEC; |
| 1564 | | } |
| 1565 | | else |
| 1566 | | { |
| 1567 | | ppc_dec_trigger_cycle = 0x7fffffff; |
| 1568 | | } |
| 2707 | case 0x009: /* MULHDUx - 64-bit only */ |
| 2708 | case 0x015: /* LDX - 64-bit only */ |
| 2709 | case 0x01b: /* SLDx - 64-bit only */ |
| 2710 | case 0x035: /* LDUX - 64-bit only */ |
| 2711 | case 0x03a: /* CNTLZDx - 64-bit only */ |
| 2712 | case 0x044: /* TD - 64-bit only */ |
| 2713 | case 0x049: /* MULHDx - 64-bit only */ |
| 2714 | case 0x054: /* LDARX - 64-bit only */ |
| 2715 | case 0x095: /* STDX - 64-bit only */ |
| 2716 | case 0x0b5: /* STDUX - 64-bit only */ |
| 2717 | case 0x0d6: /* STDCX. - 64-bit only */ |
| 2718 | case 0x0e9: /* MULLD - 64-bit only */ |
| 2719 | case 0x2e9: /* MULLDO - 64-bit only */ |
| 2720 | case 0x155: /* LWAX - 64-bit only */ |
| 2721 | case 0x175: /* LWAUX - 64-bit only */ |
| 2722 | case 0x33a: /* SRADIx - 64-bit only */ |
| 2723 | case 0x33b: /* SRADIx - 64-bit only */ |
| 2724 | case 0x1b2: /* SLBIE - 64-bit only */ |
| 2725 | case 0x1c9: /* DIVDUx - 64-bit only */ |
| 2726 | case 0x3c9: /* DIVDUOx - 64-bit only */ |
| 2727 | case 0x1e9: /* DIVDx - 64-bit only */ |
| 2728 | case 0x3e9: /* DIVDOx - 64-bit only */ |
| 2729 | case 0x1f2: /* SLBIA - 64-bit only */ |
| 2730 | case 0x21b: /* SRDx - 64-bit only */ |
| 2731 | case 0x31a: /* SRADx - 64-bit only */ |
| 2732 | case 0x3da: /* EXTSW - 64-bit only */ |
| 2733 | return FALSE; |
| 1569 | 2734 | |
| 1570 | | drc_execute(ppc.drc); |
| 2735 | case 0x004: /* TW */ |
| 2736 | UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb |
| 2737 | if (G_TO(op) & 0x10) |
| 2738 | UML_EXHc(block, IF_L, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,l |
| 2739 | if (G_TO(op) & 0x08) |
| 2740 | UML_EXHc(block, IF_G, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,g |
| 2741 | if (G_TO(op) & 0x04) |
| 2742 | UML_EXHc(block, IF_E, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,e |
| 2743 | if (G_TO(op) & 0x02) |
| 2744 | UML_EXHc(block, IF_B, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,b |
| 2745 | if (G_TO(op) & 0x01) |
| 2746 | UML_EXHc(block, IF_A, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,a |
| 2747 | return TRUE; |
| 1571 | 2748 | |
| 1572 | | // update timebase |
| 1573 | | // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly |
| 1574 | | ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); |
| 2749 | case 0x10a: /* ADDx */ |
| 2750 | case 0x30a: /* ADDOx */ |
| 2751 | UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOE(op)); // add rd,ra,rb,FLAGS_RCOE(op) |
| 2752 | generate_compute_flags(block, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); // <update flags> |
| 2753 | return TRUE; |
| 1575 | 2754 | |
| 1576 | | // update decrementer |
| 1577 | | DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); |
| 2755 | case 0x00a: /* ADDCx */ |
| 2756 | case 0x20a: /* ADDCOx */ |
| 2757 | UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOECA(op)); // add rd,ra,rb,FLAGS_RCOECA(op) |
| 2758 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2759 | return TRUE; |
| 1578 | 2760 | |
| 1579 | | return cycles - ppc_icount; |
| 1580 | | } |
| 2761 | case 0x08a: /* ADDEx */ |
| 2762 | case 0x28a: /* ADDEOx */ |
| 2763 | UML_CARRY(block, SPR32(SPR_XER), IMM(29)); // carry [xer],XER_CA |
| 2764 | UML_ADDCf(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOECA(op));// addc rd,ra,rb,FLAGS_RCOECA(op) |
| 2765 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2766 | return TRUE; |
| 1581 | 2767 | |
| 1582 | | static void ppcdrc602_set_irq_line(int irqline, int state) |
| 1583 | | { |
| 1584 | | if( state ) { |
| 1585 | | ppc.exception_pending |= 0x1; |
| 1586 | | if (ppc.irq_callback) |
| 2768 | case 0x0ca: /* ADDZEx */ |
| 2769 | case 0x2ca: /* ADDZEOx */ |
| 2770 | UML_CARRY(block, SPR32(SPR_XER), IMM(29)); // carry [xer],XER_CA |
| 2771 | UML_ADDCf(block, R32(G_RD(op)), R32(G_RA(op)), IMM(0), FLAGS_RCOECA(op)); // addc rd,ra,0,FLAGS_RCOECA(op) |
| 2772 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2773 | return TRUE; |
| 2774 | |
| 2775 | case 0x0ea: /* ADDMEx */ |
| 2776 | case 0x2ea: /* ADDMEOx */ |
| 2777 | UML_CARRY(block, SPR32(SPR_XER), IMM(29)); // carry [xer],XER_CA |
| 2778 | UML_ADDCf(block, R32(G_RD(op)), R32(G_RA(op)), IMM(-1), FLAGS_RCOE(op)); // addc rd,ra,-1,FLAGS_RCOECA(op) |
| 2779 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> |
| 2780 | return TRUE; |
| 2781 | |
| 2782 | case 0x028: /* SUBFx */ |
| 2783 | case 0x228: /* SUBFOx */ |
| 2784 | UML_SUBf(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op)), FLAGS_RCOE(op)); // sub rd,rb,ra,FLAGS_RCOE(op) |
| 2785 | generate_compute_flags(block, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); // <update flags> |
| 2786 | return TRUE; |
| 2787 | |
| 2788 | case 0x008: /* SUBFCx */ |
| 2789 | case 0x208: /* SUBFCOx */ |
| 2790 | UML_SUBf(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op)), FLAGS_RCOECA(op)); // sub rd,rb,ra,FLAGS_RCOECA(op) |
| 2791 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> |
| 2792 | return TRUE; |
| 2793 | |
| 2794 | case 0x088: /* SUBFEx */ |
| 2795 | case 0x288: /* SUBFEOx */ |
| 2796 | UML_XOR(block, IREG(0), SPR32(SPR_XER), IMM(XER_CA)); // xor i0,[xer],XER_CA |
| 2797 | UML_CARRY(block, IREG(0), IMM(29)); // carry i0,XER_CA |
| 2798 | UML_SUBBf(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op)), FLAGS_RCOECA(op));// subc rd,rb,ra,FLAGS_RCOECA(op) |
| 2799 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> |
| 2800 | return TRUE; |
| 2801 | |
| 2802 | case 0x0c8: /* SUBFZEx */ |
| 2803 | case 0x2c8: /* SUBFZEOx */ |
| 2804 | UML_XOR(block, IREG(0), SPR32(SPR_XER), IMM(XER_CA)); // xor i0,[xer],XER_CA |
| 2805 | UML_CARRY(block, IREG(0), IMM(29)); // carry i0,XER_CA |
| 2806 | UML_SUBBf(block, R32(G_RD(op)), IMM(0), R32(G_RA(op)), FLAGS_RCOECA(op)); // subc rd,0,ra,FLAGS_RCOECA(op) |
| 2807 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> |
| 2808 | return TRUE; |
| 2809 | |
| 2810 | case 0x0e8: /* SUBFMEx */ |
| 2811 | case 0x2e8: /* SUBFMEOx */ |
| 2812 | UML_XOR(block, IREG(0), SPR32(SPR_XER), IMM(XER_CA)); // xor i0,[xer],XER_CA |
| 2813 | UML_CARRY(block, IREG(0), IMM(29)); // carry i0,XER_CA |
| 2814 | UML_SUBBf(block, R32(G_RD(op)), IMM(-1), R32(G_RA(op)), FLAGS_RCOECA(op)); // subc rd,-1,ra,,FLAGS_RCOECA(op) |
| 2815 | generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> |
| 2816 | return TRUE; |
| 2817 | |
| 2818 | case 0x068: /* NEGx */ |
| 2819 | case 0x268: /* NEGOx */ |
| 2820 | UML_SUBf(block, R32(G_RD(op)), IMM(0), R32(G_RA(op)), FLAGS_RCOE(op)); // sub rd,0,ra,FLAGS_RCOE(op) |
| 2821 | generate_compute_flags(block, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); // <update flags> |
| 2822 | return TRUE; |
| 2823 | |
| 2824 | case 0x000: /* CMP */ |
| 2825 | UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb |
| 2826 | UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C | DRCUML_FLAG_S); // getflgs i0,zcs |
| 2827 | UML_LOAD(block, IREG(0), ppc->impstate->cmp_cr_table, IREG(0), DWORD); // load i0,cmp_cr_table,i0,dword |
| 2828 | UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] |
| 2829 | return TRUE; |
| 2830 | |
| 2831 | case 0x020: /* CMPL */ |
| 2832 | UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb |
| 2833 | UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C); // getflgs i0,zc |
| 2834 | UML_LOAD(block, IREG(0), ppc->impstate->cmpl_cr_table, IREG(0), DWORD); // load i0,cmpl_cr_table,i0,dword |
| 2835 | UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] |
| 2836 | return TRUE; |
| 2837 | |
| 2838 | case 0x00b: /* MULHWUx */ |
| 2839 | UML_MULUf(block, IREG(0), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); |
| 2840 | // mulu i0,rd,ra,rb,FLAGS_RC(op) |
| 2841 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2842 | return TRUE; |
| 2843 | |
| 2844 | case 0x04b: /* MULHWx */ |
| 2845 | UML_MULSf(block, IREG(0), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); |
| 2846 | // muls i0,rd,ra,rb,,FLAGS_RC(op) |
| 2847 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2848 | return TRUE; |
| 2849 | |
| 2850 | case 0x0eb: /* MULLWx */ |
| 2851 | case 0x2eb: /* MULLWOx */ |
| 2852 | if (!(op & M_OE)) |
| 2853 | { |
| 2854 | UML_MULSf(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); |
| 2855 | // muls rd,rd,ra,rb,FLAGS_RC(op) |
| 2856 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2857 | } |
| 2858 | else |
| 2859 | { |
| 2860 | UML_MULSf(block, IREG(0), IREG(1), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); |
| 2861 | // muls i0,i1,ra,rb |
| 2862 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2863 | UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 |
| 2864 | UML_SAR(block, IREG(0), IREG(0), IMM(31)); // sar i0,i0,31 |
| 2865 | UML_AND(block, SPR32(SPR_XER), SPR32(SPR_XER), IMM(XER_OV)); // and [xer],[xer],XER_OV |
| 2866 | UML_XORf(block, IREG(0), IREG(0), IREG(1), FLAGS_Z); // xor i0,i0,i1,Z |
| 2867 | UML_MOVc(block, IF_NZ, IREG(0), IMM(XER_OV | XER_SO)); // mov i0,XER_OV | XER_SO,NZ |
| 2868 | UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), IREG(0)); // or [xer],[xer],i0 |
| 2869 | } |
| 2870 | return TRUE; |
| 2871 | |
| 2872 | case 0x1cb: /* DIVWUx */ |
| 2873 | case 0x3cb: /* DIVWUOx */ |
| 2874 | UML_DIVUf(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOE(op)); |
| 2875 | // divu rd,rd,ra,rb,FLAGS_RCOE(op) |
| 2876 | generate_compute_flags(block, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); // <update flags> |
| 2877 | return TRUE; |
| 2878 | |
| 2879 | case 0x1eb: /* DIVWx */ |
| 2880 | case 0x3eb: /* DIVWOx */ |
| 2881 | UML_DIVSf(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOE(op)); |
| 2882 | // divs rd,rd,ra,rb,FLAGS_RCOE(op) |
| 2883 | generate_compute_flags(block, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); // <update flags> |
| 2884 | return TRUE; |
| 2885 | |
| 2886 | case 0x01c: /* ANDx */ |
| 2887 | UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // and ra,rs,rb,FLAGS_RC(op) |
| 2888 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2889 | return TRUE; |
| 2890 | |
| 2891 | case 0x03c: /* ANDCx */ |
| 2892 | UML_XOR(block, IREG(0), R32(G_RB(op)), IMM(~0)); // xor i0,rb,~0 |
| 2893 | UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), IREG(0), FLAGS_RC(op)); // and ra,rs,i0,FLAGS_RC(op) |
| 2894 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2895 | return TRUE; |
| 2896 | |
| 2897 | case 0x1dc: /* NANDx */ |
| 2898 | UML_AND(block, IREG(0), R32(G_RS(op)), R32(G_RB(op))); // and i0,rs,rb |
| 2899 | UML_XORf(block, R32(G_RA(op)), IREG(0), IMM(~0), FLAGS_RC(op)); // xor ra,i0,~0,FLAGS_RC(op) |
| 2900 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2901 | return TRUE; |
| 2902 | |
| 2903 | case 0x1bc: /* ORx */ |
| 2904 | UML_ORf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // or ra,rs,rb,FLAGS_RC(op) |
| 2905 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2906 | return TRUE; |
| 2907 | |
| 2908 | case 0x19c: /* ORCx */ |
| 2909 | UML_XORf(block, IREG(0), R32(G_RB(op)), IMM(~0), FLAGS_RC(op)); // xor i0,rb,~0,FLAGS_RC(op) |
| 2910 | UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), IREG(0)); // or ra,rs,i0 |
| 2911 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2912 | return TRUE; |
| 2913 | |
| 2914 | case 0x07c: /* NORx */ |
| 2915 | UML_OR(block, IREG(0), R32(G_RS(op)), R32(G_RB(op))); // or i0,rs,rb |
| 2916 | UML_XORf(block, R32(G_RA(op)), IREG(0), IMM(~0), FLAGS_RC(op)); // xor ra,i0,~0,FLAGS_RC(op) |
| 2917 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2918 | return TRUE; |
| 2919 | |
| 2920 | case 0x13c: /* XORx */ |
| 2921 | UML_XORf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // xor ra,rs,rb,FLAGS_RC(op) |
| 2922 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2923 | return TRUE; |
| 2924 | |
| 2925 | case 0x11c: /* EQVx */ |
| 2926 | UML_XOR(block, IREG(0), R32(G_RS(op)), R32(G_RB(op))); // xor i0,rs,rb |
| 2927 | UML_XORf(block, R32(G_RA(op)), IREG(0), IMM(~0), FLAGS_RC(op)); // xor ra,i0,~0,FLAGS_RC(op) |
| 2928 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2929 | return TRUE; |
| 2930 | |
| 2931 | case 0x018: /* SLWx */ |
| 2932 | UML_SHL(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // shl ra,rs,rb |
| 2933 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2934 | return TRUE; |
| 2935 | |
| 2936 | case 0x218: /* SRWx */ |
| 2937 | UML_SHRf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // shr ra,rs,rb,FLAGS_RC(op) |
| 2938 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2939 | return TRUE; |
| 2940 | |
| 2941 | case 0x318: /* SRAWx */ |
| 2942 | UML_SHL(block, IREG(1), IMM(0xffffffff), R32(G_RB(op))); // shl i1,0xffffffff,rb |
| 2943 | UML_XOR(block, IREG(1), IREG(1), IMM(~0)); // xor i1,i1,~0 |
| 2944 | UML_AND(block, IREG(0), R32(G_RS(op)), IREG(1)); // and i0,rs,i1 |
| 2945 | UML_SAR(block, IREG(1), R32(G_RS(op)), IMM(31)); // sar i1,rs,31 |
| 2946 | UML_ANDf(block, IREG(0), IREG(0), IREG(1), DRCUML_FLAG_Z); // and i0,i0,i1,z |
| 2947 | UML_SETc(block, IF_NZ, IREG(0)); // set i0,nz |
| 2948 | UML_ROLINS(block, SPR32(SPR_XER), IREG(0), IMM(29), IMM(XER_CA)); // rolins [xer],i0,29,XER_CA |
| 2949 | UML_SARf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // sar ra,rs,rb,FLAGS_RC(op) |
| 2950 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2951 | return TRUE; |
| 2952 | |
| 2953 | case 0x338: /* SRAWIx */ |
| 2954 | UML_AND(block, IREG(0), R32(G_RS(op)), IMM(~(0xffffffff << (G_SH(op) & 31)))); // and i0,rs,~(0xffffffff << (sh & 31)) |
| 2955 | UML_SAR(block, IREG(1), R32(G_RS(op)), IMM(31)); // sar i1,rs,31 |
| 2956 | UML_ANDf(block, IREG(0), IREG(0), IREG(1), DRCUML_FLAG_Z); // and i0,i0,i1,z |
| 2957 | UML_SETc(block, IF_NZ, IREG(0)); // set i0,nz |
| 2958 | UML_ROLINS(block, SPR32(SPR_XER), IREG(0), IMM(29), IMM(XER_CA)); // rolins [xer],i0,29,XER_CA |
| 2959 | UML_SARf(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_SH(op)), FLAGS_RC(op)); // sar ra,rs,sh,FLAGS_RC(op) |
| 2960 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2961 | return TRUE; |
| 2962 | |
| 2963 | case 0x01a: /* CNTLZWx */ |
| 2964 | UML_LZCNT(block, R32(G_RA(op)), R32(G_RS(op))); // lzcnt ra,rs,rb |
| 2965 | if (op & M_RC) |
| 2966 | { |
| 2967 | UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 |
| 2968 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2969 | } |
| 2970 | return TRUE; |
| 2971 | |
| 2972 | case 0x3ba: /* EXTSBx */ |
| 2973 | UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), BYTE); // sext ra,rs,byte |
| 2974 | if (op & M_RC) |
| 2975 | { |
| 2976 | UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 |
| 2977 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2978 | } |
| 2979 | return TRUE; |
| 2980 | |
| 2981 | case 0x39a: /* EXTSHx */ |
| 2982 | UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), WORD); // sext ra,rs,word |
| 2983 | if (op & M_RC) |
| 2984 | { |
| 2985 | UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 |
| 2986 | generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> |
| 2987 | } |
| 2988 | return TRUE; |
| 2989 | |
| 2990 | case 0x057: /* LBZX */ |
| 2991 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 2992 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 2993 | UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 |
| 2994 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff |
| 2995 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 2996 | return TRUE; |
| 2997 | |
| 2998 | case 0x117: /* LHZX */ |
| 2999 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3000 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3001 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 3002 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff |
| 3003 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3004 | return TRUE; |
| 3005 | |
| 3006 | case 0x157: /* LHAX */ |
| 3007 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3008 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3009 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 3010 | UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word |
| 3011 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3012 | return TRUE; |
| 3013 | |
| 3014 | case 0x017: /* LWZX */ |
| 3015 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3016 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3017 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 3018 | UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 |
| 3019 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3020 | return TRUE; |
| 3021 | |
| 3022 | case 0x217: /* LFSX */ |
| 3023 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3024 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3025 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 3026 | UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 |
| 3027 | UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword |
| 3028 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3029 | return TRUE; |
| 3030 | |
| 3031 | case 0x257: /* LFDX */ |
| 3032 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3033 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3034 | UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 |
| 3035 | UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 |
| 3036 | UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] |
| 3037 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3038 | return TRUE; |
| 3039 | |
| 3040 | case 0x316: /* LHBRX */ |
| 3041 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3042 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3043 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 3044 | UML_BSWAP(block, IREG(0), IREG(0)); // bswap i0,i0 |
| 3045 | UML_SHR(block, R32(G_RD(op)), IREG(0), IMM(16)); // shr rd,i0,16 |
| 3046 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3047 | return TRUE; |
| 3048 | |
| 3049 | case 0x216: /* LWBRX */ |
| 3050 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3051 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3052 | UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align |
| 3053 | UML_BSWAP(block, R32(G_RD(op)), IREG(0)); // bswap rd,i0 |
| 3054 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3055 | return TRUE; |
| 3056 | |
| 3057 | case 0x077: /* LBZUX */ |
| 3058 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3059 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3060 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3061 | UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 |
| 3062 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff |
| 3063 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3064 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3065 | return TRUE; |
| 3066 | |
| 3067 | case 0x137: /* LHZUX */ |
| 3068 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3069 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3070 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3071 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 3072 | UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff |
| 3073 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3074 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3075 | return TRUE; |
| 3076 | |
| 3077 | case 0x177: /* LHAUX */ |
| 3078 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3079 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3080 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3081 | UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 |
| 3082 | UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word |
| 3083 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3084 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3085 | return TRUE; |
| 3086 | |
| 3087 | case 0x037: /* LWZUX */ |
| 3088 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3089 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3090 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3091 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 3092 | UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 |
| 3093 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3094 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3095 | return TRUE; |
| 3096 | |
| 3097 | case 0x237: /* LFSUX */ |
| 3098 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3099 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3100 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3101 | UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 |
| 3102 | UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 |
| 3103 | UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword |
| 3104 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3105 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3106 | return TRUE; |
| 3107 | |
| 3108 | case 0x277: /* LFDUX */ |
| 3109 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3110 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3111 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3112 | UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 |
| 3113 | UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 |
| 3114 | UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] |
| 3115 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3116 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3117 | return TRUE; |
| 3118 | |
| 3119 | case 0x014: /* LWARX */ |
| 3120 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3121 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3122 | UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align |
| 3123 | UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 |
| 3124 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3125 | return TRUE; |
| 3126 | |
| 3127 | case 0x255: /* LSWI */ |
| 3128 | UML_MOV(block, MEM(&ppc->impstate->swcount), IMM(((G_NB(op) - 1) & 0x1f) + 1)); // mov [swcount],[xer],G_NB |
| 3129 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra |
| 3130 | UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RD(op))); // mov [swreg],4*G_RD(op) |
| 3131 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3132 | save_fast_iregs(block); // <save fastregs> |
| 3133 | UML_LABEL(block, swloop = compiler->labelnum++); // swloop: |
| 3134 | UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] |
| 3135 | UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 |
| 3136 | UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 |
| 3137 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] |
| 3138 | UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 |
| 3139 | UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f |
| 3140 | UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) |
| 3141 | UML_STORE(block, &ppc->r[0], IREG(1), IREG(0), BYTE); // store &r0,i1,i0,byte |
| 3142 | UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); |
| 3143 | // sub [swcount],[swcount],1,Z |
| 3144 | UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ |
| 3145 | load_fast_iregs(block); // <load fastregs> |
| 3146 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3147 | return TRUE; |
| 3148 | |
| 3149 | case 0x215: /* LSWX */ |
| 3150 | UML_ANDf(block, FLAGS_Z, MEM(&ppc->impstate->swcount), SPR32(SPR_XER), IMM(0x7f));// and [swcount],[xer],0x7f,Z |
| 3151 | UML_JMPc(block, IF_Z, swloopend = compiler->labelnum++); // jmp swloopend,Z |
| 3152 | UML_ADD(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb |
| 3153 | UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RD(op))); // mov [swreg],4*G_RD(op) |
| 3154 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3155 | save_fast_iregs(block); // <save fastregs> |
| 3156 | UML_LABEL(block, swloop = compiler->labelnum++); // swloop: |
| 3157 | UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] |
| 3158 | UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 |
| 3159 | UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 |
| 3160 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] |
| 3161 | UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 |
| 3162 | UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f |
| 3163 | UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) |
| 3164 | UML_STORE(block, &ppc->r[0], IREG(1), IREG(0), BYTE); // store &r0,i1,i0,byte |
| 3165 | UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); |
| 3166 | // sub [swcount],[swcount],1,Z |
| 3167 | UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ |
| 3168 | UML_LABEL(block, swloopend); // swloopend: |
| 3169 | load_fast_iregs(block); // <load fastregs> |
| 3170 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3171 | return TRUE; |
| 3172 | |
| 3173 | case 0x136: /* ECIWX */ |
| 3174 | /* not implemented */ |
| 3175 | return FALSE; |
| 3176 | |
| 3177 | case 0x0d7: /* STBX */ |
| 3178 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3179 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff |
| 3180 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3181 | UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 |
| 3182 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3183 | return TRUE; |
| 3184 | |
| 3185 | case 0x197: /* STHX */ |
| 3186 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3187 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs |
| 3188 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3189 | UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 |
| 3190 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3191 | return TRUE; |
| 3192 | |
| 3193 | case 0x097: /* STWX */ |
| 3194 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3195 | UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs |
| 3196 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3197 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 3198 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3199 | return TRUE; |
| 3200 | |
| 3201 | case 0x297: /* STFSX */ |
| 3202 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3203 | UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword |
| 3204 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] |
| 3205 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3206 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 3207 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3208 | return TRUE; |
| 3209 | |
| 3210 | case 0x3d7: /* STFIWX */ |
| 3211 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3212 | UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3213 | UML_MOV(block, IREG(1), MEM((UINT32 *)&ppc->impstate->tempdata + BYTE_XOR_LE(0)));// mov i1,[tempdata.lo] |
| 3214 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3215 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 3216 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3217 | return TRUE; |
| 3218 | |
| 3219 | case 0x2d7: /* STFDX */ |
| 3220 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3221 | UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3222 | UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] |
| 3223 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3224 | UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 |
| 3225 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3226 | return TRUE; |
| 3227 | |
| 3228 | case 0x396: /* STHBRX */ |
| 3229 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3230 | UML_BSWAP(block, IREG(1), R32(G_RS(op))); // bswap i1,rs |
| 3231 | UML_SHR(block, IREG(1), IREG(1), IMM(16)); // shr i1,i1,16 |
| 3232 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3233 | UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 |
| 3234 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3235 | return TRUE; |
| 3236 | |
| 3237 | case 0x296: /* STWBRX */ |
| 3238 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3239 | UML_BSWAP(block, IREG(1), R32(G_RS(op))); // bswap i1,rs |
| 3240 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3241 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 3242 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3243 | return TRUE; |
| 3244 | |
| 3245 | case 0x0f7: /* STBUX */ |
| 3246 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3247 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff |
| 3248 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3249 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3250 | UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 |
| 3251 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3252 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3253 | return TRUE; |
| 3254 | |
| 3255 | case 0x1b7: /* STHUX */ |
| 3256 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3257 | UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff |
| 3258 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3259 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3260 | UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 |
| 3261 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3262 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3263 | return TRUE; |
| 3264 | |
| 3265 | case 0x0b7: /* STWUX */ |
| 3266 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3267 | UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs |
| 3268 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3269 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) |
| 3270 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 3271 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3272 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3273 | return TRUE; |
| 3274 | |
| 3275 | case 0x2b7: /* STFSUX */ |
| 3276 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3277 | UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword |
| 3278 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] |
| 3279 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3280 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3281 | UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 |
| 3282 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3283 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3284 | return TRUE; |
| 3285 | |
| 3286 | case 0x2f7: /* STFDUX */ |
| 3287 | UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3288 | UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs |
| 3289 | UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] |
| 3290 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 |
| 3291 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3292 | UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 |
| 3293 | UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] |
| 3294 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3295 | return TRUE; |
| 3296 | |
| 3297 | case 0x096: /* STWCX. */ |
| 3298 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3299 | UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs |
| 3300 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3301 | UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode & 3]); // callh write32align |
| 3302 | UML_AND(block, IREG(0), CR32, IMM(~CRMASK(0))); // and i0,cr,~crmask(0) |
| 3303 | UML_ROLINS(block, IREG(0), SPR32(SPR_XER), IMM(29), IMM(0x10000000)); // rolins i0,[xer],29,0x10000000 |
| 3304 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3305 | return TRUE; |
| 3306 | |
| 3307 | case 0x2d5: /* STSWI */ |
| 3308 | UML_MOV(block, MEM(&ppc->impstate->swcount), IMM(((G_NB(op) - 1) & 0x1f) + 1)); // mov [swcount],[xer],G_NB |
| 3309 | UML_MOV(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra |
| 3310 | UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RS(op))); // mov [swreg],4*G_RS(op) |
| 3311 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3312 | save_fast_iregs(block); // <save fastregs> |
| 3313 | UML_LABEL(block, swloop = compiler->labelnum++); // swloop: |
| 3314 | UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] |
| 3315 | UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 |
| 3316 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] |
| 3317 | UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 |
| 3318 | UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f |
| 3319 | UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) |
| 3320 | UML_LOAD(block, IREG(1), &ppc->r[0], IREG(1), BYTE); // load i1,&r0,i1,byte |
| 3321 | UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 |
| 3322 | UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); |
| 3323 | // sub [swcount],[swcount],1,Z |
| 3324 | UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ |
| 3325 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3326 | return TRUE; |
| 3327 | |
| 3328 | case 0x295: /* STSWX */ |
| 3329 | UML_ANDf(block, FLAGS_Z, MEM(&ppc->impstate->swcount), SPR32(SPR_XER), IMM(0x7f));// and [swcount],[xer],0x7f,Z |
| 3330 | UML_JMPc(block, IF_Z, swloopend = compiler->labelnum++); // jmp swloopend,Z |
| 3331 | UML_ADD(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb |
| 3332 | UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RS(op))); // mov [swreg],4*G_RS(op) |
| 3333 | UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) |
| 3334 | save_fast_iregs(block); // <save fastregs> |
| 3335 | UML_LABEL(block, swloop = compiler->labelnum++); // swloop: |
| 3336 | UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] |
| 3337 | UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 |
| 3338 | UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] |
| 3339 | UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 |
| 3340 | UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f |
| 3341 | UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) |
| 3342 | UML_LOAD(block, IREG(1), &ppc->r[0], IREG(1), BYTE); // load i1,&r0,i1,byte |
| 3343 | UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 |
| 3344 | UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); |
| 3345 | // sub [swcount],[swcount],1,Z |
| 3346 | UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ |
| 3347 | UML_LABEL(block, swloopend); // swloopend: |
| 3348 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3349 | return TRUE; |
| 3350 | |
| 3351 | case 0x1b6: /* ECOWX */ |
| 3352 | /* not implemented */ |
| 3353 | return FALSE; |
| 3354 | |
| 3355 | case 0x036: /* DCBST */ |
| 3356 | case 0x056: /* DCBF */ |
| 3357 | case 0x0f6: /* DCBTST */ |
| 3358 | case 0x116: /* DCBT */ |
| 3359 | case 0x3d6: /* ICBI */ |
| 3360 | case 0x256: /* SYNC */ |
| 3361 | case 0x356: /* EIEIO */ |
| 3362 | case 0x1d6: /* DCBI */ |
| 3363 | case 0x236: /* TLBSYNC */ |
| 3364 | /* effective no-ops */ |
| 3365 | return TRUE; |
| 3366 | |
| 3367 | case 0x3f6: /* DCBZ */ |
| 3368 | UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb |
| 3369 | UML_AND(block, MEM(&ppc->impstate->tempaddr), IREG(0), IMM(~(ppc->cache_line_size - 1))); |
| 3370 | // and [tempaddr],i0,~(cache_line_size - 1) |
| 3371 | for (item = 0; item < ppc->cache_line_size / 8; item++) |
| 3372 | { |
| 3373 | UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(8 * item)); // add i0,[tempaddr],8*item |
| 3374 | UML_DMOV(block, IREG(1), IMM(0)); // dmov i1,0 |
| 3375 | UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 |
| 3376 | } |
| 3377 | return TRUE; |
| 3378 | |
| 3379 | case 0x132: /* TLBIE */ |
| 3380 | UML_MOV(block, MEM(&ppc->param0), R32(G_RB(op))); // mov [param0],rb |
| 3381 | UML_CALLC(block, ppccom_execute_tlbie, ppc); // callc ppccom_execute_tlbie,ppc |
| 3382 | return TRUE; |
| 3383 | |
| 3384 | case 0x172: /* TLBIA */ |
| 3385 | UML_CALLC(block, ppccom_execute_tlbia, ppc); // callc ppccom_execute_tlbia,ppc |
| 3386 | return TRUE; |
| 3387 | |
| 3388 | case 0x3d2: /* TLBLD */ |
| 3389 | assert(ppc->cap & PPCCAP_603_MMU); |
| 3390 | UML_MOV(block, MEM(&ppc->param0), R32(G_RB(op))); // mov [param0],rb |
| 3391 | UML_MOV(block, MEM(&ppc->param1), IMM(0)); // mov [param1],0 |
| 3392 | UML_CALLC(block, ppccom_execute_tlbl, ppc); // callc ppccom_execute_tlbl,ppc |
| 3393 | return TRUE; |
| 3394 | |
| 3395 | case 0x3f2: /* TLBLI */ |
| 3396 | assert(ppc->cap & PPCCAP_603_MMU); |
| 3397 | UML_MOV(block, MEM(&ppc->param0), R32(G_RB(op))); // mov [param0],rb |
| 3398 | UML_MOV(block, MEM(&ppc->param1), IMM(1)); // mov [param1],1 |
| 3399 | UML_CALLC(block, ppccom_execute_tlbl, ppc); // callc ppccom_execute_tlbl,ppc |
| 3400 | return TRUE; |
| 3401 | |
| 3402 | case 0x013: /* MFCR */ |
| 3403 | UML_MOV(block, R32(G_RD(op)), CR32); // mov rd,cr |
| 3404 | return TRUE; |
| 3405 | |
| 3406 | case 0x053: /* MFMSR */ |
| 3407 | UML_MOV(block, R32(G_RD(op)), MSR32); // mov rd,msr |
| 3408 | return TRUE; |
| 3409 | |
| 3410 | case 0x153: /* MFSPR */ |
| 1587 | 3411 | { |
| 1588 | | ppc.irq_callback(irqline); |
| 3412 | UINT32 spr = compute_spr(G_SPR(op)); |
| 3413 | if (spr == SPR_LR || spr == SPR_CTR || spr == SPR_XER || (spr >= SPROEA_SPRG0 && spr <= SPROEA_SPRG3)) |
| 3414 | UML_MOV(block, R32(G_RD(op)), SPR32(spr)); // mov rd,spr |
| 3415 | else if (spr == SPROEA_PVR) |
| 3416 | UML_MOV(block, R32(G_RD(op)), IMM(ppc->flavor)); // mov rd,flavor |
| 3417 | else |
| 3418 | { |
| 3419 | generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> |
| 3420 | UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr |
| 3421 | UML_CALLC(block, ppccom_execute_mfspr, ppc); // callc ppccom_execute_mfspr,ppc |
| 3422 | UML_MOV(block, R32(G_RD(op)), MEM(&ppc->param1)); // mov rd,[param1] |
| 3423 | } |
| 3424 | return TRUE; |
| 1589 | 3425 | } |
| 1590 | | } |
| 1591 | | } |
| 1592 | | #endif |
| 1593 | 3426 | |
| 1594 | | #if (HAS_MPC8240) |
| 1595 | | static void mpc8240drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 1596 | | { |
| 1597 | | float multiplier; |
| 1598 | | const ppc_config *config = _config; |
| 1599 | | int i; |
| 3427 | case 0x253: /* MFSR */ |
| 3428 | UML_MOV(block, R32(G_RD(op)), SR32(G_SR(op))); // mov rd,sr |
| 3429 | return TRUE; |
| 1600 | 3430 | |
| 1601 | | ppc_init(); |
| 1602 | | ppcdrc_init(); |
| 3431 | case 0x293: /* MFSRIN */ |
| 3432 | UML_SHR(block, IREG(0), R32(G_RB(op)), IMM(28)); // shr i0,G_RB,28 |
| 3433 | UML_LOAD(block, R32(G_RD(op)), &ppc->sr[0], IREG(0), DWORD); // load rd,sr,i0,dword |
| 3434 | return TRUE; |
| 1603 | 3435 | |
| 1604 | | ppc.optable[48] = recompile_lfs; |
| 1605 | | ppc.optable[49] = recompile_lfsu; |
| 1606 | | ppc.optable[50] = recompile_lfd; |
| 1607 | | ppc.optable[51] = recompile_lfdu; |
| 1608 | | ppc.optable[52] = recompile_stfs; |
| 1609 | | ppc.optable[53] = recompile_stfsu; |
| 1610 | | ppc.optable[54] = recompile_stfd; |
| 1611 | | ppc.optable[55] = recompile_stfdu; |
| 1612 | | ppc.optable31[631] = recompile_lfdux; |
| 1613 | | ppc.optable31[599] = recompile_lfdx; |
| 1614 | | ppc.optable31[567] = recompile_lfsux; |
| 1615 | | ppc.optable31[535] = recompile_lfsx; |
| 1616 | | ppc.optable31[595] = recompile_mfsr; |
| 1617 | | ppc.optable31[659] = recompile_mfsrin; |
| 1618 | | ppc.optable31[371] = recompile_mftb; |
| 1619 | | ppc.optable31[210] = recompile_mtsr; |
| 1620 | | ppc.optable31[242] = recompile_mtsrin; |
| 1621 | | ppc.optable31[758] = recompile_dcba; |
| 1622 | | ppc.optable31[759] = recompile_stfdux; |
| 1623 | | ppc.optable31[727] = recompile_stfdx; |
| 1624 | | ppc.optable31[983] = recompile_stfiwx; |
| 1625 | | ppc.optable31[695] = recompile_stfsux; |
| 1626 | | ppc.optable31[663] = recompile_stfsx; |
| 1627 | | ppc.optable31[370] = recompile_tlbia; |
| 1628 | | ppc.optable31[306] = recompile_tlbie; |
| 1629 | | ppc.optable31[566] = recompile_tlbsync; |
| 1630 | | ppc.optable31[310] = recompile_eciwx; |
| 1631 | | ppc.optable31[438] = recompile_ecowx; |
| 3436 | case 0x173: /* MFTB */ |
| 3437 | { |
| 3438 | UINT32 tbr = compute_spr(G_SPR(op)); |
| 3439 | if (tbr != SPRVEA_TBL_R && tbr != SPRVEA_TBU_R) |
| 3440 | return FALSE; |
| 3441 | generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> |
| 3442 | UML_MOV(block, MEM(&ppc->param0), IMM(tbr)); // mov [param0],tbr |
| 3443 | UML_CALLC(block, ppccom_execute_mftb, ppc); // callc ppccom_execute_mftb,ppc |
| 3444 | UML_MOV(block, R32(G_RD(op)), MEM(&ppc->param1)); // mov rd,[param1] |
| 3445 | return TRUE; |
| 3446 | } |
| 1632 | 3447 | |
| 1633 | | ppc.optable63[264] = recompile_fabsx; |
| 1634 | | ppc.optable63[21] = recompile_faddx; |
| 1635 | | ppc.optable63[32] = recompile_fcmpo; |
| 1636 | | ppc.optable63[0] = recompile_fcmpu; |
| 1637 | | ppc.optable63[14] = recompile_fctiwx; |
| 1638 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1639 | | ppc.optable63[18] = recompile_fdivx; |
| 1640 | | ppc.optable63[72] = recompile_fmrx; |
| 1641 | | ppc.optable63[136] = recompile_fnabsx; |
| 1642 | | ppc.optable63[40] = recompile_fnegx; |
| 1643 | | ppc.optable63[12] = recompile_frspx; |
| 1644 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1645 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1646 | | ppc.optable63[20] = recompile_fsubx; |
| 1647 | | ppc.optable63[583] = recompile_mffsx; |
| 1648 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1649 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1650 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1651 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1652 | | ppc.optable63[64] = recompile_mcrfs; |
| 3448 | case 0x090: /* MTCRF */ |
| 3449 | UML_ROLINS(block, CR32, R32(G_RS(op)), IMM(0), IMM(compute_crf_mask(G_CRM(op))));// rolins cr,rs,0,G_CRM |
| 3450 | return TRUE; |
| 1653 | 3451 | |
| 1654 | | ppc.optable59[21] = recompile_faddsx; |
| 1655 | | ppc.optable59[18] = recompile_fdivsx; |
| 1656 | | ppc.optable59[24] = recompile_fresx; |
| 1657 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1658 | | ppc.optable59[20] = recompile_fsubsx; |
| 3452 | case 0x092: /* MTMSR */ |
| 3453 | if (ppc->cap & PPCCAP_603_MMU) |
| 3454 | UML_XOR(block, IREG(0), MSR32, R32(G_RS(op))); // xor i0,msr32,rs |
| 3455 | UML_MOV(block, MSR32, R32(G_RS(op))); // mov msr,rs |
| 3456 | if (ppc->cap & PPCCAP_603_MMU) |
| 3457 | { |
| 3458 | UML_TEST(block, IREG(0), IMM(MSR603_TGPR)); // test i0,tgpr |
| 3459 | UML_CALLHc(block, IF_NZ, ppc->impstate->swap_tgpr); // callh swap_tgpr,nz |
| 3460 | } |
| 3461 | generate_update_mode(block); // <update mode> |
| 3462 | return TRUE; |
| 1659 | 3463 | |
| 1660 | | for(i = 0; i < 32; i++) |
| 1661 | | { |
| 1662 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1663 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1664 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1665 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1666 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1667 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 3464 | case 0x1d3: /* MTSPR */ |
| 3465 | { |
| 3466 | UINT32 spr = compute_spr(G_SPR(op)); |
| 3467 | if (spr == SPR_LR || spr == SPR_CTR || spr == SPR_XER || (spr >= SPROEA_SPRG0 && spr <= SPROEA_SPRG3)) |
| 3468 | UML_MOV(block, SPR32(spr), R32(G_RS(op))); // mov spr,rs |
| 3469 | else if (spr == SPROEA_PVR) |
| 3470 | ; // read only |
| 3471 | else |
| 3472 | { |
| 3473 | generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> |
| 3474 | UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr |
| 3475 | UML_MOV(block, MEM(&ppc->param1), R32(G_RS(op))); // mov [param1],rs |
| 3476 | UML_CALLC(block, ppccom_execute_mtspr, ppc); // callc ppccom_execute_mtspr,ppc |
| 3477 | compiler->checkints = TRUE; |
| 3478 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3479 | } |
| 3480 | return TRUE; |
| 3481 | } |
| 1668 | 3482 | |
| 1669 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1670 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1671 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1672 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1673 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1674 | | } |
| 3483 | case 0x0d2: /* MTSR */ |
| 3484 | UML_MOV(block, SR32(G_SR(op)), R32(G_RS(op))); // mov sr[G_SR],rs |
| 3485 | UML_CALLC(block, ppccom_tlb_flush, ppc); // callc ppccom_tlb_flush,ppc |
| 3486 | return TRUE; |
| 1675 | 3487 | |
| 1676 | | for(i = 0; i < 256; i++) |
| 1677 | | { |
| 1678 | | ppc_field_xlat[i] = |
| 1679 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1680 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1681 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1682 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1683 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1684 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1685 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1686 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1687 | | } |
| 3488 | case 0x0f2: /* MTSRIN */ |
| 3489 | UML_SHR(block, IREG(0), R32(G_RB(op)), IMM(28)); // shr i0,G_RB,28 |
| 3490 | UML_STORE(block, &ppc->sr[0], IREG(0), R32(G_RS(op)), DWORD); // store sr,i0,rs,dword |
| 3491 | UML_CALLC(block, ppccom_tlb_flush, ppc); // callc ppccom_tlb_flush,ppc |
| 3492 | return TRUE; |
| 1688 | 3493 | |
| 1689 | | // MPC8240 specific opcodes |
| 1690 | | ppc.optable31[978] = recompile_tlbld; |
| 1691 | | ppc.optable31[1010] = recompile_tlbli; |
| 3494 | case 0x200: /* MCRXR */ |
| 3495 | UML_ROLINS(block, CR32, SPR32(SPR_XER), IMM(32 - 4 * G_CRFD(op)), IMM(CRMASK(G_CRFD(op)))); |
| 3496 | // rolins cr,[xer],32-4*crfd,crmask(crfd) |
| 3497 | UML_AND(block, SPR32(SPR_XER), SPR32(SPR_XER), IMM(~0xf0000000)); // and [xer],[xer],~0xf0000000 |
| 3498 | return TRUE; |
| 1692 | 3499 | |
| 1693 | | ppc.is603 = 1; |
| 3500 | case 0x106: /* ICBT */ |
| 3501 | case 0x1c6: /* DCCCI */ |
| 3502 | case 0x3c6: /* ICCCI */ |
| 3503 | assert(ppc->cap & PPCCAP_4XX); |
| 3504 | /* effective no-nop */ |
| 3505 | return TRUE; |
| 1694 | 3506 | |
| 1695 | | ppc.read8 = program_read_byte_64be; |
| 1696 | | ppc.read16 = program_read_word_64be; |
| 1697 | | ppc.read32 = program_read_dword_64be; |
| 1698 | | ppc.read64 = program_read_qword_64be; |
| 1699 | | ppc.write8 = program_write_byte_64be; |
| 1700 | | ppc.write16 = program_write_word_64be; |
| 1701 | | ppc.write32 = program_write_dword_64be; |
| 1702 | | ppc.write64 = program_write_qword_64be; |
| 1703 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1704 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1705 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1706 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1707 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1708 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 3507 | case 0x1e6: /* DCREAD */ |
| 3508 | case 0x3e6: /* ICREAD */ |
| 3509 | assert(ppc->cap & PPCCAP_4XX); |
| 3510 | UML_MOV(block, R32(G_RT(op)), IMM(0)); // mov rt,0 |
| 3511 | return TRUE; |
| 1709 | 3512 | |
| 1710 | | ppc.irq_callback = irqcallback; |
| 3513 | case 0x143: /* MFDCR */ |
| 3514 | { |
| 3515 | UINT32 spr = compute_spr(G_SPR(op)); |
| 3516 | assert(ppc->cap & PPCCAP_4XX); |
| 3517 | generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> |
| 3518 | UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr |
| 3519 | UML_CALLC(block, ppccom_execute_mfdcr, ppc); // callc ppccom_execute_mfdcr,ppc |
| 3520 | UML_MOV(block, R32(G_RD(op)), MEM(&ppc->param1)); // mov rd,[param1] |
| 3521 | return TRUE; |
| 3522 | } |
| 1711 | 3523 | |
| 1712 | | ppc.pvr = config->pvr; |
| 3524 | case 0x1c3: /* MTDCR */ |
| 3525 | { |
| 3526 | UINT32 spr = compute_spr(G_SPR(op)); |
| 3527 | assert(ppc->cap & PPCCAP_4XX); |
| 3528 | generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> |
| 3529 | UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr |
| 3530 | UML_MOV(block, MEM(&ppc->param1), R32(G_RS(op))); // mov [param1],rs |
| 3531 | UML_CALLC(block, ppccom_execute_mtdcr, ppc); // callc ppccom_execute_mtdcr,ppc |
| 3532 | compiler->checkints = TRUE; |
| 3533 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3534 | return TRUE; |
| 3535 | } |
| 1713 | 3536 | |
| 1714 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1715 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1716 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 1717 | | } |
| 3537 | case 0x083: /* WRTEE */ |
| 3538 | assert(ppc->cap & PPCCAP_4XX); |
| 3539 | UML_ROLINS(block, MSR32, R32(G_RS(op)), IMM(0), IMM(MSR_EE)); // rolins msr,rs,0,MSR_EE |
| 3540 | compiler->checkints = TRUE; |
| 3541 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3542 | return TRUE; |
| 1718 | 3543 | |
| 1719 | | static void mpc8240drc_exit(void) |
| 1720 | | { |
| 1721 | | ppcdrc_exit(); |
| 3544 | case 0x0a3: /* WRTEEI */ |
| 3545 | assert(ppc->cap & PPCCAP_4XX); |
| 3546 | if (op & MSR_EE) |
| 3547 | { |
| 3548 | UML_OR(block, MSR32, MSR32, IMM(MSR_EE)); // or msr,msr,MSR_EE |
| 3549 | compiler->checkints = TRUE; |
| 3550 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> |
| 3551 | } |
| 3552 | else |
| 3553 | UML_AND(block, MSR32, MSR32, IMM(~MSR_EE)); // and msr,msr,~MSR_EE |
| 3554 | return TRUE; |
| 3555 | } |
| 3556 | |
| 3557 | return FALSE; |
| 1722 | 3558 | } |
| 1723 | | #endif |
| 1724 | 3559 | |
| 1725 | 3560 | |
| 1726 | | #if (HAS_PPC601) |
| 1727 | | static void ppc601drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 3561 | /*------------------------------------------------- |
| 3562 | generate_instruction_3b - compile opcodes in |
| 3563 | the 0x3b group |
| 3564 | -------------------------------------------------*/ |
| 3565 | |
| 3566 | static int generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 1728 | 3567 | { |
| 1729 | | int pll_config = 0; |
| 1730 | | float multiplier; |
| 1731 | | const ppc_config *config = _config; |
| 1732 | | int i; |
| 3568 | UINT32 op = *desc->opptr.l; |
| 3569 | UINT32 opswitch = (op >> 1) & 0x1f; |
| 1733 | 3570 | |
| 1734 | | ppc_init(); |
| 1735 | | ppcdrc_init(); |
| 3571 | switch (opswitch) |
| 3572 | { |
| 3573 | case 0x15: /* FADDSx */ |
| 3574 | UML_FDADD(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdadd f0,ra,rb |
| 3575 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3576 | return TRUE; |
| 1736 | 3577 | |
| 1737 | | ppc.optable[48] = recompile_lfs; |
| 1738 | | ppc.optable[49] = recompile_lfsu; |
| 1739 | | ppc.optable[50] = recompile_lfd; |
| 1740 | | ppc.optable[51] = recompile_lfdu; |
| 1741 | | ppc.optable[52] = recompile_stfs; |
| 1742 | | ppc.optable[53] = recompile_stfsu; |
| 1743 | | ppc.optable[54] = recompile_stfd; |
| 1744 | | ppc.optable[55] = recompile_stfdu; |
| 1745 | | ppc.optable31[631] = recompile_lfdux; |
| 1746 | | ppc.optable31[599] = recompile_lfdx; |
| 1747 | | ppc.optable31[567] = recompile_lfsux; |
| 1748 | | ppc.optable31[535] = recompile_lfsx; |
| 1749 | | ppc.optable31[595] = recompile_mfsr; |
| 1750 | | ppc.optable31[659] = recompile_mfsrin; |
| 1751 | | ppc.optable31[371] = recompile_mftb; |
| 1752 | | ppc.optable31[210] = recompile_mtsr; |
| 1753 | | ppc.optable31[242] = recompile_mtsrin; |
| 1754 | | ppc.optable31[758] = recompile_dcba; |
| 1755 | | ppc.optable31[759] = recompile_stfdux; |
| 1756 | | ppc.optable31[727] = recompile_stfdx; |
| 1757 | | ppc.optable31[983] = recompile_stfiwx; |
| 1758 | | ppc.optable31[695] = recompile_stfsux; |
| 1759 | | ppc.optable31[663] = recompile_stfsx; |
| 1760 | | ppc.optable31[370] = recompile_tlbia; |
| 1761 | | ppc.optable31[306] = recompile_tlbie; |
| 1762 | | ppc.optable31[566] = recompile_tlbsync; |
| 1763 | | ppc.optable31[310] = recompile_eciwx; |
| 1764 | | ppc.optable31[438] = recompile_ecowx; |
| 3578 | case 0x14: /* FSUBSx */ |
| 3579 | UML_FDSUB(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdsub f0,ra,rb |
| 3580 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3581 | return TRUE; |
| 1765 | 3582 | |
| 1766 | | ppc.optable63[264] = recompile_fabsx; |
| 1767 | | ppc.optable63[21] = recompile_faddx; |
| 1768 | | ppc.optable63[32] = recompile_fcmpo; |
| 1769 | | ppc.optable63[0] = recompile_fcmpu; |
| 1770 | | ppc.optable63[14] = recompile_fctiwx; |
| 1771 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1772 | | ppc.optable63[18] = recompile_fdivx; |
| 1773 | | ppc.optable63[72] = recompile_fmrx; |
| 1774 | | ppc.optable63[136] = recompile_fnabsx; |
| 1775 | | ppc.optable63[40] = recompile_fnegx; |
| 1776 | | ppc.optable63[12] = recompile_frspx; |
| 1777 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1778 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1779 | | ppc.optable63[20] = recompile_fsubx; |
| 1780 | | ppc.optable63[583] = recompile_mffsx; |
| 1781 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1782 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1783 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1784 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1785 | | ppc.optable63[64] = recompile_mcrfs; |
| 3583 | case 0x19: /* FMULSx */ |
| 3584 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdmul f0,ra,rb |
| 3585 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3586 | return TRUE; |
| 1786 | 3587 | |
| 1787 | | ppc.optable59[21] = recompile_faddsx; |
| 1788 | | ppc.optable59[18] = recompile_fdivsx; |
| 1789 | | ppc.optable59[24] = recompile_fresx; |
| 1790 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1791 | | ppc.optable59[20] = recompile_fsubsx; |
| 3588 | case 0x12: /* FDIVSx */ |
| 3589 | UML_FDDIV(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fddiv f0,ra,rb |
| 3590 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3591 | return TRUE; |
| 1792 | 3592 | |
| 1793 | | for(i = 0; i < 32; i++) |
| 1794 | | { |
| 1795 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1796 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1797 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1798 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1799 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1800 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 3593 | case 0x16: /* FSQRTSx */ |
| 3594 | UML_FDSQRT(block, FREG(0), F64(G_RB(op))); // fdsqrt f0,rb |
| 3595 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3596 | return TRUE; |
| 1801 | 3597 | |
| 1802 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1803 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1804 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1805 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1806 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 3598 | case 0x18: /* FRESx */ |
| 3599 | UML_FSFRFLT(block, FREG(0), F64(G_RB(op)), QWORD); // fsfrlt f0,rb,qword |
| 3600 | UML_FSRECIP(block, FREG(0), FREG(0)); // fsrecip f0,f0 |
| 3601 | UML_FDFRFLT(block, F64(G_RD(op)), FREG(0), DWORD); // fdfrflt rd,f0,dword |
| 3602 | return TRUE; |
| 3603 | |
| 3604 | case 0x1d: /* FMADDSx */ |
| 3605 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3606 | UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb |
| 3607 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3608 | return TRUE; |
| 3609 | |
| 3610 | case 0x1c: /* FMSUBSx */ |
| 3611 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3612 | UML_FDSUB(block, FREG(0), FREG(0), F64(G_RB(op))); // fdsub f0,f0,rb |
| 3613 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3614 | return TRUE; |
| 3615 | |
| 3616 | case 0x1f: /* FNMADDSx */ |
| 3617 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3618 | UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb |
| 3619 | UML_FDNEG(block, FREG(0), FREG(0)); // fdneg f0,f0 |
| 3620 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3621 | return TRUE; |
| 3622 | |
| 3623 | case 0x1e: /* FNMSUBSx */ |
| 3624 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3625 | UML_FDSUB(block, FREG(0), F64(G_RB(op)), FREG(0)); // fdsub f0,rb,f0 |
| 3626 | UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 |
| 3627 | return TRUE; |
| 1807 | 3628 | } |
| 1808 | 3629 | |
| 1809 | | for(i = 0; i < 256; i++) |
| 3630 | return FALSE; |
| 3631 | } |
| 3632 | |
| 3633 | |
| 3634 | |
| 3635 | /*------------------------------------------------- |
| 3636 | generate_instruction_3f - compile opcodes in |
| 3637 | the 0x3f group |
| 3638 | -------------------------------------------------*/ |
| 3639 | |
| 3640 | static int generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) |
| 3641 | { |
| 3642 | UINT32 op = *desc->opptr.l; |
| 3643 | UINT32 opswitch = (op >> 1) & 0x3ff; |
| 3644 | |
| 3645 | if (opswitch & 0x10) |
| 1810 | 3646 | { |
| 1811 | | ppc_field_xlat[i] = |
| 1812 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1813 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1814 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1815 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1816 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1817 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1818 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1819 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1820 | | } |
| 3647 | opswitch &= 0x1f; |
| 3648 | switch (opswitch) |
| 3649 | { |
| 3650 | case 0x15: /* FADDx */ |
| 3651 | UML_FDADD(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdadd rd,ra,rb |
| 3652 | return TRUE; |
| 1821 | 3653 | |
| 1822 | | ppc.is603 = 1; |
| 3654 | case 0x14: /* FSUBx */ |
| 3655 | UML_FDSUB(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdsub rd,ra,rb |
| 3656 | return TRUE; |
| 1823 | 3657 | |
| 1824 | | ppc.read8 = program_read_byte_64be; |
| 1825 | | ppc.read16 = program_read_word_64be; |
| 1826 | | ppc.read32 = program_read_dword_64be; |
| 1827 | | ppc.read64 = program_read_qword_64be; |
| 1828 | | ppc.write8 = program_write_byte_64be; |
| 1829 | | ppc.write16 = program_write_word_64be; |
| 1830 | | ppc.write32 = program_write_dword_64be; |
| 1831 | | ppc.write64 = program_write_qword_64be; |
| 1832 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1833 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1834 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1835 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1836 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1837 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 3658 | case 0x19: /* FMULx */ |
| 3659 | UML_FDMUL(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdmul rd,ra,rb |
| 3660 | return TRUE; |
| 1838 | 3661 | |
| 1839 | | ppc.irq_callback = irqcallback; |
| 3662 | case 0x12: /* FDIVx */ |
| 3663 | UML_FDDIV(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fddiv rd,ra,rb |
| 3664 | return TRUE; |
| 1840 | 3665 | |
| 1841 | | ppc.pvr = config->pvr; |
| 3666 | case 0x16: /* FSQRTx */ |
| 3667 | UML_FDSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdsqrt rd,rb |
| 3668 | return TRUE; |
| 1842 | 3669 | |
| 1843 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1844 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1845 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 3670 | case 0x1a: /* FRSQRTEx */ |
| 3671 | UML_FDRSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdrsqrt rd,rb |
| 3672 | return TRUE; |
| 1846 | 3673 | |
| 1847 | | switch(config->pvr) |
| 3674 | case 0x17: /* FSELx */ |
| 3675 | UML_FDCMP(block, F64(G_RA(op)), MEM(&ppc->impstate->fp0)); // fdcmp f0,ra,[fp0] |
| 3676 | UML_FDMOVc(block, IF_AE, F64(G_RD(op)), F64(G_REGC(op))); // fdmov rd,rc,AE |
| 3677 | UML_FDMOVc(block, IF_B, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb,B |
| 3678 | return TRUE; |
| 3679 | |
| 3680 | case 0x1d: /* FMADDx */ |
| 3681 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3682 | UML_FDADD(block, F64(G_RD(op)), FREG(0), F64(G_RB(op))); // fdadd rd,f0,rb |
| 3683 | return TRUE; |
| 3684 | |
| 3685 | case 0x1f: /* FNMADDx */ |
| 3686 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3687 | UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb |
| 3688 | UML_FDNEG(block, F64(G_RD(op)), FREG(0)); // fdneg rd,f0 |
| 3689 | return TRUE; |
| 3690 | |
| 3691 | case 0x1c: /* FMSUBx */ |
| 3692 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3693 | UML_FDSUB(block, F64(G_RD(op)), FREG(0), F64(G_RB(op))); // fdsub rd,f0,rb |
| 3694 | return TRUE; |
| 3695 | |
| 3696 | case 0x1e: /* FNMSUBx */ |
| 3697 | UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc |
| 3698 | UML_FDSUB(block, F64(G_RD(op)), F64(G_RB(op)), FREG(0)); // fdsub rd,rb,f0 |
| 3699 | return TRUE; |
| 3700 | } |
| 3701 | } |
| 3702 | else |
| 1848 | 3703 | { |
| 1849 | | case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1850 | | case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1851 | | case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; |
| 1852 | | default: break; |
| 1853 | | } |
| 3704 | switch (opswitch) |
| 3705 | { |
| 3706 | case 0x32e: /* FCTIDx - 64-bit only */ |
| 3707 | case 0x32f: /* FCTIDZx - 64-bit only */ |
| 3708 | case 0x34e: /* FCFIDx - 64-bit only */ |
| 3709 | return FALSE; |
| 1854 | 3710 | |
| 1855 | | if (pll_config == -1) |
| 1856 | | { |
| 1857 | | fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); |
| 3711 | case 0x000: /* FCMPU */ |
| 3712 | case 0x020: /* FCMPO */ |
| 3713 | UML_FDCMP(block, F64(G_RA(op)), F64(G_RB(op))); // fdcmp ra,rb |
| 3714 | UML_GETFLGS(block, IREG(0), DRCUML_FLAG_C | DRCUML_FLAG_Z | DRCUML_FLAG_U); // getflgs i0,czu |
| 3715 | UML_LOAD(block, IREG(0), ppc->impstate->fcmp_cr_table, IREG(0), DWORD); // load i0,fcmp_cr_table,i0,dword |
| 3716 | UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] |
| 3717 | return TRUE; |
| 3718 | |
| 3719 | case 0x00c: /* FRSPx */ |
| 3720 | UML_FDRNDS(block, F64(G_RD(op)), F64(G_RB(op))); // fdrnds rd,rb |
| 3721 | return TRUE; |
| 3722 | |
| 3723 | case 0x00e: /* FCTIWx */ |
| 3724 | UML_FDTOINT(block, IREG(0), F64(G_RB(op)), DWORD, DEFAULT); // fdtoint i0,rb,dword,default |
| 3725 | UML_DAND(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(0xffffffff)); // dand i0,i0,0xffffffff |
| 3726 | UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmovr rd,i0 |
| 3727 | return TRUE; |
| 3728 | |
| 3729 | case 0x00f: /* FCTIWZx */ |
| 3730 | UML_FDTOINT(block, IREG(0), F64(G_RB(op)), DWORD, TRUNC); // fdtoint i0,rb,dword,default |
| 3731 | UML_DAND(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(0xffffffff)); // dand i0,i0,0xffffffff |
| 3732 | UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmovr rd,i0 |
| 3733 | return TRUE; |
| 3734 | |
| 3735 | case 0x028: /* FNEGx */ |
| 3736 | UML_FDNEG(block, F64(G_RD(op)), F64(G_RB(op))); // fdneg rd,rb |
| 3737 | return TRUE; |
| 3738 | |
| 3739 | case 0x048: /* FMRx */ |
| 3740 | UML_FDMOV(block, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb |
| 3741 | return TRUE; |
| 3742 | |
| 3743 | case 0x088: /* FNABSx */ |
| 3744 | UML_FDABS(block, FREG(0), F64(G_RB(op))); // fdabs f0,rb |
| 3745 | UML_FDNEG(block, F64(G_RD(op)), FREG(0)); // fdneg rd,f0 |
| 3746 | return TRUE; |
| 3747 | |
| 3748 | case 0x108: /* FABSx */ |
| 3749 | UML_FDABS(block, F64(G_RD(op)), F64(G_RB(op))); // fdabs rd,rb |
| 3750 | return TRUE; |
| 3751 | |
| 3752 | case 0x046: /* MTFSB0x */ |
| 3753 | UML_AND(block, FPSCR32, FPSCR32, IMM(~(0x80000000 >> G_CRBD(op)))); // and fpscr32,fpscr32,~(0x80000000 >> G_CRBD) |
| 3754 | return TRUE; |
| 3755 | |
| 3756 | case 0x026: /* MTFSB1x */ |
| 3757 | UML_OR(block, FPSCR32, FPSCR32, IMM(0x80000000 >> G_CRBD(op))); // or fpscr32,fpscr32,(0x80000000 >> G_CRBD) |
| 3758 | return TRUE; |
| 3759 | |
| 3760 | case 0x040: /* MCRFS */ |
| 3761 | UML_ROLINS(block, CR32, FPSCR32, IMM(((G_CRFS(op) - G_CRFD(op)) & 7) * 4), IMM(CRMASK(G_CRFD(op)))); |
| 3762 | // rolins cr,fpscr,shift,crmask[crfd] |
| 3763 | UML_AND(block, FPSCR32, FPSCR32, IMM(~CRMASK(G_CRFS(op)))); // and fpscr,fpscr,~crmask[crfs] |
| 3764 | return TRUE; |
| 3765 | |
| 3766 | case 0x247: /* MFFSx */ |
| 3767 | UML_MOV(block, R32(G_RD(op)), FPSCR32); // mov rd,fpscr |
| 3768 | return TRUE; |
| 3769 | |
| 3770 | case 0x2c7: /* MTFSFx */ |
| 3771 | UML_ROLINS(block, FPSCR32, R32(G_RB(op)), IMM(0), IMM(compute_crf_mask(G_FM(op)))); |
| 3772 | // rolins fpscr,rb,0,crf_mask |
| 3773 | return TRUE; |
| 3774 | |
| 3775 | case 0x086: /* MTFSFIx */ |
| 3776 | UML_ROLINS(block, FPSCR32, R32(G_IMM(op)), IMM(28 - 4 * G_CRFD(op)), IMM(CRMASK(G_CRFD(op)))); |
| 3777 | // rolins fpscr,rb,0,crf_mask |
| 3778 | return TRUE; |
| 3779 | } |
| 1858 | 3780 | } |
| 1859 | 3781 | |
| 1860 | | ppc.hid1 = pll_config << 28; |
| 3782 | return FALSE; |
| 1861 | 3783 | } |
| 1862 | 3784 | |
| 1863 | | static void ppc601drc_exit(void) |
| 3785 | |
| 3786 | |
| 3787 | /*************************************************************************** |
| 3788 | CODE LOGGING HELPERS |
| 3789 | ***************************************************************************/ |
| 3790 | |
| 3791 | /*------------------------------------------------- |
| 3792 | log_add_disasm_comment - add a comment |
| 3793 | including disassembly of a PowerPC instruction |
| 3794 | -------------------------------------------------*/ |
| 3795 | |
| 3796 | static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) |
| 1864 | 3797 | { |
| 1865 | | #if LOG_CODE |
| 1866 | | //if (symfile) fclose(symfile); |
| 3798 | #if (LOG_UML) |
| 3799 | char buffer[100]; |
| 3800 | ppc_dasm_one(buffer, pc, op); |
| 3801 | UML_COMMENT(block, "%08X: %s", pc, buffer); // comment |
| 1867 | 3802 | #endif |
| 1868 | | ppcdrc_exit(); |
| 1869 | 3803 | } |
| 1870 | | #endif |
| 1871 | 3804 | |
| 1872 | 3805 | |
| 1873 | | #if (HAS_PPC604) |
| 1874 | | static void ppc604drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) |
| 3806 | /*------------------------------------------------- |
| 3807 | log_desc_flags_to_string - generate a string |
| 3808 | representing the instruction description |
| 3809 | flags |
| 3810 | -------------------------------------------------*/ |
| 3811 | |
| 3812 | static const char *log_desc_flags_to_string(UINT32 flags) |
| 1875 | 3813 | { |
| 1876 | | float multiplier; |
| 1877 | | const ppc_config *config = _config; |
| 1878 | | int i; |
| 3814 | static char tempbuf[30]; |
| 3815 | char *dest = tempbuf; |
| 1879 | 3816 | |
| 1880 | | ppc_init(); |
| 1881 | | ppcdrc_init(); |
| 3817 | /* branches */ |
| 3818 | if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH) |
| 3819 | *dest++ = 'U'; |
| 3820 | else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH) |
| 3821 | *dest++ = 'C'; |
| 3822 | else |
| 3823 | *dest++ = '.'; |
| 1882 | 3824 | |
| 1883 | | ppc.optable[48] = recompile_lfs; |
| 1884 | | ppc.optable[49] = recompile_lfsu; |
| 1885 | | ppc.optable[50] = recompile_lfd; |
| 1886 | | ppc.optable[51] = recompile_lfdu; |
| 1887 | | ppc.optable[52] = recompile_stfs; |
| 1888 | | ppc.optable[53] = recompile_stfsu; |
| 1889 | | ppc.optable[54] = recompile_stfd; |
| 1890 | | ppc.optable[55] = recompile_stfdu; |
| 1891 | | ppc.optable31[631] = recompile_lfdux; |
| 1892 | | ppc.optable31[599] = recompile_lfdx; |
| 1893 | | ppc.optable31[567] = recompile_lfsux; |
| 1894 | | ppc.optable31[535] = recompile_lfsx; |
| 1895 | | ppc.optable31[595] = recompile_mfsr; |
| 1896 | | ppc.optable31[659] = recompile_mfsrin; |
| 1897 | | ppc.optable31[371] = recompile_mftb; |
| 1898 | | ppc.optable31[210] = recompile_mtsr; |
| 1899 | | ppc.optable31[242] = recompile_mtsrin; |
| 1900 | | ppc.optable31[758] = recompile_dcba; |
| 1901 | | ppc.optable31[759] = recompile_stfdux; |
| 1902 | | ppc.optable31[727] = recompile_stfdx; |
| 1903 | | ppc.optable31[983] = recompile_stfiwx; |
| 1904 | | ppc.optable31[695] = recompile_stfsux; |
| 1905 | | ppc.optable31[663] = recompile_stfsx; |
| 1906 | | ppc.optable31[370] = recompile_tlbia; |
| 1907 | | ppc.optable31[306] = recompile_tlbie; |
| 1908 | | ppc.optable31[566] = recompile_tlbsync; |
| 1909 | | ppc.optable31[310] = recompile_eciwx; |
| 1910 | | ppc.optable31[438] = recompile_ecowx; |
| 3825 | /* intrablock branches */ |
| 3826 | *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.'; |
| 1911 | 3827 | |
| 1912 | | ppc.optable63[264] = recompile_fabsx; |
| 1913 | | ppc.optable63[21] = recompile_faddx; |
| 1914 | | ppc.optable63[32] = recompile_fcmpo; |
| 1915 | | ppc.optable63[0] = recompile_fcmpu; |
| 1916 | | ppc.optable63[14] = recompile_fctiwx; |
| 1917 | | ppc.optable63[15] = recompile_fctiwzx; |
| 1918 | | ppc.optable63[18] = recompile_fdivx; |
| 1919 | | ppc.optable63[72] = recompile_fmrx; |
| 1920 | | ppc.optable63[136] = recompile_fnabsx; |
| 1921 | | ppc.optable63[40] = recompile_fnegx; |
| 1922 | | ppc.optable63[12] = recompile_frspx; |
| 1923 | | ppc.optable63[26] = recompile_frsqrtex; |
| 1924 | | ppc.optable63[22] = recompile_fsqrtx; |
| 1925 | | ppc.optable63[20] = recompile_fsubx; |
| 1926 | | ppc.optable63[583] = recompile_mffsx; |
| 1927 | | ppc.optable63[70] = recompile_mtfsb0x; |
| 1928 | | ppc.optable63[38] = recompile_mtfsb1x; |
| 1929 | | ppc.optable63[711] = recompile_mtfsfx; |
| 1930 | | ppc.optable63[134] = recompile_mtfsfix; |
| 1931 | | ppc.optable63[64] = recompile_mcrfs; |
| 3828 | /* branch targets */ |
| 3829 | *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.'; |
| 1932 | 3830 | |
| 1933 | | ppc.optable59[21] = recompile_faddsx; |
| 1934 | | ppc.optable59[18] = recompile_fdivsx; |
| 1935 | | ppc.optable59[24] = recompile_fresx; |
| 1936 | | ppc.optable59[22] = recompile_fsqrtsx; |
| 1937 | | ppc.optable59[20] = recompile_fsubsx; |
| 3831 | /* delay slots */ |
| 3832 | *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.'; |
| 1938 | 3833 | |
| 1939 | | for(i = 0; i < 32; i++) |
| 1940 | | { |
| 1941 | | ppc.optable63[i * 32 | 29] = recompile_fmaddx; |
| 1942 | | ppc.optable63[i * 32 | 28] = recompile_fmsubx; |
| 1943 | | ppc.optable63[i * 32 | 25] = recompile_fmulx; |
| 1944 | | ppc.optable63[i * 32 | 31] = recompile_fnmaddx; |
| 1945 | | ppc.optable63[i * 32 | 30] = recompile_fnmsubx; |
| 1946 | | ppc.optable63[i * 32 | 23] = recompile_fselx; |
| 3834 | /* exceptions */ |
| 3835 | if (flags & OPFLAG_WILL_CAUSE_EXCEPTION) |
| 3836 | *dest++ = 'E'; |
| 3837 | else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION) |
| 3838 | *dest++ = 'e'; |
| 3839 | else |
| 3840 | *dest++ = '.'; |
| 1947 | 3841 | |
| 1948 | | ppc.optable59[i * 32 | 29] = recompile_fmaddsx; |
| 1949 | | ppc.optable59[i * 32 | 28] = recompile_fmsubsx; |
| 1950 | | ppc.optable59[i * 32 | 25] = recompile_fmulsx; |
| 1951 | | ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; |
| 1952 | | ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; |
| 1953 | | } |
| 3842 | /* read/write */ |
| 3843 | if (flags & OPFLAG_READS_MEMORY) |
| 3844 | *dest++ = 'R'; |
| 3845 | else if (flags & OPFLAG_WRITES_MEMORY) |
| 3846 | *dest++ = 'W'; |
| 3847 | else |
| 3848 | *dest++ = '.'; |
| 1954 | 3849 | |
| 1955 | | ppc.optable31[978] = recompile_tlbld; |
| 3850 | /* TLB validation */ |
| 3851 | *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.'; |
| 1956 | 3852 | |
| 1957 | | for(i = 0; i < 256; i++) |
| 1958 | | { |
| 1959 | | ppc_field_xlat[i] = |
| 1960 | | ((i & 0x80) ? 0xF0000000 : 0) | |
| 1961 | | ((i & 0x40) ? 0x0F000000 : 0) | |
| 1962 | | ((i & 0x20) ? 0x00F00000 : 0) | |
| 1963 | | ((i & 0x10) ? 0x000F0000 : 0) | |
| 1964 | | ((i & 0x08) ? 0x0000F000 : 0) | |
| 1965 | | ((i & 0x04) ? 0x00000F00 : 0) | |
| 1966 | | ((i & 0x02) ? 0x000000F0 : 0) | |
| 1967 | | ((i & 0x01) ? 0x0000000F : 0); |
| 1968 | | } |
| 3853 | /* TLB modification */ |
| 3854 | *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.'; |
| 1969 | 3855 | |
| 1970 | | ppc.is603 = 1; |
| 3856 | /* redispatch */ |
| 3857 | *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.'; |
| 3858 | return tempbuf; |
| 3859 | } |
| 1971 | 3860 | |
| 1972 | | ppc.read8 = program_read_byte_64be; |
| 1973 | | ppc.read16 = program_read_word_64be; |
| 1974 | | ppc.read32 = program_read_dword_64be; |
| 1975 | | ppc.read64 = program_read_qword_64be; |
| 1976 | | ppc.write8 = program_write_byte_64be; |
| 1977 | | ppc.write16 = program_write_word_64be; |
| 1978 | | ppc.write32 = program_write_dword_64be; |
| 1979 | | ppc.write64 = program_write_qword_64be; |
| 1980 | | ppc.read16_unaligned = ppc_read16_unaligned; |
| 1981 | | ppc.read32_unaligned = ppc_read32_unaligned; |
| 1982 | | ppc.read64_unaligned = ppc_read64_unaligned; |
| 1983 | | ppc.write16_unaligned = ppc_write16_unaligned; |
| 1984 | | ppc.write32_unaligned = ppc_write32_unaligned; |
| 1985 | | ppc.write64_unaligned = ppc_write64_unaligned; |
| 1986 | 3861 | |
| 1987 | | ppc.irq_callback = irqcallback; |
| 3862 | /*------------------------------------------------- |
| 3863 | log_register_list - log a list of GPR registers |
| 3864 | -------------------------------------------------*/ |
| 1988 | 3865 | |
| 1989 | | ppc.pvr = config->pvr; |
| 3866 | static void log_register_list(drcuml_state *drcuml, const char *string, UINT64 gprmask, UINT64 fprmask) |
| 3867 | { |
| 3868 | int count = 0; |
| 3869 | int regnum; |
| 1990 | 3870 | |
| 1991 | | multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + |
| 1992 | | (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; |
| 1993 | | bus_freq_multiplier = (int)(multiplier * 2); |
| 3871 | /* skip if nothing */ |
| 3872 | if ((gprmask & ~1) == 0 && fprmask == 0) |
| 3873 | return; |
| 3874 | |
| 3875 | drcuml_log_printf(drcuml, "[%s:", string); |
| 3876 | |
| 3877 | for (regnum = 0; regnum < 32; regnum++) |
| 3878 | if (gprmask & ((UINT64)1 << regnum)) |
| 3879 | drcuml_log_printf(drcuml, "%sr%d", (count++ == 0) ? "" : ",", regnum); |
| 3880 | for (regnum = 0; regnum < 8; regnum++) |
| 3881 | if (gprmask & ((UINT64)1 << (32 + regnum))) |
| 3882 | drcuml_log_printf(drcuml, "%scr%d", (count++ == 0) ? "" : ",", regnum); |
| 3883 | if (gprmask & ((UINT64)1 << 40)) |
| 3884 | drcuml_log_printf(drcuml, "%sxer", (count++ == 0) ? "" : ","); |
| 3885 | if (gprmask & ((UINT64)1 << 41)) |
| 3886 | drcuml_log_printf(drcuml, "%sctr", (count++ == 0) ? "" : ","); |
| 3887 | if (gprmask & ((UINT64)1 << 42)) |
| 3888 | drcuml_log_printf(drcuml, "%slr", (count++ == 0) ? "" : ","); |
| 3889 | |
| 3890 | for (regnum = 0; regnum < 32; regnum++) |
| 3891 | if (fprmask & ((UINT64)1 << regnum)) |
| 3892 | drcuml_log_printf(drcuml, "%sfpr%d", (count++ == 0) ? "" : ",", regnum); |
| 3893 | if (fprmask & ((UINT64)1 << 32)) |
| 3894 | drcuml_log_printf(drcuml, "%sfpscr", (count++ == 0) ? "" : ","); |
| 3895 | drcuml_log_printf(drcuml, "] "); |
| 1994 | 3896 | } |
| 1995 | 3897 | |
| 1996 | | static void ppc604drc_exit(void) |
| 3898 | |
| 3899 | /*------------------------------------------------- |
| 3900 | log_opcode_desc - log a list of descriptions |
| 3901 | -------------------------------------------------*/ |
| 3902 | |
| 3903 | static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) |
| 1997 | 3904 | { |
| 1998 | | #if LOG_CODE |
| 1999 | | //if (symfile) fclose(symfile); |
| 3905 | /* open the file, creating it if necessary */ |
| 3906 | if (indent == 0) |
| 3907 | drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc); |
| 3908 | |
| 3909 | /* output each descriptor */ |
| 3910 | for ( ; desclist != NULL; desclist = desclist->next) |
| 3911 | { |
| 3912 | char buffer[100]; |
| 3913 | |
| 3914 | /* disassemle the current instruction and output it to the log */ |
| 3915 | #if (LOG_UML || LOG_NATIVE) |
| 3916 | if (desclist->flags & OPFLAG_VIRTUAL_NOOP) |
| 3917 | strcpy(buffer, "<virtual nop>"); |
| 3918 | else |
| 3919 | ppc_dasm_one(buffer, desclist->pc, *desclist->opptr.l); |
| 3920 | #else |
| 3921 | strcpy(buffer, "???"); |
| 2000 | 3922 | #endif |
| 2001 | | ppcdrc_exit(); |
| 3923 | drcuml_log_printf(drcuml, "%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), buffer); |
| 3924 | |
| 3925 | /* output register states */ |
| 3926 | log_register_list(drcuml, "use", desclist->gpr.used, desclist->fpr.used); |
| 3927 | log_register_list(drcuml, "mod", desclist->gpr.modified, desclist->fpr.modified); |
| 3928 | log_register_list(drcuml, "lrd", desclist->gpr.liveread, desclist->fpr.liveread); |
| 3929 | log_register_list(drcuml, "lwr", desclist->gpr.livewrite, desclist->fpr.livewrite); |
| 3930 | drcuml_log_printf(drcuml, "\n"); |
| 3931 | |
| 3932 | /* if we have a delay slot, output it recursively */ |
| 3933 | if (desclist->delay != NULL) |
| 3934 | log_opcode_desc(drcuml, desclist->delay, indent + 1); |
| 3935 | |
| 3936 | /* at the end of a sequence add a dividing line */ |
| 3937 | if (desclist->flags & OPFLAG_END_SEQUENCE) |
| 3938 | drcuml_log_printf(drcuml, "-----\n"); |
| 3939 | } |
| 2002 | 3940 | } |
| 2003 | | #endif |
| 2004 | 3941 | |
| 2005 | 3942 | |
| 2006 | | static void ppc_get_context(void *dst) |
| 3943 | |
| 3944 | /*************************************************************************** |
| 3945 | PPC 4XX VARIANTS |
| 3946 | ***************************************************************************/ |
| 3947 | |
| 3948 | #if (HAS_PPC403GA || HAS_PPC403GCX) |
| 3949 | |
| 3950 | /*------------------------------------------------- |
| 3951 | ppcdrc4xx_get_info - PowerPC 4XX-specific |
| 3952 | information getter |
| 3953 | -------------------------------------------------*/ |
| 3954 | |
| 3955 | static void ppcdrc4xx_get_info(UINT32 state, cpuinfo *info) |
| 2007 | 3956 | { |
| 2008 | | /* copy the context */ |
| 2009 | | if (dst) |
| 2010 | | *(PPC_REGS *)dst = ppc; |
| 3957 | ppcdrc_get_info(state, info); |
| 3958 | ppc4xx_get_info(ppc, state, info); |
| 2011 | 3959 | } |
| 2012 | 3960 | |
| 2013 | 3961 | |
| 2014 | | static void ppc_set_context(void *src) |
| 3962 | /*------------------------------------------------- |
| 3963 | ppcdrc4xx_set_info - PowerPC 4XX-specific |
| 3964 | information setter |
| 3965 | -------------------------------------------------*/ |
| 3966 | |
| 3967 | static void ppcdrc4xx_set_info(UINT32 state, cpuinfo *info) |
| 2015 | 3968 | { |
| 2016 | | /* copy the context */ |
| 2017 | | if (src) |
| 2018 | | ppc = *(PPC_REGS *)src; |
| 3969 | ppcdrc_set_info(state, info); |
| 3970 | ppc4xx_set_info(ppc, state, info); |
| 3971 | } |
| 2019 | 3972 | |
| 2020 | | change_pc(ppc.pc); |
| 3973 | #endif |
| 3974 | |
| 3975 | |
| 3976 | #if (HAS_PPC403GA) |
| 3977 | |
| 3978 | /*------------------------------------------------- |
| 3979 | ppc403ga_init - PowerPC 403GA-specific |
| 3980 | initialization |
| 3981 | -------------------------------------------------*/ |
| 3982 | |
| 3983 | static void ppc403ga_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 3984 | { |
| 3985 | ppcdrc_init(PPC_MODEL_403GA, PPCCAP_4XX, 1, clock, config, irqcallback); |
| 2021 | 3986 | } |
| 2022 | 3987 | |
| 2023 | 3988 | |
| 2024 | | /************************************************************************** |
| 2025 | | * Generic set_info |
| 2026 | | **************************************************************************/ |
| 3989 | /*------------------------------------------------- |
| 3990 | ppc403ga_get_info - PowerPC 403GA-specific |
| 3991 | information getter |
| 3992 | -------------------------------------------------*/ |
| 2027 | 3993 | |
| 2028 | | static void ppc_set_info(UINT32 state, cpuinfo *info) |
| 3994 | void ppc403ga_get_info(UINT32 state, cpuinfo *info) |
| 2029 | 3995 | { |
| 2030 | 3996 | switch (state) |
| 2031 | 3997 | { |
| 2032 | | case CPUINFO_INT_PC: |
| 2033 | | case CPUINFO_INT_REGISTER + PPC_PC: ppc.pc = info->i; break; |
| 2034 | | case CPUINFO_INT_REGISTER + PPC_MSR: ppc_set_msr(info->i); break; |
| 2035 | | case CPUINFO_INT_REGISTER + PPC_CR: ppc_set_cr(info->i); break; |
| 2036 | | case CPUINFO_INT_REGISTER + PPC_LR: LR = info->i; break; |
| 2037 | | case CPUINFO_INT_REGISTER + PPC_CTR: CTR = info->i; break; |
| 2038 | | case CPUINFO_INT_REGISTER + PPC_XER: XER = info->i; break; |
| 2039 | | case CPUINFO_INT_REGISTER + PPC_SRR0: SRR0 = info->i; break; |
| 2040 | | case CPUINFO_INT_REGISTER + PPC_SRR1: SRR1 = info->i; break; |
| 3998 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2041 | 3999 | |
| 2042 | | case CPUINFO_INT_REGISTER + PPC_R0: ppc.r[0] = info->i; break; |
| 2043 | | case CPUINFO_INT_REGISTER + PPC_R1: ppc.r[1] = info->i; break; |
| 2044 | | case CPUINFO_INT_REGISTER + PPC_R2: ppc.r[2] = info->i; break; |
| 2045 | | case CPUINFO_INT_REGISTER + PPC_R3: ppc.r[3] = info->i; break; |
| 2046 | | case CPUINFO_INT_REGISTER + PPC_R4: ppc.r[4] = info->i; break; |
| 2047 | | case CPUINFO_INT_REGISTER + PPC_R5: ppc.r[5] = info->i; break; |
| 2048 | | case CPUINFO_INT_REGISTER + PPC_R6: ppc.r[6] = info->i; break; |
| 2049 | | case CPUINFO_INT_REGISTER + PPC_R7: ppc.r[7] = info->i; break; |
| 2050 | | case CPUINFO_INT_REGISTER + PPC_R8: ppc.r[8] = info->i; break; |
| 2051 | | case CPUINFO_INT_REGISTER + PPC_R9: ppc.r[9] = info->i; break; |
| 2052 | | case CPUINFO_INT_REGISTER + PPC_R10: ppc.r[10] = info->i; break; |
| 2053 | | case CPUINFO_INT_REGISTER + PPC_R11: ppc.r[11] = info->i; break; |
| 2054 | | case CPUINFO_INT_REGISTER + PPC_R12: ppc.r[12] = info->i; break; |
| 2055 | | case CPUINFO_INT_REGISTER + PPC_R13: ppc.r[13] = info->i; break; |
| 2056 | | case CPUINFO_INT_REGISTER + PPC_R14: ppc.r[14] = info->i; break; |
| 2057 | | case CPUINFO_INT_REGISTER + PPC_R15: ppc.r[15] = info->i; break; |
| 2058 | | case CPUINFO_INT_REGISTER + PPC_R16: ppc.r[16] = info->i; break; |
| 2059 | | case CPUINFO_INT_REGISTER + PPC_R17: ppc.r[17] = info->i; break; |
| 2060 | | case CPUINFO_INT_REGISTER + PPC_R18: ppc.r[18] = info->i; break; |
| 2061 | | case CPUINFO_INT_REGISTER + PPC_R19: ppc.r[19] = info->i; break; |
| 2062 | | case CPUINFO_INT_REGISTER + PPC_R20: ppc.r[20] = info->i; break; |
| 2063 | | case CPUINFO_INT_REGISTER + PPC_R21: ppc.r[21] = info->i; break; |
| 2064 | | case CPUINFO_INT_REGISTER + PPC_R22: ppc.r[22] = info->i; break; |
| 2065 | | case CPUINFO_INT_REGISTER + PPC_R23: ppc.r[23] = info->i; break; |
| 2066 | | case CPUINFO_INT_REGISTER + PPC_R24: ppc.r[24] = info->i; break; |
| 2067 | | case CPUINFO_INT_REGISTER + PPC_R25: ppc.r[25] = info->i; break; |
| 2068 | | case CPUINFO_INT_REGISTER + PPC_R26: ppc.r[26] = info->i; break; |
| 2069 | | case CPUINFO_INT_REGISTER + PPC_R27: ppc.r[27] = info->i; break; |
| 2070 | | case CPUINFO_INT_REGISTER + PPC_R28: ppc.r[28] = info->i; break; |
| 2071 | | case CPUINFO_INT_REGISTER + PPC_R29: ppc.r[29] = info->i; break; |
| 2072 | | case CPUINFO_INT_REGISTER + PPC_R30: ppc.r[30] = info->i; break; |
| 2073 | | case CPUINFO_INT_REGISTER + PPC_R31: ppc.r[31] = info->i; break; |
| 4000 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4001 | case CPUINFO_PTR_INIT: info->init = ppc403ga_init; break; |
| 4002 | case CPUINFO_PTR_SET_INFO: info->setinfo = ppcdrc4xx_set_info; break; |
| 2074 | 4003 | |
| 2075 | | case CPUINFO_INT_PPC_DRC_OPTIONS: ppc.drcoptions = info->i; break; |
| 4004 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4005 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 403GA"); break; |
| 4006 | |
| 4007 | /* --- everything else is handled generically --- */ |
| 4008 | default: ppcdrc4xx_get_info(state, info); break; |
| 2076 | 4009 | } |
| 2077 | 4010 | } |
| 2078 | 4011 | |
| 2079 | | static void ppc_get_info(UINT32 state, cpuinfo *info) |
| 4012 | #endif |
| 4013 | |
| 4014 | |
| 4015 | #if (HAS_PPC403GCX) |
| 4016 | |
| 4017 | /*------------------------------------------------- |
| 4018 | ppc403gcx_init - PowerPC 403GCX-specific |
| 4019 | initialization |
| 4020 | -------------------------------------------------*/ |
| 4021 | |
| 4022 | static void ppc403gcx_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2080 | 4023 | { |
| 2081 | | switch(state) |
| 4024 | ppcdrc_init(PPC_MODEL_403GCX, PPCCAP_4XX, 1, clock, config, irqcallback); |
| 4025 | } |
| 4026 | |
| 4027 | |
| 4028 | /*------------------------------------------------- |
| 4029 | ppc403gcx_get_info - PowerPC 403GCX-specific |
| 4030 | information getter |
| 4031 | -------------------------------------------------*/ |
| 4032 | |
| 4033 | void ppc403gcx_get_info(UINT32 state, cpuinfo *info) |
| 4034 | { |
| 4035 | switch (state) |
| 2082 | 4036 | { |
| 2083 | 4037 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2084 | | case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break; |
| 2085 | | case CPUINFO_INT_INPUT_LINES: info->i = 1; break; |
| 2086 | | case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; |
| 2087 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2088 | | case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; |
| 2089 | | case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; |
| 2090 | | case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; |
| 2091 | | case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; |
| 2092 | | case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; |
| 2093 | | case CPUINFO_INT_MAX_CYCLES: info->i = 40; break; |
| 2094 | 4038 | |
| 2095 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2096 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2097 | | case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break; |
| 2098 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; |
| 2099 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; |
| 2100 | | case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break; |
| 2101 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; |
| 2102 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; |
| 2103 | | case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break; |
| 4039 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4040 | case CPUINFO_PTR_INIT: info->init = ppc403gcx_init; break; |
| 4041 | case CPUINFO_PTR_SET_INFO: info->setinfo = ppcdrc4xx_set_info; break; |
| 2104 | 4042 | |
| 2105 | | case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break; |
| 4043 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4044 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 403GCX"); break; |
| 2106 | 4045 | |
| 2107 | | case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; |
| 4046 | /* --- everything else is handled generically --- */ |
| 4047 | default: ppcdrc4xx_get_info(state, info); break; |
| 4048 | } |
| 4049 | } |
| 2108 | 4050 | |
| 2109 | | case CPUINFO_INT_PC: /* intentional fallthrough */ |
| 2110 | | case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc.pc; break; |
| 2111 | | case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc_get_msr(); break; |
| 2112 | | case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc_get_cr(); break; |
| 2113 | | case CPUINFO_INT_REGISTER + PPC_LR: info->i = LR; break; |
| 2114 | | case CPUINFO_INT_REGISTER + PPC_CTR: info->i = CTR; break; |
| 2115 | | case CPUINFO_INT_REGISTER + PPC_XER: info->i = XER; break; |
| 2116 | | case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = SRR0; break; |
| 2117 | | case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = SRR1; break; |
| 4051 | #endif |
| 2118 | 4052 | |
| 2119 | | case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc.r[0]; break; |
| 2120 | | case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc.r[1]; break; |
| 2121 | | case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc.r[2]; break; |
| 2122 | | case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc.r[3]; break; |
| 2123 | | case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc.r[4]; break; |
| 2124 | | case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc.r[5]; break; |
| 2125 | | case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc.r[6]; break; |
| 2126 | | case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc.r[7]; break; |
| 2127 | | case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc.r[8]; break; |
| 2128 | | case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc.r[9]; break; |
| 2129 | | case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc.r[10]; break; |
| 2130 | | case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc.r[11]; break; |
| 2131 | | case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc.r[12]; break; |
| 2132 | | case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc.r[13]; break; |
| 2133 | | case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc.r[14]; break; |
| 2134 | | case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc.r[15]; break; |
| 2135 | | case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc.r[16]; break; |
| 2136 | | case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc.r[17]; break; |
| 2137 | | case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc.r[18]; break; |
| 2138 | | case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc.r[19]; break; |
| 2139 | | case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc.r[20]; break; |
| 2140 | | case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc.r[21]; break; |
| 2141 | | case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc.r[22]; break; |
| 2142 | | case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc.r[23]; break; |
| 2143 | | case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc.r[24]; break; |
| 2144 | | case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc.r[25]; break; |
| 2145 | | case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc.r[26]; break; |
| 2146 | | case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc.r[27]; break; |
| 2147 | | case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc.r[28]; break; |
| 2148 | | case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc.r[29]; break; |
| 2149 | | case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc.r[30]; break; |
| 2150 | | case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc.r[31]; break; |
| 2151 | 4053 | |
| 2152 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2153 | | case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppc_get_context; break; |
| 2154 | | case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppc_set_context; break; |
| 2155 | | case CPUINFO_PTR_BURN: info->burn = NULL; break; |
| 2156 | | #ifdef ENABLE_DEBUGGER |
| 2157 | | case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppc_dasm; break; |
| 2158 | | #endif /* ENABLE_DEBUGGER */ |
| 2159 | | case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc_icount; break; |
| 2160 | 4054 | |
| 2161 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2162 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; |
| 2163 | | case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "PowerPC"); break; |
| 2164 | | case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break; |
| 2165 | | case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; |
| 2166 | | case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 4055 | /*************************************************************************** |
| 4056 | PPC 6XX VARIANTS |
| 4057 | ***************************************************************************/ |
| 2167 | 4058 | |
| 2168 | | case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; |
| 4059 | #if (HAS_PPC601) |
| 2169 | 4060 | |
| 2170 | | case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc.pc); break; |
| 2171 | | case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR: %08X", ppc_get_msr()); break; |
| 2172 | | case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc_get_cr()); break; |
| 2173 | | case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", LR); break; |
| 2174 | | case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR: %08X", CTR); break; |
| 2175 | | case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER: %08X", XER); break; |
| 2176 | | case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", SRR0); break; |
| 2177 | | case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", SRR1); break; |
| 4061 | /*------------------------------------------------- |
| 4062 | ppc601_init - PowerPC 601-specific |
| 4063 | initialization |
| 4064 | -------------------------------------------------*/ |
| 2178 | 4065 | |
| 2179 | | case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc.r[0]); break; |
| 2180 | | case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc.r[1]); break; |
| 2181 | | case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc.r[2]); break; |
| 2182 | | case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc.r[3]); break; |
| 2183 | | case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc.r[4]); break; |
| 2184 | | case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc.r[5]); break; |
| 2185 | | case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc.r[6]); break; |
| 2186 | | case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc.r[7]); break; |
| 2187 | | case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc.r[8]); break; |
| 2188 | | case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc.r[9]); break; |
| 2189 | | case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10: %08X", ppc.r[10]); break; |
| 2190 | | case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11: %08X", ppc.r[11]); break; |
| 2191 | | case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12: %08X", ppc.r[12]); break; |
| 2192 | | case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13: %08X", ppc.r[13]); break; |
| 2193 | | case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14: %08X", ppc.r[14]); break; |
| 2194 | | case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15: %08X", ppc.r[15]); break; |
| 2195 | | case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16: %08X", ppc.r[16]); break; |
| 2196 | | case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17: %08X", ppc.r[17]); break; |
| 2197 | | case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18: %08X", ppc.r[18]); break; |
| 2198 | | case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19: %08X", ppc.r[19]); break; |
| 2199 | | case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20: %08X", ppc.r[20]); break; |
| 2200 | | case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21: %08X", ppc.r[21]); break; |
| 2201 | | case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22: %08X", ppc.r[22]); break; |
| 2202 | | case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23: %08X", ppc.r[23]); break; |
| 2203 | | case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24: %08X", ppc.r[24]); break; |
| 2204 | | case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25: %08X", ppc.r[25]); break; |
| 2205 | | case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26: %08X", ppc.r[26]); break; |
| 2206 | | case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27: %08X", ppc.r[27]); break; |
| 2207 | | case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28: %08X", ppc.r[28]); break; |
| 2208 | | case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29: %08X", ppc.r[29]); break; |
| 2209 | | case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30: %08X", ppc.r[30]); break; |
| 2210 | | case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31: %08X", ppc.r[31]); break; |
| 2211 | | } |
| 4066 | static void ppc601_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 4067 | { |
| 4068 | ppcdrc_init(PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 0/* no TB */, clock, config, irqcallback); |
| 2212 | 4069 | } |
| 2213 | 4070 | |
| 2214 | 4071 | |
| 4072 | /*------------------------------------------------- |
| 4073 | ppc601_get_info - PowerPC 601-specific |
| 4074 | information getter |
| 4075 | -------------------------------------------------*/ |
| 2215 | 4076 | |
| 2216 | | /* PowerPC 403 */ |
| 2217 | | #if (HAS_PPC403) |
| 2218 | | static void ppc403_set_info(UINT32 state, cpuinfo *info) |
| 4077 | void ppc601_get_info(UINT32 state, cpuinfo *info) |
| 2219 | 4078 | { |
| 2220 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 4079 | switch (state) |
| 2221 | 4080 | { |
| 2222 | | ppcdrc403_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2223 | | return; |
| 4081 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 4082 | |
| 4083 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 4084 | case CPUINFO_PTR_INIT: info->init = ppc601_init; break; |
| 4085 | |
| 4086 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 4087 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 601"); break; |
| 4088 | |
| 4089 | /* --- everything else is handled generically --- */ |
| 4090 | default: ppcdrc_get_info(state, info); break; |
| 2224 | 4091 | } |
| 2225 | | switch(state) |
| 2226 | | { |
| 2227 | | default: ppc_set_info(state, info); break; |
| 2228 | | } |
| 2229 | 4092 | } |
| 2230 | 4093 | |
| 2231 | | void ppc403_get_info(UINT32 state, cpuinfo *info) |
| 4094 | #endif |
| 4095 | |
| 4096 | |
| 4097 | #if (HAS_PPC602) |
| 4098 | |
| 4099 | /*------------------------------------------------- |
| 4100 | ppc602_init - PowerPC 602-specific |
| 4101 | initialization |
| 4102 | -------------------------------------------------*/ |
| 4103 | |
| 4104 | static void ppc602_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2232 | 4105 | { |
| 2233 | | switch(state) |
| 4106 | ppcdrc_init(PPC_MODEL_602, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 1/* unknown */, clock, config, irqcallback); |
| 4107 | } |
| 4108 | |
| 4109 | |
| 4110 | /*------------------------------------------------- |
| 4111 | ppc602_get_info - PowerPC 602-specific |
| 4112 | information getter |
| 4113 | -------------------------------------------------*/ |
| 4114 | |
| 4115 | void ppc602_get_info(UINT32 state, cpuinfo *info) |
| 4116 | { |
| 4117 | switch (state) |
| 2234 | 4118 | { |
| 2235 | 4119 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2236 | | case CPUINFO_INT_INPUT_LINES: info->i = 7; break; |
| 2237 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2238 | 4120 | |
| 2239 | 4121 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2240 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc403_set_info; break; |
| 2241 | | case CPUINFO_PTR_INIT: info->init = ppcdrc403_init; break; |
| 2242 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc403_reset; break; |
| 2243 | | case CPUINFO_PTR_EXIT: info->exit = ppcdrc403_exit; break; |
| 2244 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc403_execute; break; |
| 4122 | case CPUINFO_PTR_INIT: info->init = ppc602_init; break; |
| 2245 | 4123 | |
| 2246 | 4124 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2247 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; |
| 4125 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 602"); break; |
| 2248 | 4126 | |
| 2249 | | default: ppc_get_info(state, info); break; |
| 4127 | /* --- everything else is handled generically --- */ |
| 4128 | default: ppcdrc_get_info(state, info); break; |
| 2250 | 4129 | } |
| 2251 | 4130 | } |
| 4131 | |
| 2252 | 4132 | #endif |
| 2253 | 4133 | |
| 2254 | | /* PowerPC 603 */ |
| 4134 | |
| 2255 | 4135 | #if (HAS_PPC603) |
| 2256 | | static void ppc603_set_info(UINT32 state, cpuinfo *info) |
| 4136 | |
| 4137 | /*------------------------------------------------- |
| 4138 | ppc603_init - PowerPC 603-specific |
| 4139 | initialization |
| 4140 | -------------------------------------------------*/ |
| 4141 | |
| 4142 | static void ppc603_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2257 | 4143 | { |
| 2258 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2259 | | { |
| 2260 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2261 | | return; |
| 2262 | | } |
| 2263 | | switch(state) |
| 2264 | | { |
| 2265 | | case CPUINFO_INT_REGISTER + PPC_DEC: write_decrementer(info->i); break; |
| 2266 | | default: ppc_set_info(state, info); break; |
| 2267 | | } |
| 4144 | ppcdrc_init(PPC_MODEL_603, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, clock, config, irqcallback); |
| 2268 | 4145 | } |
| 2269 | 4146 | |
| 4147 | |
| 4148 | /*------------------------------------------------- |
| 4149 | ppc603_get_info - PowerPC 603-specific |
| 4150 | information getter |
| 4151 | -------------------------------------------------*/ |
| 4152 | |
| 2270 | 4153 | void ppc603_get_info(UINT32 state, cpuinfo *info) |
| 2271 | 4154 | { |
| 2272 | | switch(state) |
| 4155 | switch (state) |
| 2273 | 4156 | { |
| 2274 | 4157 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2275 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2276 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2277 | | case CPUINFO_INT_REGISTER + PPC_DEC: info->i = read_decrementer(); break; |
| 2278 | 4158 | |
| 2279 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2280 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2281 | | case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2282 | | case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break; |
| 2283 | | |
| 2284 | 4159 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2285 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc603_set_info; break; |
| 2286 | | case CPUINFO_PTR_INIT: info->init = ppcdrc603_init; break; |
| 2287 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2288 | | case CPUINFO_PTR_EXIT: info->exit = ppcdrc603_exit; break; |
| 2289 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2290 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2291 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2292 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2293 | | case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break; |
| 4160 | case CPUINFO_PTR_INIT: info->init = ppc603_init; break; |
| 2294 | 4161 | |
| 2295 | 4162 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2296 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC603"); break; |
| 2297 | | case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", read_decrementer()); break; |
| 4163 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603"); break; |
| 2298 | 4164 | |
| 2299 | | default: ppc_get_info(state, info); break; |
| 4165 | /* --- everything else is handled generically --- */ |
| 4166 | default: ppcdrc_get_info(state, info); break; |
| 2300 | 4167 | } |
| 2301 | 4168 | } |
| 4169 | |
| 2302 | 4170 | #endif |
| 2303 | 4171 | |
| 2304 | | /* PowerPC 602 */ |
| 2305 | | #if (HAS_PPC602) |
| 2306 | | static void ppc602_set_info(UINT32 state, cpuinfo *info) |
| 4172 | |
| 4173 | #if (HAS_PPC603E) |
| 4174 | |
| 4175 | /*------------------------------------------------- |
| 4176 | ppc603e_init - PowerPC 603e-specific |
| 4177 | initialization |
| 4178 | -------------------------------------------------*/ |
| 4179 | |
| 4180 | static void ppc603e_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2307 | 4181 | { |
| 2308 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2309 | | { |
| 2310 | | ppcdrc602_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2311 | | return; |
| 2312 | | } |
| 2313 | | switch(state) |
| 2314 | | { |
| 2315 | | default: ppc_set_info(state, info); break; |
| 2316 | | } |
| 4182 | ppcdrc_init(PPC_MODEL_603E, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, clock, config, irqcallback); |
| 2317 | 4183 | } |
| 2318 | 4184 | |
| 2319 | | void ppc602_get_info(UINT32 state, cpuinfo *info) |
| 4185 | |
| 4186 | /*------------------------------------------------- |
| 4187 | ppc603e_get_info - PowerPC 603e-specific |
| 4188 | information getter |
| 4189 | -------------------------------------------------*/ |
| 4190 | |
| 4191 | void ppc603e_get_info(UINT32 state, cpuinfo *info) |
| 2320 | 4192 | { |
| 2321 | | switch(state) |
| 4193 | switch (state) |
| 2322 | 4194 | { |
| 2323 | 4195 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2324 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2325 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2326 | 4196 | |
| 2327 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2328 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2329 | | case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2330 | | case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break; |
| 2331 | | |
| 2332 | 4197 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2333 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc602_set_info; break; |
| 2334 | | case CPUINFO_PTR_INIT: info->init = ppcdrc602_init; break; |
| 2335 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc602_reset; break; |
| 2336 | | case CPUINFO_PTR_EXIT: info->exit = ppcdrc602_exit; break; |
| 2337 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc602_execute; break; |
| 2338 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2339 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2340 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 2341 | | case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break; |
| 4198 | case CPUINFO_PTR_INIT: info->init = ppc603e_init; break; |
| 2342 | 4199 | |
| 2343 | 4200 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2344 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC602"); break; |
| 4201 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603e"); break; |
| 2345 | 4202 | |
| 2346 | | default: ppc_get_info(state, info); break; |
| 4203 | /* --- everything else is handled generically --- */ |
| 4204 | default: ppcdrc_get_info(state, info); break; |
| 2347 | 4205 | } |
| 2348 | 4206 | } |
| 4207 | |
| 2349 | 4208 | #endif |
| 2350 | 4209 | |
| 2351 | | /* Motorola MPC8240 */ |
| 2352 | 4210 | |
| 2353 | | #if (HAS_MPC8240) |
| 2354 | | static void mpc8240_set_info(UINT32 state, cpuinfo *info) |
| 4211 | #if (HAS_PPC603R) |
| 4212 | |
| 4213 | /*------------------------------------------------- |
| 4214 | ppc603r_init - PowerPC 603r-specific |
| 4215 | initialization |
| 4216 | -------------------------------------------------*/ |
| 4217 | |
| 4218 | static void ppc603r_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2355 | 4219 | { |
| 2356 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2357 | | { |
| 2358 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2359 | | return; |
| 2360 | | } |
| 2361 | | switch(state) |
| 2362 | | { |
| 2363 | | default: ppc_set_info(state, info); break; |
| 2364 | | } |
| 4220 | ppcdrc_init(PPC_MODEL_603R, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, clock, config, irqcallback); |
| 2365 | 4221 | } |
| 2366 | 4222 | |
| 2367 | | void mpc8240_get_info(UINT32 state, cpuinfo *info) |
| 4223 | |
| 4224 | /*------------------------------------------------- |
| 4225 | ppc603r_get_info - PowerPC 603r-specific |
| 4226 | information getter |
| 4227 | -------------------------------------------------*/ |
| 4228 | |
| 4229 | void ppc603r_get_info(UINT32 state, cpuinfo *info) |
| 2368 | 4230 | { |
| 2369 | | switch(state) |
| 4231 | switch (state) |
| 2370 | 4232 | { |
| 2371 | 4233 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2372 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2373 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2374 | 4234 | |
| 2375 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2376 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2377 | | |
| 2378 | 4235 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2379 | | case CPUINFO_PTR_SET_INFO: info->setinfo = mpc8240_set_info; break; |
| 2380 | | case CPUINFO_PTR_INIT: info->init = mpc8240drc_init; break; |
| 2381 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2382 | | case CPUINFO_PTR_EXIT: info->exit = mpc8240drc_exit; break; |
| 2383 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2384 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2385 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2386 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 4236 | case CPUINFO_PTR_INIT: info->init = ppc603r_init; break; |
| 2387 | 4237 | |
| 2388 | 4238 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2389 | | case CPUINFO_STR_NAME: strcpy(info->s, "MPC8240"); break; |
| 4239 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603R"); break; |
| 2390 | 4240 | |
| 2391 | | default: ppc_get_info(state, info); break; |
| 4241 | /* --- everything else is handled generically --- */ |
| 4242 | default: ppcdrc_get_info(state, info); break; |
| 2392 | 4243 | } |
| 2393 | 4244 | } |
| 4245 | |
| 2394 | 4246 | #endif |
| 2395 | 4247 | |
| 2396 | 4248 | |
| 2397 | | /* PPC601 */ |
| 4249 | #if (HAS_PPC604) |
| 2398 | 4250 | |
| 2399 | | #if (HAS_PPC601) |
| 2400 | | static void ppc601_set_info(UINT32 state, cpuinfo *info) |
| 4251 | /*------------------------------------------------- |
| 4252 | ppc604_init - PowerPC 604-specific |
| 4253 | initialization |
| 4254 | -------------------------------------------------*/ |
| 4255 | |
| 4256 | static void ppc604_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2401 | 4257 | { |
| 2402 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2403 | | { |
| 2404 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2405 | | return; |
| 2406 | | } |
| 2407 | | switch(state) |
| 2408 | | { |
| 2409 | | default: ppc_set_info(state, info); break; |
| 2410 | | } |
| 4258 | ppcdrc_init(PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 4, clock, config, irqcallback); |
| 2411 | 4259 | } |
| 2412 | 4260 | |
| 2413 | | void ppc601_get_info(UINT32 state, cpuinfo *info) |
| 4261 | |
| 4262 | /*------------------------------------------------- |
| 4263 | ppc604_get_info - PowerPC 604-specific |
| 4264 | information getter |
| 4265 | -------------------------------------------------*/ |
| 4266 | |
| 4267 | void ppc604_get_info(UINT32 state, cpuinfo *info) |
| 2414 | 4268 | { |
| 2415 | | switch(state) |
| 4269 | switch (state) |
| 2416 | 4270 | { |
| 2417 | 4271 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2418 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2419 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2420 | 4272 | |
| 2421 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2422 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2423 | | |
| 2424 | 4273 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2425 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc601_set_info; break; |
| 2426 | | case CPUINFO_PTR_INIT: info->init = ppc601drc_init; break; |
| 2427 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2428 | | case CPUINFO_PTR_EXIT: info->exit = ppc601drc_exit; break; |
| 2429 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2430 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2431 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2432 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 4274 | case CPUINFO_PTR_INIT: info->init = ppc604_init; break; |
| 2433 | 4275 | |
| 2434 | 4276 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2435 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC601"); break; |
| 4277 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 604"); break; |
| 2436 | 4278 | |
| 2437 | | default: ppc_get_info(state, info); break; |
| 4279 | /* --- everything else is handled generically --- */ |
| 4280 | default: ppcdrc_get_info(state, info); break; |
| 2438 | 4281 | } |
| 2439 | 4282 | } |
| 4283 | |
| 2440 | 4284 | #endif |
| 2441 | 4285 | |
| 2442 | | /* PPC604 */ |
| 2443 | 4286 | |
| 2444 | | #if (HAS_PPC604) |
| 2445 | | static void ppc604_set_info(UINT32 state, cpuinfo *info) |
| 4287 | |
| 4288 | /*************************************************************************** |
| 4289 | PPC 6XX VARIANTS |
| 4290 | ***************************************************************************/ |
| 4291 | |
| 4292 | #if (HAS_MPC8240) |
| 4293 | |
| 4294 | /*------------------------------------------------- |
| 4295 | mpc8240_init - PowerPC MPC8240-specific |
| 4296 | initialization |
| 4297 | -------------------------------------------------*/ |
| 4298 | |
| 4299 | static void mpc8240_init(int index, int clock, const void *config, int (*irqcallback)(int)) |
| 2446 | 4300 | { |
| 2447 | | if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) |
| 2448 | | { |
| 2449 | | ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); |
| 2450 | | return; |
| 2451 | | } |
| 2452 | | switch(state) |
| 2453 | | { |
| 2454 | | default: ppc_set_info(state, info); break; |
| 2455 | | } |
| 4301 | ppcdrc_init(PPC_MODEL_MPC8240, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 4/* unknown */, clock, config, irqcallback); |
| 2456 | 4302 | } |
| 2457 | 4303 | |
| 2458 | | void ppc604_get_info(UINT32 state, cpuinfo *info) |
| 4304 | |
| 4305 | /*------------------------------------------------- |
| 4306 | mpc8240_get_info - PowerPC MPC8240-specific |
| 4307 | information getter |
| 4308 | -------------------------------------------------*/ |
| 4309 | |
| 4310 | void mpc8240_get_info(UINT32 state, cpuinfo *info) |
| 2459 | 4311 | { |
| 2460 | | switch(state) |
| 4312 | switch (state) |
| 2461 | 4313 | { |
| 2462 | 4314 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 2463 | | case CPUINFO_INT_INPUT_LINES: info->i = 5; break; |
| 2464 | | case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; |
| 2465 | 4315 | |
| 2466 | | case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; |
| 2467 | | case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; |
| 2468 | | |
| 2469 | 4316 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 2470 | | case CPUINFO_PTR_SET_INFO: info->setinfo = ppc604_set_info; break; |
| 2471 | | case CPUINFO_PTR_INIT: info->init = ppc604drc_init; break; |
| 2472 | | case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; |
| 2473 | | case CPUINFO_PTR_EXIT: info->exit = ppc604drc_exit; break; |
| 2474 | | case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; |
| 2475 | | case CPUINFO_PTR_READ: info->read = ppc_read; break; |
| 2476 | | case CPUINFO_PTR_WRITE: info->write = ppc_write; break; |
| 2477 | | case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; |
| 4317 | case CPUINFO_PTR_INIT: info->init = mpc8240_init; break; |
| 2478 | 4318 | |
| 2479 | 4319 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 2480 | | case CPUINFO_STR_NAME: strcpy(info->s, "PPC604"); break; |
| 4320 | case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC MPC8240"); break; |
| 2481 | 4321 | |
| 2482 | | default: ppc_get_info(state, info); break; |
| 4322 | /* --- everything else is handled generically --- */ |
| 4323 | default: ppcdrc_get_info(state, info); break; |
| 2483 | 4324 | } |
| 2484 | 4325 | } |
| 4326 | |
| 2485 | 4327 | #endif |
| 4328 | |
| 4329 | |
| 4330 | |
| 4331 | /*************************************************************************** |
| 4332 | DISASSEMBLERS |
| 4333 | ***************************************************************************/ |
| 4334 | |
| 4335 | #if !defined(MAME_DEBUG) && (LOG_UML || LOG_NATIVE) |
| 4336 | #include "ppc_dasm.c" |
| 4337 | #endif |
src/emu/cpu/mips/mdrc64.c
| r2821 | r2822 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | mdrc64.c |
| 4 | | |
| 5 | | x64 MIPS III recompiler. |
| 6 | | |
| 7 | | Copyright Aaron Giles |
| 8 | | Released for general use under the MAME license |
| 9 | | Visit http://mamedev.org for licensing and usage restrictions. |
| 10 | | |
| 11 | | **************************************************************************** |
| 12 | | |
| 13 | | Conventions/rules: |
| 14 | | |
| 15 | | * Instructions are grouped into sequences by mips3fe; each |
| 16 | | sequence of instructions is guaranteed to not contain any |
| 17 | | branches to any instructions within the sequence apart from |
| 18 | | the first. |
| 19 | | |
| 20 | | * Because of the above rule, assumptions are made during the |
| 21 | | execution of a sequence in order to optimize the generated |
| 22 | | code. |
| 23 | | |
| 24 | | * Because some state may be live and not flushed to memory at |
| 25 | | the time an exception is generated, all exception-generating |
| 26 | | instructions must jump to stub code that is appended to each |
| 27 | | group of instructions which cleans up live registers before |
| 28 | | running the exception code. |
| 29 | | |
| 30 | | * Page faults are trickier because they are detected in a |
| 31 | | subroutine. In order to handle this, special markers are added |
| 32 | | to the code consisting of one qword EXCEPTION_ADDRESS_COOKIE |
| 33 | | followed by the return address of the call. When a page fault |
| 34 | | needs to be generated, the common code scans forward from |
| 35 | | the return address for this cookie/address pair and jumps to |
| 36 | | the code immediately following. |
| 37 | | |
| 38 | | * Convention: jumps to non-constant addresses have their target |
| 39 | | PC stored at [sp+SPOFFS_NEXTPC] |
| 40 | | |
| 41 | | **************************************************************************** |
| 42 | | |
| 43 | | Future improvements: |
| 44 | | * problem: |
| 45 | | lui r3,$b000 |
| 46 | | lw r3,$100(r3) |
| 47 | | if exception happens, then r3 is trashed |
| 48 | | |
| 49 | | * register allocator can use non-volatile registers if the |
| 50 | | lifetime is only for this one instruction (only for |
| 51 | | registers where (gpr.used & ~gpr.modified) |
| 52 | | |
| 53 | | * spec says if registers aren't sign-extended, then 32-bit ops have |
| 54 | | undefined results; this can simplify our code |
| 55 | | |
| 56 | | * track which results are 32-bit sign extended versus 64-bit and |
| 57 | | only promote when necessary |
| 58 | | |
| 59 | | * register aliasing - move from one to another either doesn't do |
| 60 | | anything and tracks both, or else shifts ownership to new |
| 61 | | target |
| 62 | | |
| 63 | | * generic drc: |
| 64 | | * common code to load registers prior to instruction |
| 65 | | - each register has a callback that generates the load |
| 66 | | * generate code |
| 67 | | * common code to write registers afterwards |
| 68 | | * common register allocation routines (64 integer, 64 FPU) |
| 69 | | * common OOB mechanism |
| 70 | | * common self-mod code detection (via write bitmask) |
| 71 | | * common code validation routines |
| 72 | | |
| 73 | | **************************************************************************** |
| 74 | | |
| 75 | | Temporary stack usage: |
| 76 | | [esp+32].b = storage for CL in LWL/LWR/SWL/SWR |
| 77 | | [esp+36].l = storage for new target PC in JR/JALR |
| 78 | | |
| 79 | | ***************************************************************************/ |
| 80 | | |
| 81 | | #include "mips3fe.h" |
| 82 | | #include "deprecat.h" |
| 83 | | |
| 84 | | |
| 85 | | /*************************************************************************** |
| 86 | | DEBUGGING |
| 87 | | ***************************************************************************/ |
| 88 | | |
| 89 | | #define DISABLE_FIXED_RAM_LOAD (0) |
| 90 | | #define DISABLE_FIXED_RAM_STORE (0) |
| 91 | | #define FLUSH_AFTER_EACH_INSTRUCTION (0) |
| 92 | | #define PRINTF_EXCEPTIONS (0) |
| 93 | | #define PROBE_ADDRESS (0) |
| 94 | | #define LOG_HOTSPOTS (0) |
| 95 | | |
| 96 | | |
| 97 | | |
| 98 | | /*************************************************************************** |
| 99 | | CONSTANTS |
| 100 | | ***************************************************************************/ |
| 101 | | |
| 102 | | /* extra "conditions" used to augment the basic conditions for OOB handlers */ |
| 103 | | #define COND_NONE 16 |
| 104 | | #define COND_NO_JUMP 17 |
| 105 | | |
| 106 | | /* 64-bit cookie that is scanned for during exception processing */ |
| 107 | | #define EXCEPTION_ADDRESS_COOKIE U64(0xcc90cc90cc90cc90) |
| 108 | | |
| 109 | | /* append_readwrite flags */ |
| 110 | | #define ARW_READ 0x0000 |
| 111 | | #define ARW_WRITE 0x0001 |
| 112 | | #define ARW_UNSIGNED 0x0000 |
| 113 | | #define ARW_SIGNED 0x0002 |
| 114 | | #define ARW_MASKED 0x0004 |
| 115 | | #define ARW_CACHED 0x0008 |
| 116 | | #define ARW_UNCACHED 0x0010 |
| 117 | | |
| 118 | | /* compiler_register_allocate flags */ |
| 119 | | #define ALLOC_SRC 0x0001 |
| 120 | | #define ALLOC_DST 0x0002 |
| 121 | | #define ALLOC_DIRTY 0x0004 |
| 122 | | |
| 123 | | /* x86 register tracking flags */ |
| 124 | | #define X86REG_LIVE 0x80 /* register is live and contains something */ |
| 125 | | #define X86REG_MIPSMASK 0x3f /* low 6 bits indicate which MIPS register we hold */ |
| 126 | | |
| 127 | | /* MIPS register tracking flags */ |
| 128 | | #define MIPSREG_CONSTANT 0x8000 /* register is constant; low 10 bits select which one */ |
| 129 | | #define MIPSREG_DIRTY 0x4000 /* register has been modified and needs to be flushed */ |
| 130 | | #define MIPSREG_LIVE 0x2000 /* register is live in an x86 register */ |
| 131 | | #define MIPSREG_X86MASK 0x000f /* low 4 bits indicate which x86 register holds us */ |
| 132 | | |
| 133 | | |
| 134 | | |
| 135 | | /*************************************************************************** |
| 136 | | MACROS |
| 137 | | ***************************************************************************/ |
| 138 | | |
| 139 | | #define SPOFFS_SAVECL 32 |
| 140 | | #define SPOFFS_NEXTPC 36 |
| 141 | | |
| 142 | | #define REGADDR(reg) MDRC(&mips3.core->r[reg]) |
| 143 | | #define HIADDR MDRC(&mips3.core->r[REG_HI]) |
| 144 | | #define LOADDR MDRC(&mips3.core->r[REG_LO]) |
| 145 | | #define CPR0ADDR(reg) MDRC(&mips3.core->cpr[0][reg]) |
| 146 | | #define CCR0ADDR(reg) MDRC(&mips3.core->ccr[0][reg]) |
| 147 | | #define CPR1ADDR(reg) MDRC(&mips3.core->cpr[1][reg]) |
| 148 | | #define CCR1ADDR(reg) MDRC(&mips3.core->ccr[1][reg]) |
| 149 | | #define CPR2ADDR(reg) MDRC(&mips3.core->cpr[2][reg]) |
| 150 | | #define CCR2ADDR(reg) MDRC(&mips3.core->ccr[2][reg]) |
| 151 | | #define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg]) |
| 152 | | #define FPR32ADDR(reg) MDRC(FPR32(reg)) |
| 153 | | #define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg]) |
| 154 | | #define FPR64ADDR(reg) MDRC(FPR64(reg)) |
| 155 | | #define CF1ADDR(which) MDRC(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)]) |
| 156 | | #define PCADDR MDRC(&mips3.core->pc) |
| 157 | | #define ICOUNTADDR MDRC(&mips3.core->icount) |
| 158 | | #define COREADDR MDRC(mips3.core) |
| 159 | | |
| 160 | | /* macros for querying/accessing the tracking flags */ |
| 161 | | #define ISCONST(x) (((x) & MIPSREG_CONSTANT) != 0) |
| 162 | | #define ISDIRTY(x) (((x) & MIPSREG_DIRTY) != 0) |
| 163 | | #define ISLIVE(x) (((x) & MIPSREG_LIVE) != 0) |
| 164 | | #define CONSTVAL(x) ((INT32)((x) >> 32)) |
| 165 | | #define X86REG(x) ((x) & MIPSREG_X86MASK) |
| 166 | | |
| 167 | | /* macro for defining a small positivec constant inline */ |
| 168 | | #define MAKE_CONST(x) (MIPSREG_CONSTANT | ((INT64)(x) << 32)) |
| 169 | | #define MAKE_DESTREG(x) (MIPSREG_DIRTY | ((x) & MIPSREG_X86MASK)) |
| 170 | | |
| 171 | | |
| 172 | | |
| 173 | | /*************************************************************************** |
| 174 | | TYPEDEFS |
| 175 | | ***************************************************************************/ |
| 176 | | |
| 177 | | typedef struct _readwrite_handlers readwrite_handlers; |
| 178 | | struct _readwrite_handlers |
| 179 | | { |
| 180 | | x86code * read_byte_signed; |
| 181 | | x86code * read_byte_unsigned; |
| 182 | | x86code * read_half_signed; |
| 183 | | x86code * read_half_unsigned; |
| 184 | | x86code * read_word_signed; |
| 185 | | x86code * read_word_unsigned; |
| 186 | | x86code * read_word_masked; |
| 187 | | x86code * read_double; |
| 188 | | x86code * read_double_masked; |
| 189 | | x86code * write_byte; |
| 190 | | x86code * write_half; |
| 191 | | x86code * write_word; |
| 192 | | x86code * write_word_masked; |
| 193 | | x86code * write_double; |
| 194 | | x86code * write_double_masked; |
| 195 | | }; |
| 196 | | |
| 197 | | |
| 198 | | typedef INT64 mipsreg_state; |
| 199 | | typedef UINT8 x86reg_state; |
| 200 | | |
| 201 | | |
| 202 | | typedef struct _compiler_state compiler_state; |
| 203 | | struct _compiler_state |
| 204 | | { |
| 205 | | UINT32 cycles; /* accumulated cycles */ |
| 206 | | x86reg_state x86regs[REG_MAX]; /* tracking what is in the x86 registers */ |
| 207 | | mipsreg_state mipsregs[35]; /* tracking what is in the MIPS registers */ |
| 208 | | }; |
| 209 | | |
| 210 | | |
| 211 | | typedef struct _oob_handler oob_handler; |
| 212 | | |
| 213 | | typedef void (*oob_callback_func)(drc_core *drc, oob_handler *oob, void *param); |
| 214 | | |
| 215 | | struct _oob_handler |
| 216 | | { |
| 217 | | oob_callback_func callback; /* pointer to callback function */ |
| 218 | | void * param; /* callback parameter */ |
| 219 | | const opcode_desc * desc; /* pointer to description of relevant instruction */ |
| 220 | | emit_link link; /* link to source of the branch */ |
| 221 | | compiler_state compiler; /* state of the compiler at this time */ |
| 222 | | }; |
| 223 | | |
| 224 | | |
| 225 | | struct _mips3drc_data |
| 226 | | { |
| 227 | | /* misc data */ |
| 228 | | UINT64 abs64mask[2]; |
| 229 | | UINT32 abs32mask[4]; |
| 230 | | |
| 231 | | /* C functions */ |
| 232 | | x86code * activecpu_gettotalcycles; |
| 233 | | x86code * mips3com_update_cycle_counting; |
| 234 | | x86code * mips3com_tlbr; |
| 235 | | x86code * mips3com_tlbwi; |
| 236 | | x86code * mips3com_tlbwr; |
| 237 | | x86code * mips3com_tlbp; |
| 238 | | |
| 239 | | /* internal functions */ |
| 240 | | x86code * generate_interrupt_exception; |
| 241 | | x86code * generate_cop_exception; |
| 242 | | x86code * generate_overflow_exception; |
| 243 | | x86code * generate_invalidop_exception; |
| 244 | | x86code * generate_syscall_exception; |
| 245 | | x86code * generate_break_exception; |
| 246 | | x86code * generate_trap_exception; |
| 247 | | x86code * generate_tlbload_exception; |
| 248 | | x86code * generate_tlbstore_exception; |
| 249 | | x86code * handle_pc_tlb_mismatch; |
| 250 | | x86code * find_exception_handler; |
| 251 | | x86code * explode_ccr31; |
| 252 | | x86code * recover_ccr31; |
| 253 | | |
| 254 | | /* read/write handlers */ |
| 255 | | readwrite_handlers general; |
| 256 | | readwrite_handlers cached; |
| 257 | | readwrite_handlers uncached; |
| 258 | | |
| 259 | | /* out of bounds handlers */ |
| 260 | | oob_handler ooblist[COMPILE_MAX_INSTRUCTIONS*2]; |
| 261 | | int oobcount; |
| 262 | | |
| 263 | | /* C functions */ |
| 264 | | x86code * execute_c_version; |
| 265 | | |
| 266 | | /* hotspot tracking */ |
| 267 | | #if LOG_HOTSPOTS |
| 268 | | struct |
| 269 | | { |
| 270 | | offs_t pc; |
| 271 | | UINT32 opcode; |
| 272 | | UINT64 count; |
| 273 | | } hotspot[100000]; |
| 274 | | int next_hotspot; |
| 275 | | #endif |
| 276 | | }; |
| 277 | | |
| 278 | | |
| 279 | | |
| 280 | | /*************************************************************************** |
| 281 | | FUNCTION PROTOTYPES |
| 282 | | ***************************************************************************/ |
| 283 | | |
| 284 | | static void drc_reset_callback(drc_core *drc); |
| 285 | | static void drc_recompile_callback(drc_core *drc); |
| 286 | | static void drc_entrygen_callback(drc_core *drc); |
| 287 | | |
| 288 | | static void compile_one(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 289 | | |
| 290 | | static void oob_exception_cleanup(drc_core *drc, oob_handler *oob, void *param); |
| 291 | | static void oob_interrupt_cleanup(drc_core *drc, oob_handler *oob, void *param); |
| 292 | | |
| 293 | | static void compiler_register_set_constant(compiler_state *compiler, UINT8 mipsreg, UINT64 constval); |
| 294 | | static mipsreg_state compiler_register_allocate(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT8 flags); |
| 295 | | static void compiler_register_flush(drc_core *drc, compiler_state *compiler, UINT8 mipsreg, int free); |
| 296 | | static void compiler_register_flush_all(drc_core *drc, compiler_state *compiler); |
| 297 | | |
| 298 | | static void probe_printf(void); |
| 299 | | |
| 300 | | static void generate_read_write_handlers(drc_core *drc, readwrite_handlers *handlers, const char *type, UINT8 flags); |
| 301 | | static void append_generate_exception(drc_core *drc, UINT8 exception); |
| 302 | | static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags, UINT32 ptroffs); |
| 303 | | static void append_handle_pc_tlb_mismatch(drc_core *drc); |
| 304 | | static void append_find_exception_handler(drc_core *drc); |
| 305 | | static void append_explode_ccr31(drc_core *drc); |
| 306 | | static void append_recover_ccr31(drc_core *drc); |
| 307 | | static void append_check_interrupts(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 308 | | //static void append_check_sw_interrupts(drc_core *drc, int inline_generate); |
| 309 | | |
| 310 | | static void emit_update_cycles_pc_and_flush(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, offs_t destpc); |
| 311 | | |
| 312 | | static int compile_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 313 | | static int compile_special(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 314 | | static int compile_regimm(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 315 | | static int compile_idt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 316 | | static int compile_cop0(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 317 | | static int compile_cop1(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 318 | | static int compile_cop1x(drc_core *drc, compiler_state *compiler, const opcode_desc *desc); |
| 319 | | |
| 320 | | static int compile_shift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable); |
| 321 | | static int compile_dshift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable, int shift_const_plus32); |
| 322 | | static int compile_movzn(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_movn); |
| 323 | | static int compile_trapcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int immediate); |
| 324 | | static int compile_branchcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition); |
| 325 | | static int compile_branchcz(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int link); |
| 326 | | static int compile_add(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate); |
| 327 | | static int compile_dadd(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate); |
| 328 | | static int compile_sub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions); |
| 329 | | static int compile_dsub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions); |
| 330 | | static int compile_mult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned); |
| 331 | | static int compile_dmult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned); |
| 332 | | static int compile_div(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned); |
| 333 | | static int compile_ddiv(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned); |
| 334 | | static int compile_logical(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int operation, int immediate); |
| 335 | | static int compile_slt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned, int immediate); |
| 336 | | static int compile_load(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, int is_unsigned); |
| 337 | | static int compile_load_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest); |
| 338 | | static int compile_loadx_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest); |
| 339 | | static int compile_load_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right); |
| 340 | | static int compile_load_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right); |
| 341 | | static int compile_store(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size); |
| 342 | | static int compile_store_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src); |
| 343 | | static int compile_storex_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src); |
| 344 | | static int compile_store_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right); |
| 345 | | static int compile_store_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right); |
| 346 | | |
| 347 | | |
| 348 | | |
| 349 | | /*************************************************************************** |
| 350 | | PRIVATE GLOBAL VARIABLES |
| 351 | | ***************************************************************************/ |
| 352 | | |
| 353 | | static const UINT8 nvreg[] = { REG_NV0, REG_NV1, REG_NV2, REG_NV3, REG_NV4, REG_NV5, REG_NV6 }; |
| 354 | | |
| 355 | | static const char *const x86regname[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; |
| 356 | | |
| 357 | | |
| 358 | | |
| 359 | | /*************************************************************************** |
| 360 | | INLINE FUNCTIONS |
| 361 | | ***************************************************************************/ |
| 362 | | |
| 363 | | /*------------------------------------------------- |
| 364 | | oob_request_callback - request an out-of- |
| 365 | | bounds callback for later |
| 366 | | -------------------------------------------------*/ |
| 367 | | |
| 368 | | INLINE void oob_request_callback(drc_core *drc, UINT8 condition, oob_callback_func callback, const compiler_state *compiler, const opcode_desc *desc, void *param) |
| 369 | | { |
| 370 | | oob_handler *oob = &mips3.drcdata->ooblist[mips3.drcdata->oobcount++]; |
| 371 | | |
| 372 | | /* fill in the next handler */ |
| 373 | | oob->callback = callback; |
| 374 | | oob->desc = desc; |
| 375 | | oob->compiler = *compiler; |
| 376 | | oob->param = param; |
| 377 | | |
| 378 | | /* emit an appropriate jump */ |
| 379 | | if (condition == COND_NO_JUMP) |
| 380 | | { |
| 381 | | oob->link.size = 0; |
| 382 | | oob->link.target = drc->cache_top; |
| 383 | | } |
| 384 | | else if (condition == COND_NONE) |
| 385 | | emit_jmp_near_link(DRCTOP, &oob->link); // jmp <target> |
| 386 | | else |
| 387 | | emit_jcc_near_link(DRCTOP, condition, &oob->link); // jcc <target> |
| 388 | | } |
| 389 | | |
| 390 | | |
| 391 | | /*------------------------------------------------- |
| 392 | | compiler_state_reset - reset the compiler |
| 393 | | state |
| 394 | | -------------------------------------------------*/ |
| 395 | | |
| 396 | | INLINE void compiler_state_reset(compiler_state *compiler) |
| 397 | | { |
| 398 | | memset(compiler, 0, sizeof(*compiler)); |
| 399 | | compiler_register_set_constant(compiler, 0, 0); |
| 400 | | } |
| 401 | | |
| 402 | | |
| 403 | | |
| 404 | | /*************************************************************************** |
| 405 | | CORE RECOMPILER SYSTEMS |
| 406 | | ***************************************************************************/ |
| 407 | | |
| 408 | | /*------------------------------------------------- |
| 409 | | mips3drc_init - initialize the drc-specific |
| 410 | | state |
| 411 | | -------------------------------------------------*/ |
| 412 | | |
| 413 | | static void mips3drc_init(void) |
| 414 | | { |
| 415 | | drc_config drconfig; |
| 416 | | |
| 417 | | /* fill in the config */ |
| 418 | | memset(&drconfig, 0, sizeof(drconfig)); |
| 419 | | drconfig.cache_base = mips3.cache; |
| 420 | | drconfig.cache_size = CACHE_SIZE; |
| 421 | | drconfig.max_instructions = (512 + 128) / 4; |
| 422 | | drconfig.address_bits = 32; |
| 423 | | drconfig.lsbs_to_ignore = 2; |
| 424 | | drconfig.baseptr = &mips3.core->r[17]; |
| 425 | | drconfig.pcptr = (UINT32 *)&mips3.core->pc; |
| 426 | | drconfig.cb_reset = drc_reset_callback; |
| 427 | | drconfig.cb_recompile = drc_recompile_callback; |
| 428 | | drconfig.cb_entrygen = drc_entrygen_callback; |
| 429 | | |
| 430 | | /* initialize the compiler */ |
| 431 | | mips3.drc = drc_init(cpu_getactivecpu(), &drconfig); |
| 432 | | mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS; |
| 433 | | |
| 434 | | /* allocate our data out of the cache */ |
| 435 | | mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata) + 16); |
| 436 | | mips3.drcdata = (mips3drc_data *)((((FPTR)mips3.drcdata + 15) >> 4) << 4); |
| 437 | | memset(mips3.drcdata, 0, sizeof(*mips3.drcdata)); |
| 438 | | |
| 439 | | /* set up constants */ |
| 440 | | mips3.drcdata->abs64mask[0] = U64(0x7fffffffffffffff); |
| 441 | | mips3.drcdata->abs32mask[0] = 0x7fffffff; |
| 442 | | |
| 443 | | /* get pointers to C functions */ |
| 444 | | mips3.drcdata->activecpu_gettotalcycles = (x86code *)activecpu_gettotalcycles; |
| 445 | | mips3.drcdata->mips3com_update_cycle_counting = (x86code *)mips3com_update_cycle_counting; |
| 446 | | mips3.drcdata->mips3com_tlbr = (x86code *)mips3com_tlbr; |
| 447 | | mips3.drcdata->mips3com_tlbwi = (x86code *)mips3com_tlbwi; |
| 448 | | mips3.drcdata->mips3com_tlbwr = (x86code *)mips3com_tlbwr; |
| 449 | | mips3.drcdata->mips3com_tlbp = (x86code *)mips3com_tlbp; |
| 450 | | |
| 451 | | #if COMPARE_AGAINST_C |
| 452 | | mips3.drcdata->execute_c_version = (x86code *)execute_c_version; |
| 453 | | #endif |
| 454 | | } |
| 455 | | |
| 456 | | |
| 457 | | /*------------------------------------------------- |
| 458 | | mips3drc_exit - clean up the drc-specific |
| 459 | | state |
| 460 | | -------------------------------------------------*/ |
| 461 | | |
| 462 | | static void mips3drc_exit(void) |
| 463 | | { |
| 464 | | printf("Final code size = %d\n", (int)(mips3.drc->cache_top - mips3.drc->cache_base)); |
| 465 | | #if LOG_HOTSPOTS |
| 466 | | /* print top hotspots */ |
| 467 | | { |
| 468 | | int maxspot = 0; |
| 469 | | int hotnum; |
| 470 | | int count; |
| 471 | | |
| 472 | | for (count = 0; count < 10; count++) |
| 473 | | { |
| 474 | | for (hotnum = 1; hotnum < mips3.drcdata->next_hotspot; hotnum++) |
| 475 | | if (mips3.drcdata->hotspot[hotnum].count > mips3.drcdata->hotspot[maxspot].count) |
| 476 | | maxspot = hotnum; |
| 477 | | printf("%08X%08X hits: add_speedup(0x%08X, 0x%08X);\n", |
| 478 | | (UINT32)(mips3.drcdata->hotspot[maxspot].count >> 32), |
| 479 | | (UINT32)mips3.drcdata->hotspot[maxspot].count, |
| 480 | | mips3.drcdata->hotspot[maxspot].pc, |
| 481 | | mips3.drcdata->hotspot[maxspot].opcode); |
| 482 | | mips3.drcdata->hotspot[maxspot].count = 0; |
| 483 | | } |
| 484 | | } |
| 485 | | #endif |
| 486 | | drc_exit(mips3.drc); |
| 487 | | } |
| 488 | | |
| 489 | | |
| 490 | | |
| 491 | | /*************************************************************************** |
| 492 | | RECOMPILER CALLBACKS |
| 493 | | ***************************************************************************/ |
| 494 | | |
| 495 | | /*------------------------------------------------------------------ |
| 496 | | drc_reset_callback |
| 497 | | ------------------------------------------------------------------*/ |
| 498 | | |
| 499 | | static void drc_reset_callback(drc_core *drc) |
| 500 | | { |
| 501 | | if (LOG_CODE) |
| 502 | | { |
| 503 | | x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->exit_point); |
| 504 | | x86log_disasm_code_range(mips3.log, "exit_point:", drc->exit_point, drc->recompile); |
| 505 | | x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch); |
| 506 | | x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush); |
| 507 | | x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top); |
| 508 | | } |
| 509 | | |
| 510 | | mips3.drcdata->generate_interrupt_exception = drc->cache_top; |
| 511 | | append_generate_exception(drc, EXCEPTION_INTERRUPT); |
| 512 | | if (LOG_CODE) |
| 513 | | x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top); |
| 514 | | |
| 515 | | mips3.drcdata->generate_cop_exception = drc->cache_top; |
| 516 | | append_generate_exception(drc, EXCEPTION_BADCOP); |
| 517 | | if (LOG_CODE) |
| 518 | | x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top); |
| 519 | | |
| 520 | | mips3.drcdata->generate_overflow_exception = drc->cache_top; |
| 521 | | append_generate_exception(drc, EXCEPTION_OVERFLOW); |
| 522 | | if (LOG_CODE) |
| 523 | | x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top); |
| 524 | | |
| 525 | | mips3.drcdata->generate_invalidop_exception = drc->cache_top; |
| 526 | | append_generate_exception(drc, EXCEPTION_INVALIDOP); |
| 527 | | if (LOG_CODE) |
| 528 | | x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top); |
| 529 | | |
| 530 | | mips3.drcdata->generate_syscall_exception = drc->cache_top; |
| 531 | | append_generate_exception(drc, EXCEPTION_SYSCALL); |
| 532 | | if (LOG_CODE) |
| 533 | | x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top); |
| 534 | | |
| 535 | | mips3.drcdata->generate_break_exception = drc->cache_top; |
| 536 | | append_generate_exception(drc, EXCEPTION_BREAK); |
| 537 | | if (LOG_CODE) |
| 538 | | x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top); |
| 539 | | |
| 540 | | mips3.drcdata->generate_trap_exception = drc->cache_top; |
| 541 | | append_generate_exception(drc, EXCEPTION_TRAP); |
| 542 | | if (LOG_CODE) |
| 543 | | x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top); |
| 544 | | |
| 545 | | mips3.drcdata->generate_tlbload_exception = drc->cache_top; |
| 546 | | append_generate_exception(drc, EXCEPTION_TLBLOAD); |
| 547 | | if (LOG_CODE) |
| 548 | | x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top); |
| 549 | | |
| 550 | | mips3.drcdata->generate_tlbstore_exception = drc->cache_top; |
| 551 | | append_generate_exception(drc, EXCEPTION_TLBSTORE); |
| 552 | | if (LOG_CODE) |
| 553 | | x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top); |
| 554 | | |
| 555 | | mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top; |
| 556 | | append_handle_pc_tlb_mismatch(drc); |
| 557 | | if (LOG_CODE) |
| 558 | | x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top); |
| 559 | | |
| 560 | | mips3.drcdata->find_exception_handler = drc->cache_top; |
| 561 | | append_find_exception_handler(drc); |
| 562 | | if (LOG_CODE) |
| 563 | | x86log_disasm_code_range(mips3.log, "find_exception_handler:", mips3.drcdata->find_exception_handler, drc->cache_top); |
| 564 | | |
| 565 | | mips3.drcdata->explode_ccr31 = drc->cache_top; |
| 566 | | append_explode_ccr31(drc); |
| 567 | | if (LOG_CODE) |
| 568 | | x86log_disasm_code_range(mips3.log, "explode_ccr31:", mips3.drcdata->explode_ccr31, drc->cache_top); |
| 569 | | |
| 570 | | mips3.drcdata->recover_ccr31 = drc->cache_top; |
| 571 | | append_recover_ccr31(drc); |
| 572 | | if (LOG_CODE) |
| 573 | | x86log_disasm_code_range(mips3.log, "recover_ccr31:", mips3.drcdata->recover_ccr31, drc->cache_top); |
| 574 | | |
| 575 | | generate_read_write_handlers(drc, &mips3.drcdata->general, "general", 0); |
| 576 | | generate_read_write_handlers(drc, &mips3.drcdata->cached, "cached", ARW_CACHED); |
| 577 | | generate_read_write_handlers(drc, &mips3.drcdata->uncached, "uncached", ARW_UNCACHED); |
| 578 | | } |
| 579 | | |
| 580 | | |
| 581 | | /*------------------------------------------------------------------ |
| 582 | | drc_recompile_callback |
| 583 | | ------------------------------------------------------------------*/ |
| 584 | | |
| 585 | | static void drc_recompile_callback(drc_core *drc) |
| 586 | | { |
| 587 | | int compiled_last_sequence = FALSE; |
| 588 | | const opcode_desc *seqhead, *seqlast; |
| 589 | | const opcode_desc *desclist; |
| 590 | | void *start = drc->cache_top; |
| 591 | | int override = FALSE; |
| 592 | | int oobnum; |
| 593 | | |
| 594 | | (void)start; |
| 595 | | |
| 596 | | /* begin the sequence */ |
| 597 | | drc_begin_sequence(drc, mips3.core->pc); |
| 598 | | mips3.drcdata->oobcount = 0; |
| 599 | | |
| 600 | | /* get a description of this sequence */ |
| 601 | | desclist = drcfe_describe_code(mips3.drcfe, mips3.core->pc); |
| 602 | | if (LOG_CODE) |
| 603 | | log_opcode_desc(mips3.log, desclist, 0); |
| 604 | | |
| 605 | | /* loop until we get through all instruction sequences */ |
| 606 | | for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next) |
| 607 | | { |
| 608 | | const opcode_desc *curdesc; |
| 609 | | compiler_state compiler; |
| 610 | | |
| 611 | | /* determine the last instruction in this sequence */ |
| 612 | | for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next) |
| 613 | | if (seqlast->flags & OPFLAG_END_SEQUENCE) |
| 614 | | break; |
| 615 | | assert(seqlast != NULL); |
| 616 | | |
| 617 | | /* add this as an entry point */ |
| 618 | | if (drc_add_entry_point(drc, seqhead->pc, override) && !override) |
| 619 | | { |
| 620 | | /* if this is the first sequence, it is a recompile request; allow overrides */ |
| 621 | | if (seqhead == desclist) |
| 622 | | { |
| 623 | | override = TRUE; |
| 624 | | drc_add_entry_point(drc, seqhead->pc, override); |
| 625 | | } |
| 626 | | |
| 627 | | /* otherwise, just emit a jump to existing code */ |
| 628 | | else |
| 629 | | { |
| 630 | | if (compiled_last_sequence) |
| 631 | | drc_append_fixed_dispatcher(drc, seqhead->pc, TRUE); |
| 632 | | compiled_last_sequence = FALSE; |
| 633 | | continue; |
| 634 | | } |
| 635 | | } |
| 636 | | compiled_last_sequence = TRUE; |
| 637 | | |
| 638 | | /* add a code log entry */ |
| 639 | | if (LOG_CODE) |
| 640 | | x86log_add_comment(mips3.log, drc->cache_top, "-------------------------"); |
| 641 | | |
| 642 | | /* validate this code block if we're not pointing into ROM */ |
| 643 | | /* note that we assume P1 still contains the PC */ |
| 644 | | if (memory_get_write_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, seqhead->physpc) != NULL) |
| 645 | | { |
| 646 | | if (LOG_CODE) |
| 647 | | x86log_add_comment(mips3.log, drc->cache_top, "[Validation for %08X]", seqhead->pc); |
| 648 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)seqhead->opptr.v); // mov rax,seqhead->opptr |
| 649 | | for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) |
| 650 | | { |
| 651 | | emit_cmp_m32_imm(DRCTOP, MBD(REG_RAX, curdesc->opptr.b - seqhead->opptr.b), *curdesc->opptr.l); |
| 652 | | // cmp [code],val |
| 653 | | emit_jcc(DRCTOP, COND_NE, mips3.drc->recompile); // jne recompile |
| 654 | | } |
| 655 | | } |
| 656 | | |
| 657 | | /* initialize the compiler state */ |
| 658 | | compiler_state_reset(&compiler); |
| 659 | | |
| 660 | | #if LOG_HOTSPOTS |
| 661 | | /* add hotspot tracking */ |
| 662 | | { |
| 663 | | int hotnum; |
| 664 | | |
| 665 | | drc_register_code_at_cache_top(drc, seqhead->pc); |
| 666 | | |
| 667 | | for (hotnum = 0; hotnum < mips3.drcdata->next_hotspot; hotnum++) |
| 668 | | if (mips3.drcdata->hotspot[hotnum].pc == seqhead->pc && mips3.drcdata->hotspot[hotnum].opcode == *seqhead->opptr.l) |
| 669 | | break; |
| 670 | | if (hotnum == mips3.drcdata->next_hotspot) |
| 671 | | { |
| 672 | | assert(hotnum < ARRAY_LENGTH(mips3.drcdata->hotspot)); |
| 673 | | mips3.drcdata->hotspot[hotnum].pc = seqhead->pc; |
| 674 | | mips3.drcdata->hotspot[hotnum].opcode = *seqhead->opptr.l; |
| 675 | | mips3.drcdata->hotspot[hotnum].count = 0; |
| 676 | | mips3.drcdata->next_hotspot++; |
| 677 | | } |
| 678 | | emit_add_m64_imm(DRCTOP, MDRC(&mips3.drcdata->hotspot[hotnum].count), 1); |
| 679 | | } |
| 680 | | #endif |
| 681 | | |
| 682 | | /* iterate over instructions in the sequence and compile them */ |
| 683 | | for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) |
| 684 | | compile_one(drc, &compiler, curdesc); |
| 685 | | |
| 686 | | /* at the end of the sequence; update the PC in memory and check cycle counts */ |
| 687 | | if (!(seqlast->flags & (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_WILL_CAUSE_EXCEPTION))) |
| 688 | | { |
| 689 | | UINT32 nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; |
| 690 | | emit_update_cycles_pc_and_flush(drc, &compiler, NULL, nextpc); |
| 691 | | } |
| 692 | | |
| 693 | | /* if this is a likely branch, the fall through case needs to skip the next instruction */ |
| 694 | | if ((seqlast->flags & OPFLAG_IS_CONDITIONAL_BRANCH) && seqlast->skipslots > 0) |
| 695 | | if (seqlast->next != NULL && seqlast->next->pc != seqlast->pc + 8) |
| 696 | | { |
| 697 | | compiler_register_flush_all(drc, &compiler); |
| 698 | | drc_append_tentative_fixed_dispatcher(drc, seqlast->pc + 8, TRUE); // jmp <pc+8> |
| 699 | | } |
| 700 | | |
| 701 | | /* if we need a redispatch, do it now */ |
| 702 | | if (seqlast->flags & OPFLAG_REDISPATCH) |
| 703 | | { |
| 704 | | UINT32 nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; |
| 705 | | compiler_register_flush_all(drc, &compiler); |
| 706 | | drc_append_tentative_fixed_dispatcher(drc, nextpc, TRUE); // jmp <nextpc> |
| 707 | | } |
| 708 | | |
| 709 | | /* if we need to return to the start, do it */ |
| 710 | | if (seqlast->flags & OPFLAG_RETURN_TO_START) |
| 711 | | { |
| 712 | | compiler_register_flush_all(drc, &compiler); |
| 713 | | drc_append_tentative_fixed_dispatcher(drc, mips3.core->pc, FALSE); // jmp <startpc> |
| 714 | | } |
| 715 | | } |
| 716 | | |
| 717 | | /* end the sequence */ |
| 718 | | drc_end_sequence(drc); |
| 719 | | |
| 720 | | /* run the out-of-bounds handlers */ |
| 721 | | for (oobnum = 0; oobnum < mips3.drcdata->oobcount; oobnum++) |
| 722 | | { |
| 723 | | oob_handler *oob = &mips3.drcdata->ooblist[oobnum]; |
| 724 | | (*oob->callback)(drc, oob, oob->param); |
| 725 | | } |
| 726 | | |
| 727 | | /* log the generated code */ |
| 728 | | if (LOG_CODE) |
| 729 | | { |
| 730 | | char label[60]; |
| 731 | | sprintf(label, "Code @ %08X (%08X physical)", desclist->pc, desclist->physpc); |
| 732 | | x86log_disasm_code_range(mips3.log, label, start, drc->cache_top); |
| 733 | | } |
| 734 | | } |
| 735 | | |
| 736 | | |
| 737 | | /*------------------------------------------------------------------ |
| 738 | | drc_entrygen_callback |
| 739 | | ------------------------------------------------------------------*/ |
| 740 | | |
| 741 | | static void drc_entrygen_callback(drc_core *drc) |
| 742 | | { |
| 743 | | append_check_interrupts(drc, NULL, NULL); |
| 744 | | } |
| 745 | | |
| 746 | | |
| 747 | | |
| 748 | | /*************************************************************************** |
| 749 | | RECOMPILER CORE |
| 750 | | ***************************************************************************/ |
| 751 | | |
| 752 | | /*------------------------------------------------------------------ |
| 753 | | compile_one |
| 754 | | ------------------------------------------------------------------*/ |
| 755 | | |
| 756 | | static void compile_one(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 757 | | { |
| 758 | | int hotnum; |
| 759 | | |
| 760 | | /* register this instruction */ |
| 761 | | if (!(desc->flags & OPFLAG_IN_DELAY_SLOT)) |
| 762 | | drc_register_code_at_cache_top(drc, desc->pc); |
| 763 | | |
| 764 | | /* add an entry for the log */ |
| 765 | | if (LOG_CODE) |
| 766 | | log_add_disasm_comment(mips3.log, drc->cache_top, desc->pc, *desc->opptr.l); |
| 767 | | |
| 768 | | /* if we want a probe, add it here */ |
| 769 | | if (desc->pc == PROBE_ADDRESS) |
| 770 | | { |
| 771 | | emit_mov_m32_imm(DRCTOP, PCADDR, desc->pc); // mov [pc],desc->pc |
| 772 | | compiler_register_flush_all(drc, compiler); |
| 773 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)probe_printf); |
| 774 | | emit_call_r64(DRCTOP, REG_RAX); |
| 775 | | } |
| 776 | | |
| 777 | | /* if we are debugging, call the debugger */ |
| 778 | | if (Machine->debug_mode || COMPARE_AGAINST_C) |
| 779 | | { |
| 780 | | emit_mov_m32_imm(DRCTOP, PCADDR, desc->pc); // mov [pc],desc->pc |
| 781 | | if (COMPARE_AGAINST_C && !(desc->flags & OPFLAG_IN_DELAY_SLOT)) |
| 782 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->execute_c_version)); |
| 783 | | if (Machine->debug_mode) |
| 784 | | drc_append_call_debugger(drc); // <call debugger> |
| 785 | | } |
| 786 | | |
| 787 | | /* validate our TLB entry at this PC; if we fail, we need to recompile */ |
| 788 | | if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000)) |
| 789 | | { |
| 790 | | emit_cmp_m32_imm(DRCTOP, MDRC(&mips3.core->tlb_table[desc->pc >> 12]), mips3.core->tlb_table[desc->pc >> 12]); |
| 791 | | // cmp tlb_table[pc>>12],<original value> |
| 792 | | oob_request_callback(drc, COND_NE, oob_exception_cleanup, compiler, desc, mips3.drcdata->handle_pc_tlb_mismatch); |
| 793 | | // jne handle_pc_tlb_mismatch |
| 794 | | } |
| 795 | | |
| 796 | | /* accumulate total cycles */ |
| 797 | | compiler->cycles += desc->cycles; |
| 798 | | |
| 799 | | /* is this a hotspot? */ |
| 800 | | for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++) |
| 801 | | if (desc->pc == mips3.hotspot[hotnum].pc && *desc->opptr.l == mips3.hotspot[hotnum].opcode) |
| 802 | | { |
| 803 | | compiler->cycles += mips3.hotspot[hotnum].cycles; |
| 804 | | break; |
| 805 | | } |
| 806 | | |
| 807 | | /* if this is an invalid opcode, generate the exception now */ |
| 808 | | if (desc->flags & OPFLAG_INVALID_OPCODE) |
| 809 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_invalidop_exception); |
| 810 | | |
| 811 | | /* otherwise, it's a regular instruction */ |
| 812 | | else |
| 813 | | { |
| 814 | | /* compile the instruction */ |
| 815 | | if (!compile_instruction(drc, compiler, desc)) |
| 816 | | fatalerror("Unimplemented op %08X (%02X,%02X)", *desc->opptr.l, *desc->opptr.l >> 26, *desc->opptr.l & 0x3f); |
| 817 | | |
| 818 | | /* flush */ |
| 819 | | if (FLUSH_AFTER_EACH_INSTRUCTION) |
| 820 | | compiler_register_flush_all(drc, compiler); |
| 821 | | } |
| 822 | | } |
| 823 | | |
| 824 | | |
| 825 | | |
| 826 | | /*************************************************************************** |
| 827 | | OUT-OF-BOUNDS CODEGEN |
| 828 | | ***************************************************************************/ |
| 829 | | |
| 830 | | /*------------------------------------------------- |
| 831 | | oob_exception_cleanup - out-of-bounds code |
| 832 | | generator for cleaning up and generating an |
| 833 | | exception with the EPC pointing to the |
| 834 | | current instruction |
| 835 | | -------------------------------------------------*/ |
| 836 | | |
| 837 | | static void oob_exception_cleanup(drc_core *drc, oob_handler *oob, void *param) |
| 838 | | { |
| 839 | | /* if this is non-jumping error, emit a unique signature */ |
| 840 | | if (oob->link.size == 0) |
| 841 | | { |
| 842 | | /* align to an 8-byte boundary */ |
| 843 | | while (((UINT64)drc->cache_top & 7) != 0) |
| 844 | | emit_int_3(DRCTOP); |
| 845 | | |
| 846 | | /* logging */ |
| 847 | | if (LOG_CODE) |
| 848 | | { |
| 849 | | x86log_add_comment(mips3.log, drc->cache_top, "[Exception path for %08X]", oob->desc->pc); |
| 850 | | x86log_mark_as_data(mips3.log, drc->cache_top, drc->cache_top + 15, 8); |
| 851 | | } |
| 852 | | |
| 853 | | /* output a pair of qwords */ |
| 854 | | emit_qword(DRCTOP, EXCEPTION_ADDRESS_COOKIE); |
| 855 | | emit_qword(DRCTOP, (UINT64)oob->link.target); |
| 856 | | } |
| 857 | | |
| 858 | | /* otherwise, just resolve the link */ |
| 859 | | else |
| 860 | | { |
| 861 | | resolve_link(DRCTOP, &oob->link); |
| 862 | | if (LOG_CODE) |
| 863 | | x86log_add_comment(mips3.log, drc->cache_top, "[Exception path for %08X]", oob->desc->pc); |
| 864 | | } |
| 865 | | |
| 866 | | /* adjust for cycles */ |
| 867 | | if (oob->compiler.cycles != 0) |
| 868 | | emit_sub_m32_imm(DRCTOP, ICOUNTADDR, oob->compiler.cycles); // sub [icount],cycles |
| 869 | | |
| 870 | | /* update the PC with the instruction PC */ |
| 871 | | if (!(oob->desc->flags & OPFLAG_IN_DELAY_SLOT)) |
| 872 | | emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc); // mov p1,pc |
| 873 | | else |
| 874 | | emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc | 1); // mov p1,pc | 1 |
| 875 | | |
| 876 | | /* flush any dirty registers */ |
| 877 | | compiler_register_flush_all(drc, &oob->compiler); // <flush registers> |
| 878 | | |
| 879 | | /* jump to the exception generator */ |
| 880 | | emit_jmp(DRCTOP, param); // jmp <generate exception> |
| 881 | | } |
| 882 | | |
| 883 | | |
| 884 | | /*------------------------------------------------- |
| 885 | | oob_interrupt_cleanup - out-of-bounds code |
| 886 | | generator for cleaning up and generating an |
| 887 | | interrupt with the EPC pointing to the |
| 888 | | following instruction |
| 889 | | -------------------------------------------------*/ |
| 890 | | |
| 891 | | static void oob_interrupt_cleanup(drc_core *drc, oob_handler *oob, void *param) |
| 892 | | { |
| 893 | | /* resolve the link */ |
| 894 | | resolve_link(DRCTOP, &oob->link); |
| 895 | | |
| 896 | | /* add a code log entry */ |
| 897 | | if (LOG_CODE) |
| 898 | | x86log_add_comment(mips3.log, drc->cache_top, "[Interrupt path for %08X]", oob->desc->pc); |
| 899 | | |
| 900 | | /* adjust for cycles */ |
| 901 | | if (oob->compiler.cycles != 0) |
| 902 | | emit_sub_m32_imm(DRCTOP, ICOUNTADDR, oob->compiler.cycles); // sub [icount],cycles |
| 903 | | |
| 904 | | /* update the PC with the following instruction PC */ |
| 905 | | if (!(oob->desc->flags & OPFLAG_IN_DELAY_SLOT)) |
| 906 | | { |
| 907 | | assert(!(oob->desc->flags & OPFLAG_IS_BRANCH)); |
| 908 | | emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc + 4); // mov p1,pc + 4 |
| 909 | | } |
| 910 | | else |
| 911 | | { |
| 912 | | assert(oob->desc->branch != NULL); |
| 913 | | if (oob->desc->branch->targetpc != BRANCH_TARGET_DYNAMIC) |
| 914 | | emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->branch->targetpc); // mov p1,<targetpc> |
| 915 | | else |
| 916 | | emit_mov_r32_m32(DRCTOP, REG_P1, MBD(REG_RSP, SPOFFS_NEXTPC)); // mov p1,[rsp + nextpc] |
| 917 | | } |
| 918 | | |
| 919 | | /* flush any dirty registers */ |
| 920 | | compiler_register_flush_all(drc, &oob->compiler); // <flush registers> |
| 921 | | |
| 922 | | /* jump to the exception generator */ |
| 923 | | emit_jmp(DRCTOP, param); // jmp <generate exception> |
| 924 | | } |
| 925 | | |
| 926 | | |
| 927 | | |
| 928 | | /*************************************************************************** |
| 929 | | REGISTER ALLOCATION ROUTINES |
| 930 | | ***************************************************************************/ |
| 931 | | |
| 932 | | /*------------------------------------------------- |
| 933 | | compiler_register_set_constant - set a MIPS |
| 934 | | register to a constant value |
| 935 | | -------------------------------------------------*/ |
| 936 | | |
| 937 | | static void compiler_register_set_constant(compiler_state *compiler, UINT8 mipsreg, UINT64 constval) |
| 938 | | { |
| 939 | | mipsreg_state reg = compiler->mipsregs[mipsreg]; |
| 940 | | |
| 941 | | assert((INT32)constval == (INT64)constval); |
| 942 | | |
| 943 | | /* if the register was previously live, free it */ |
| 944 | | if (ISLIVE(reg)) |
| 945 | | { |
| 946 | | assert(compiler->x86regs[X86REG(reg)] & X86REG_LIVE); |
| 947 | | compiler->x86regs[X86REG(reg)] = 0; |
| 948 | | } |
| 949 | | |
| 950 | | /* set up the constant */ |
| 951 | | compiler->mipsregs[mipsreg] = MAKE_CONST(constval) | ((mipsreg == 0) ? 0 : MIPSREG_DIRTY); |
| 952 | | } |
| 953 | | |
| 954 | | |
| 955 | | /*------------------------------------------------- |
| 956 | | compiler_register_allocate - allocate an x86 |
| 957 | | register to hold a MIPS register |
| 958 | | -------------------------------------------------*/ |
| 959 | | |
| 960 | | static mipsreg_state compiler_register_allocate(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT8 flags) |
| 961 | | { |
| 962 | | UINT8 regindex, regnum = 0; |
| 963 | | UINT64 livemask = 0; |
| 964 | | |
| 965 | | /* register 0 is always constant */ |
| 966 | | if (mipsreg == 0) |
| 967 | | return MAKE_CONST(0); |
| 968 | | |
| 969 | | /* first see if we are already allocated */ |
| 970 | | if (ISLIVE(compiler->mipsregs[mipsreg])) |
| 971 | | { |
| 972 | | /* if we're not a source, make sure we are marked dirty */ |
| 973 | | if (flags & ALLOC_DIRTY) |
| 974 | | compiler->mipsregs[mipsreg] |= MIPSREG_DIRTY; |
| 975 | | return compiler->mipsregs[mipsreg]; |
| 976 | | } |
| 977 | | |
| 978 | | /* if we just want a source register, return a constant directly */ |
| 979 | | if (flags == ALLOC_SRC && ISCONST(compiler->mipsregs[mipsreg])) |
| 980 | | return compiler->mipsregs[mipsreg]; |
| 981 | | |
| 982 | | /* first look for a free entry */ |
| 983 | | for (regindex = 0; regindex < NUM_NVREG; regindex++) |
| 984 | | { |
| 985 | | regnum = nvreg[regindex]; |
| 986 | | if (!(compiler->x86regs[regnum] & X86REG_LIVE)) |
| 987 | | goto allocateit; |
| 988 | | else |
| 989 | | livemask |= (UINT64)1 << (compiler->x86regs[regnum] & X86REG_MIPSMASK); |
| 990 | | } |
| 991 | | |
| 992 | | /* can't have anything we need for this instruction, however */ |
| 993 | | livemask &= ~desc->gpr.used & ~desc->gpr.modified; |
| 994 | | desc = desc->next; |
| 995 | | |
| 996 | | /* next loop over the registers, figuring out who has the longest until being used */ |
| 997 | | while (desc != NULL && livemask != 0) |
| 998 | | { |
| 999 | | /* if this instruction uses the last remaining register, we have to pick from among those */ |
| 1000 | | if ((livemask & ~desc->gpr.used) == 0) |
| 1001 | | break; |
| 1002 | | livemask &= ~desc->gpr.used; |
| 1003 | | |
| 1004 | | /* if this instruction modifies any of the registers, we want those */ |
| 1005 | | if ((livemask & desc->gpr.modified) != 0) |
| 1006 | | { |
| 1007 | | livemask &= desc->gpr.modified; |
| 1008 | | break; |
| 1009 | | } |
| 1010 | | |
| 1011 | | /* advance to the next instruction; stop if we hit end-of-sequence */ |
| 1012 | | if (desc->flags & OPFLAG_END_SEQUENCE) |
| 1013 | | break; |
| 1014 | | desc = desc->next; |
| 1015 | | } |
| 1016 | | |
| 1017 | | /* pick the first one */ |
| 1018 | | for (regindex = 0; regindex < NUM_NVREG; regindex++) |
| 1019 | | { |
| 1020 | | regnum = nvreg[regindex]; |
| 1021 | | if (livemask & ((UINT64)1 << (compiler->x86regs[regnum] & X86REG_MIPSMASK))) |
| 1022 | | break; |
| 1023 | | } |
| 1024 | | assert(regindex != NUM_NVREG); |
| 1025 | | |
| 1026 | | /* flush it */ |
| 1027 | | compiler_register_flush(drc, compiler, compiler->x86regs[regnum] & X86REG_MIPSMASK, TRUE); |
| 1028 | | |
| 1029 | | allocateit: |
| 1030 | | /* load the contents if we are a source */ |
| 1031 | | if (LOG_CODE) |
| 1032 | | x86log_add_comment(mips3.log, drc->cache_top, "allocate r%d (%s)", mipsreg, x86regname[regnum]); |
| 1033 | | if (flags & ALLOC_SRC) |
| 1034 | | { |
| 1035 | | mipsreg_state state = compiler->mipsregs[mipsreg]; |
| 1036 | | if (ISCONST(state)) |
| 1037 | | emit_mov_r64_imm(DRCTOP, regnum, CONSTVAL(state)); // mov <x86reg>,constant |
| 1038 | | else |
| 1039 | | emit_mov_r64_m64(DRCTOP, regnum, REGADDR(mipsreg)); // mov <x86reg>,[reg] |
| 1040 | | } |
| 1041 | | |
| 1042 | | /* mark it allocated */ |
| 1043 | | assert(!(compiler->x86regs[regnum] & X86REG_LIVE)); |
| 1044 | | compiler->x86regs[regnum] = X86REG_LIVE | mipsreg; |
| 1045 | | compiler->mipsregs[mipsreg] = MIPSREG_LIVE | regnum | ((flags & ALLOC_DIRTY) ? MIPSREG_DIRTY : 0); |
| 1046 | | return compiler->mipsregs[mipsreg]; |
| 1047 | | } |
| 1048 | | |
| 1049 | | |
| 1050 | | /*------------------------------------------------- |
| 1051 | | compiler_register_flush - flush and optionally |
| 1052 | | free a single MIPS register |
| 1053 | | -------------------------------------------------*/ |
| 1054 | | |
| 1055 | | static void compiler_register_flush(drc_core *drc, compiler_state *compiler, UINT8 mipsreg, int free) |
| 1056 | | { |
| 1057 | | mipsreg_state reg = compiler->mipsregs[mipsreg]; |
| 1058 | | |
| 1059 | | assert(ISCONST(reg) || ISLIVE(reg)); |
| 1060 | | |
| 1061 | | /* flush the value if dirty */ |
| 1062 | | if (ISDIRTY(reg)) |
| 1063 | | { |
| 1064 | | if (LOG_CODE) |
| 1065 | | x86log_add_comment(mips3.log, drc->cache_top, "flush r%d (%s)", mipsreg, ISCONST(reg) ? "constant" : x86regname[X86REG(reg)]); |
| 1066 | | |
| 1067 | | /* flush a constant value */ |
| 1068 | | if (ISCONST(reg)) |
| 1069 | | emit_mov_m64_imm(DRCTOP, REGADDR(mipsreg), CONSTVAL(reg)); // mov [reg],constant |
| 1070 | | |
| 1071 | | /* flush a live value */ |
| 1072 | | else if (ISLIVE(reg)) |
| 1073 | | emit_mov_m64_r64(DRCTOP, REGADDR(mipsreg), X86REG(reg)); // mov [reg],<x86reg> |
| 1074 | | } |
| 1075 | | |
| 1076 | | /* clear the dirty flag */ |
| 1077 | | if (!free) |
| 1078 | | compiler->mipsregs[mipsreg] &= ~MIPSREG_DIRTY; |
| 1079 | | else |
| 1080 | | { |
| 1081 | | if (ISLIVE(reg)) |
| 1082 | | compiler->x86regs[X86REG(reg)] = 0; |
| 1083 | | compiler->mipsregs[mipsreg] = 0; |
| 1084 | | } |
| 1085 | | } |
| 1086 | | |
| 1087 | | |
| 1088 | | /*------------------------------------------------- |
| 1089 | | compiler_register_flush_all - flush all dirty |
| 1090 | | registers |
| 1091 | | -------------------------------------------------*/ |
| 1092 | | |
| 1093 | | static void compiler_register_flush_all(drc_core *drc, compiler_state *compiler) |
| 1094 | | { |
| 1095 | | int mipsreg; |
| 1096 | | |
| 1097 | | /* flush all dirty registers */ |
| 1098 | | for (mipsreg = 1; mipsreg < 35; mipsreg++) |
| 1099 | | if (ISDIRTY(compiler->mipsregs[mipsreg])) |
| 1100 | | compiler_register_flush(drc, compiler, mipsreg, FALSE); |
| 1101 | | } |
| 1102 | | |
| 1103 | | |
| 1104 | | |
| 1105 | | /*************************************************************************** |
| 1106 | | COMPILER CALLBACKS |
| 1107 | | ***************************************************************************/ |
| 1108 | | |
| 1109 | | /*------------------------------------------------- |
| 1110 | | probe_printf - print the current CPU state |
| 1111 | | and return |
| 1112 | | -------------------------------------------------*/ |
| 1113 | | |
| 1114 | | static void probe_printf(void) |
| 1115 | | { |
| 1116 | | printf(" PC=%08X r1=%08X%08X r2=%08X%08X r3=%08X%08X\n", |
| 1117 | | mips3.core->pc, |
| 1118 | | (UINT32)(mips3.core->r[1] >> 32), (UINT32)mips3.core->r[1], |
| 1119 | | (UINT32)(mips3.core->r[2] >> 32), (UINT32)mips3.core->r[2], |
| 1120 | | (UINT32)(mips3.core->r[3] >> 32), (UINT32)mips3.core->r[3]); |
| 1121 | | printf(" r4=%08X%08X r5=%08X%08X r6=%08X%08X r7=%08X%08X\n", |
| 1122 | | (UINT32)(mips3.core->r[4] >> 32), (UINT32)mips3.core->r[4], |
| 1123 | | (UINT32)(mips3.core->r[5] >> 32), (UINT32)mips3.core->r[5], |
| 1124 | | (UINT32)(mips3.core->r[6] >> 32), (UINT32)mips3.core->r[6], |
| 1125 | | (UINT32)(mips3.core->r[7] >> 32), (UINT32)mips3.core->r[7]); |
| 1126 | | printf(" r8=%08X%08X r9=%08X%08X r10=%08X%08X r11=%08X%08X\n", |
| 1127 | | (UINT32)(mips3.core->r[8] >> 32), (UINT32)mips3.core->r[8], |
| 1128 | | (UINT32)(mips3.core->r[9] >> 32), (UINT32)mips3.core->r[9], |
| 1129 | | (UINT32)(mips3.core->r[10] >> 32), (UINT32)mips3.core->r[10], |
| 1130 | | (UINT32)(mips3.core->r[11] >> 32), (UINT32)mips3.core->r[11]); |
| 1131 | | printf("r12=%08X%08X r13=%08X%08X r14=%08X%08X r15=%08X%08X\n", |
| 1132 | | (UINT32)(mips3.core->r[12] >> 32), (UINT32)mips3.core->r[12], |
| 1133 | | (UINT32)(mips3.core->r[13] >> 32), (UINT32)mips3.core->r[13], |
| 1134 | | (UINT32)(mips3.core->r[14] >> 32), (UINT32)mips3.core->r[14], |
| 1135 | | (UINT32)(mips3.core->r[15] >> 32), (UINT32)mips3.core->r[15]); |
| 1136 | | printf("r16=%08X%08X r17=%08X%08X r18=%08X%08X r19=%08X%08X\n", |
| 1137 | | (UINT32)(mips3.core->r[16] >> 32), (UINT32)mips3.core->r[16], |
| 1138 | | (UINT32)(mips3.core->r[17] >> 32), (UINT32)mips3.core->r[17], |
| 1139 | | (UINT32)(mips3.core->r[18] >> 32), (UINT32)mips3.core->r[18], |
| 1140 | | (UINT32)(mips3.core->r[19] >> 32), (UINT32)mips3.core->r[19]); |
| 1141 | | printf("r20=%08X%08X r21=%08X%08X r22=%08X%08X r23=%08X%08X\n", |
| 1142 | | (UINT32)(mips3.core->r[20] >> 32), (UINT32)mips3.core->r[20], |
| 1143 | | (UINT32)(mips3.core->r[21] >> 32), (UINT32)mips3.core->r[21], |
| 1144 | | (UINT32)(mips3.core->r[22] >> 32), (UINT32)mips3.core->r[22], |
| 1145 | | (UINT32)(mips3.core->r[23] >> 32), (UINT32)mips3.core->r[23]); |
| 1146 | | printf("r24=%08X%08X r25=%08X%08X r26=%08X%08X r27=%08X%08X\n", |
| 1147 | | (UINT32)(mips3.core->r[24] >> 32), (UINT32)mips3.core->r[24], |
| 1148 | | (UINT32)(mips3.core->r[25] >> 32), (UINT32)mips3.core->r[25], |
| 1149 | | (UINT32)(mips3.core->r[26] >> 32), (UINT32)mips3.core->r[26], |
| 1150 | | (UINT32)(mips3.core->r[27] >> 32), (UINT32)mips3.core->r[27]); |
| 1151 | | printf("r28=%08X%08X r29=%08X%08X r30=%08X%08X r31=%08X%08X\n", |
| 1152 | | (UINT32)(mips3.core->r[28] >> 32), (UINT32)mips3.core->r[28], |
| 1153 | | (UINT32)(mips3.core->r[29] >> 32), (UINT32)mips3.core->r[29], |
| 1154 | | (UINT32)(mips3.core->r[30] >> 32), (UINT32)mips3.core->r[30], |
| 1155 | | (UINT32)(mips3.core->r[31] >> 32), (UINT32)mips3.core->r[31]); |
| 1156 | | printf(" hi=%08X%08X lo=%08X%08X\n", |
| 1157 | | (UINT32)(mips3.core->r[REG_HI] >> 32), (UINT32)mips3.core->r[REG_HI], |
| 1158 | | (UINT32)(mips3.core->r[REG_LO] >> 32), (UINT32)mips3.core->r[REG_LO]); |
| 1159 | | } |
| 1160 | | |
| 1161 | | |
| 1162 | | /*------------------------------------------------- |
| 1163 | | exception_trap - log any exceptions that |
| 1164 | | aren't interrupts |
| 1165 | | -------------------------------------------------*/ |
| 1166 | | |
| 1167 | | static void exception_trap(void) |
| 1168 | | { |
| 1169 | | if ((mips3.core->cpr[0][COP0_Cause] & 0xff) != 0) |
| 1170 | | printf("Exception: EPC=%08X Cause=%08X BadVAddr=%08X Jmp=%08X\n", (UINT32)mips3.core->cpr[0][COP0_EPC], (UINT32)mips3.core->cpr[0][COP0_Cause], (UINT32)mips3.core->cpr[0][COP0_BadVAddr], mips3.core->pc); |
| 1171 | | } |
| 1172 | | |
| 1173 | | |
| 1174 | | |
| 1175 | | /*************************************************************************** |
| 1176 | | COMMON ROUTINES |
| 1177 | | ***************************************************************************/ |
| 1178 | | |
| 1179 | | /*------------------------------------------------------------------ |
| 1180 | | generate_read_write_handlers |
| 1181 | | ------------------------------------------------------------------*/ |
| 1182 | | |
| 1183 | | static void generate_read_write_handlers(drc_core *drc, readwrite_handlers *handlers, const char *type, UINT8 flags) |
| 1184 | | { |
| 1185 | | char buffer[100]; |
| 1186 | | |
| 1187 | | handlers->read_byte_signed = drc->cache_top; |
| 1188 | | append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_byte_signed)); |
| 1189 | | sprintf(buffer, "%s.read_byte_signed:", type); |
| 1190 | | if (LOG_CODE) |
| 1191 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_byte_signed, drc->cache_top); |
| 1192 | | |
| 1193 | | handlers->read_byte_unsigned = drc->cache_top; |
| 1194 | | append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_byte_unsigned)); |
| 1195 | | sprintf(buffer, "%s.read_byte_unsigned:", type); |
| 1196 | | if (LOG_CODE) |
| 1197 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_byte_unsigned, drc->cache_top); |
| 1198 | | |
| 1199 | | handlers->read_half_signed = drc->cache_top; |
| 1200 | | append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_half_signed)); |
| 1201 | | sprintf(buffer, "%s.read_half_signed:", type); |
| 1202 | | if (LOG_CODE) |
| 1203 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_half_signed, drc->cache_top); |
| 1204 | | |
| 1205 | | handlers->read_half_unsigned = drc->cache_top; |
| 1206 | | append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_half_unsigned)); |
| 1207 | | sprintf(buffer, "%s.read_half_unsigned:", type); |
| 1208 | | if (LOG_CODE) |
| 1209 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_half_unsigned, drc->cache_top); |
| 1210 | | |
| 1211 | | handlers->read_word_signed = drc->cache_top; |
| 1212 | | append_readwrite_and_translate(drc, 4, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_word_signed)); |
| 1213 | | sprintf(buffer, "%s.read_word_signed:", type); |
| 1214 | | if (LOG_CODE) |
| 1215 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_signed, drc->cache_top); |
| 1216 | | |
| 1217 | | handlers->read_word_unsigned = drc->cache_top; |
| 1218 | | append_readwrite_and_translate(drc, 4, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_word_unsigned)); |
| 1219 | | sprintf(buffer, "%s.read_word_unsigned:", type); |
| 1220 | | if (LOG_CODE) |
| 1221 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_unsigned, drc->cache_top); |
| 1222 | | |
| 1223 | | handlers->read_word_masked = drc->cache_top; |
| 1224 | | append_readwrite_and_translate(drc, 4, ARW_READ | ARW_UNSIGNED | ARW_MASKED | flags, offsetof(readwrite_handlers, read_word_masked)); |
| 1225 | | sprintf(buffer, "%s.read_word_masked:", type); |
| 1226 | | if (LOG_CODE) |
| 1227 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_masked, drc->cache_top); |
| 1228 | | |
| 1229 | | handlers->read_double = drc->cache_top; |
| 1230 | | append_readwrite_and_translate(drc, 8, ARW_READ | flags, offsetof(readwrite_handlers, read_double)); |
| 1231 | | sprintf(buffer, "%s.read_double:", type); |
| 1232 | | if (LOG_CODE) |
| 1233 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_double, drc->cache_top); |
| 1234 | | |
| 1235 | | handlers->read_double_masked = drc->cache_top; |
| 1236 | | append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED | flags, offsetof(readwrite_handlers, read_double_masked)); |
| 1237 | | sprintf(buffer, "%s.read_double_masked:", type); |
| 1238 | | if (LOG_CODE) |
| 1239 | | x86log_disasm_code_range(mips3.log, buffer, handlers->read_double_masked, drc->cache_top); |
| 1240 | | |
| 1241 | | handlers->write_byte = drc->cache_top; |
| 1242 | | append_readwrite_and_translate(drc, 1, ARW_WRITE | flags, offsetof(readwrite_handlers, write_byte)); |
| 1243 | | sprintf(buffer, "%s.write_byte:", type); |
| 1244 | | if (LOG_CODE) |
| 1245 | | x86log_disasm_code_range(mips3.log, buffer, handlers->write_byte, drc->cache_top); |
| 1246 | | |
| 1247 | | handlers->write_half = drc->cache_top; |
| 1248 | | append_readwrite_and_translate(drc, 2, ARW_WRITE | flags, offsetof(readwrite_handlers, write_half)); |
| 1249 | | sprintf(buffer, "%s.write_half:", type); |
| 1250 | | if (LOG_CODE) |
| 1251 | | x86log_disasm_code_range(mips3.log, buffer, handlers->write_half, drc->cache_top); |
| 1252 | | |
| 1253 | | handlers->write_word = drc->cache_top; |
| 1254 | | append_readwrite_and_translate(drc, 4, ARW_WRITE | flags, offsetof(readwrite_handlers, write_word)); |
| 1255 | | sprintf(buffer, "%s.write_word:", type); |
| 1256 | | if (LOG_CODE) |
| 1257 | | x86log_disasm_code_range(mips3.log, buffer, handlers->write_word, drc->cache_top); |
| 1258 | | |
| 1259 | | handlers->write_word_masked = drc->cache_top; |
| 1260 | | append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED | flags, offsetof(readwrite_handlers, write_word_masked)); |
| 1261 | | sprintf(buffer, "%s.write_word_masked:", type); |
| 1262 | | if (LOG_CODE) |
| 1263 | | x86log_disasm_code_range(mips3.log, buffer, handlers->write_word_masked, drc->cache_top); |
| 1264 | | |
| 1265 | | handlers->write_double = drc->cache_top; |
| 1266 | | append_readwrite_and_translate(drc, 8, ARW_WRITE | flags, offsetof(readwrite_handlers, write_double)); |
| 1267 | | sprintf(buffer, "%s.write_double:", type); |
| 1268 | | if (LOG_CODE) |
| 1269 | | x86log_disasm_code_range(mips3.log, buffer, handlers->write_double, drc->cache_top); |
| 1270 | | |
| 1271 | | handlers->write_double_masked = drc->cache_top; |
| 1272 | | append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED | flags, offsetof(readwrite_handlers, write_double_masked)); |
| 1273 | | sprintf(buffer, "%s.write_double_masked:", type); |
| 1274 | | if (LOG_CODE) |
| 1275 | | x86log_disasm_code_range(mips3.log, buffer, handlers->write_double_masked, drc->cache_top); |
| 1276 | | } |
| 1277 | | |
| 1278 | | |
| 1279 | | /*------------------------------------------------------------------ |
| 1280 | | append_generate_exception |
| 1281 | | ------------------------------------------------------------------*/ |
| 1282 | | |
| 1283 | | static void append_generate_exception(drc_core *drc, UINT8 exception) |
| 1284 | | { |
| 1285 | | UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180; |
| 1286 | | emit_link link1, link2; |
| 1287 | | |
| 1288 | | if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) |
| 1289 | | { |
| 1290 | | /* assumes failed address is in P2 */ |
| 1291 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_P2); // mov [BadVAddr],p2 |
| 1292 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff |
| 1293 | | emit_and_r32_imm(DRCTOP, REG_P2, 0xffffe000); // and p2,0xffffe000 |
| 1294 | | emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_P2); // or [EntryHi],p2 |
| 1295 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000 |
| 1296 | | emit_shr_r32_imm(DRCTOP, REG_P2, 9); // shr p2,9 |
| 1297 | | emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_P2); // or [Context],p2 |
| 1298 | | } |
| 1299 | | |
| 1300 | | /* on entry, exception PC must be in REG_P1, and low bit set if in a delay slot */ |
| 1301 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[Cause] |
| 1302 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff |
| 1303 | | emit_test_r32_imm(DRCTOP, REG_P1, 1); // test p1,1 |
| 1304 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1305 | | emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000 |
| 1306 | | emit_sub_r32_imm(DRCTOP, REG_P1, 5); // sub p1,5 |
| 1307 | | |
| 1308 | | resolve_link(DRCTOP, &link1); // skip: |
| 1309 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_P1); // mov [EPC],p1 |
| 1310 | | if (exception) |
| 1311 | | emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2 |
| 1312 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [Cause],eax |
| 1313 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[SR] |
| 1314 | | emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL |
| 1315 | | emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV |
| 1316 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [SR],eax |
| 1317 | | emit_mov_r32_imm(DRCTOP, REG_P1, 0xbfc00200 + offset); // mov p1,0xbfc00200+offset |
| 1318 | | emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2 |
| 1319 | | emit_mov_r32_imm(DRCTOP, REG_P1, 0x80000000 + offset); // mov p1,0x80000000+offset |
| 1320 | | |
| 1321 | | resolve_link(DRCTOP, &link2); // skip2: |
| 1322 | | if (PRINTF_EXCEPTIONS) |
| 1323 | | { |
| 1324 | | emit_mov_m32_r32(DRCTOP, PCADDR, REG_P1); // mov [PC],p1 |
| 1325 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)exception_trap); // mov rax,exception_trap |
| 1326 | | emit_call_r64(DRCTOP, REG_RAX); // call rax |
| 1327 | | emit_mov_r32_m32(DRCTOP, REG_P1, PCADDR); // mov p1,[PC] |
| 1328 | | } |
| 1329 | | drc_append_dispatcher(drc); // dispatch |
| 1330 | | } |
| 1331 | | |
| 1332 | | |
| 1333 | | /*------------------------------------------------------------------ |
| 1334 | | append_handle_pc_tlb_mismatch |
| 1335 | | ------------------------------------------------------------------*/ |
| 1336 | | |
| 1337 | | static void append_handle_pc_tlb_mismatch(drc_core *drc) |
| 1338 | | { |
| 1339 | | #if 0 |
| 1340 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_R15D); // mov eax,edi |
| 1341 | | emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12 |
| 1342 | | emit_mov_r32_m32(DRCTOP, REG_EDX, MISD(REG_EAX, 4, &mips3.core->tlb_table)); // mov edx,tlb_table[eax*4] |
| 1343 | | emit_test_r32_imm(DRCTOP, REG_EDX, 2); // test edx,2 |
| 1344 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_R15D); // mov eax,edi |
| 1345 | | emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception |
| 1346 | | emit_mov_m32bd_r32(DRCTOP, drc->pcptr, REG_R15D); // mov [pcptr],edi |
| 1347 | | emit_jmp(DRCTOP, drc->recompile); // call recompile |
| 1348 | | #endif |
| 1349 | | } |
| 1350 | | |
| 1351 | | |
| 1352 | | /*------------------------------------------------------------------ |
| 1353 | | append_find_exception_handler |
| 1354 | | ------------------------------------------------------------------*/ |
| 1355 | | |
| 1356 | | static void append_find_exception_handler(drc_core *drc) |
| 1357 | | { |
| 1358 | | x86code *loop; |
| 1359 | | |
| 1360 | | emit_mov_r64_m64(DRCTOP, REG_RAX, MBD(REG_RSP, 0)); // mov rax,[rsp] |
| 1361 | | emit_mov_r64_imm(DRCTOP, REG_V5, EXCEPTION_ADDRESS_COOKIE); // mov v5,EXCEPTION_ADDRESS_COOKIE |
| 1362 | | emit_mov_r64_r64(DRCTOP, REG_V6, REG_RAX); // mov v6,rax |
| 1363 | | emit_and_r64_imm(DRCTOP, REG_RAX, ~7); // and rax,~7 |
| 1364 | | emit_add_r64_imm(DRCTOP, REG_RSP, 8); // add rsp,8 |
| 1365 | | emit_add_r64_imm(DRCTOP, REG_RAX, 8); // add rax,8 |
| 1366 | | loop = drc->cache_top; // loop: |
| 1367 | | emit_cmp_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_V5); // cmp [rax],v5 |
| 1368 | | emit_lea_r64_m64(DRCTOP, REG_RAX, MBD(REG_RAX, 8)); // lea rax,[rax+8] |
| 1369 | | emit_jcc(DRCTOP, COND_NE, loop); // jne loop |
| 1370 | | emit_cmp_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_V6); // cmp [rax],v6 |
| 1371 | | emit_lea_r64_m64(DRCTOP, REG_RAX, MBD(REG_RAX, 8)); // lea rax,[rax+8] |
| 1372 | | emit_jcc(DRCTOP, COND_NE, loop); // jne loop |
| 1373 | | emit_jmp_r64(DRCTOP, REG_RAX); // jmp rax |
| 1374 | | } |
| 1375 | | |
| 1376 | | |
| 1377 | | /*------------------------------------------------------------------ |
| 1378 | | append_direct_ram_read |
| 1379 | | ------------------------------------------------------------------*/ |
| 1380 | | |
| 1381 | | static void append_direct_ram_read(drc_core *drc, int size, UINT8 flags, void *rambase, offs_t ramstart) |
| 1382 | | { |
| 1383 | | void *adjbase = (UINT8 *)rambase - ramstart; |
| 1384 | | INT64 adjdisp = (UINT8 *)adjbase - (UINT8 *)drc->baseptr; |
| 1385 | | int raxrel = ((INT32)adjdisp != adjdisp); |
| 1386 | | |
| 1387 | | /* if we can't fit the delta to adjbase within an INT32, load RAX with the full address here */ |
| 1388 | | if (raxrel) |
| 1389 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)adjbase); |
| 1390 | | |
| 1391 | | /* fast RAM byte read */ |
| 1392 | | if (size == 1) |
| 1393 | | { |
| 1394 | | /* adjust for endianness */ |
| 1395 | | if (mips3.core->bigendian) |
| 1396 | | emit_xor_r32_imm(DRCTOP, REG_P1, 3); // xor p1,3 |
| 1397 | | |
| 1398 | | /* read rax-relative */ |
| 1399 | | if (raxrel) |
| 1400 | | { |
| 1401 | | if (flags & ARW_SIGNED) |
| 1402 | | emit_movsx_r64_m8(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsx rax,byte ptr [p1 + rax] |
| 1403 | | else |
| 1404 | | emit_movzx_r64_m8(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movzx rax,byte ptr [p1 + rax] |
| 1405 | | } |
| 1406 | | |
| 1407 | | /* read drc-relative */ |
| 1408 | | else |
| 1409 | | { |
| 1410 | | if (flags & ARW_SIGNED) |
| 1411 | | emit_movsx_r64_m8(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsx rax,byte ptr [p1 + adjbase] |
| 1412 | | else |
| 1413 | | emit_movzx_r64_m8(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movzx rax,byte ptr [p1 + adjbase] |
| 1414 | | } |
| 1415 | | } |
| 1416 | | |
| 1417 | | /* fast RAM halfword read */ |
| 1418 | | else if (size == 2) |
| 1419 | | { |
| 1420 | | /* adjust for endianness */ |
| 1421 | | if (mips3.core->bigendian) |
| 1422 | | emit_xor_r32_imm(DRCTOP, REG_P1, 2); // xor p1,2 |
| 1423 | | |
| 1424 | | /* read rax-relative */ |
| 1425 | | if (raxrel) |
| 1426 | | { |
| 1427 | | if (flags & ARW_SIGNED) |
| 1428 | | emit_movsx_r64_m16(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsx rax,word ptr [p1 + rax] |
| 1429 | | else |
| 1430 | | emit_movzx_r64_m16(DRCTOP, REG_EAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movzx rax,word ptr [p1 + rax] |
| 1431 | | } |
| 1432 | | |
| 1433 | | /* read drc-relative */ |
| 1434 | | else |
| 1435 | | { |
| 1436 | | if (flags & ARW_SIGNED) |
| 1437 | | emit_movsx_r64_m16(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsx rax,word ptr [p1 + adjbase] |
| 1438 | | else |
| 1439 | | emit_movzx_r64_m16(DRCTOP, REG_EAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movzx rax,word ptr [p1 + adjbase] |
| 1440 | | } |
| 1441 | | } |
| 1442 | | |
| 1443 | | /* fast RAM dword read */ |
| 1444 | | else if (size == 4) |
| 1445 | | { |
| 1446 | | /* read rax-relative */ |
| 1447 | | if (raxrel) |
| 1448 | | { |
| 1449 | | if (flags & ARW_SIGNED) |
| 1450 | | emit_movsxd_r64_m32(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsxd rax,dword ptr [p1 + rax] |
| 1451 | | else |
| 1452 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBISD(REG_RAX, REG_P1, 1, 0)); // mov eax,word ptr [p1 + rax] |
| 1453 | | } |
| 1454 | | |
| 1455 | | /* read drc-relative */ |
| 1456 | | else |
| 1457 | | { |
| 1458 | | if (flags & ARW_SIGNED) |
| 1459 | | emit_movsxd_r64_m32(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsxd rax,dword ptr [p1 + adjbase] |
| 1460 | | else |
| 1461 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MDRCISD(adjbase, REG_P1, 1, 0)); // mov eax,word ptr [p1 + adjbase] |
| 1462 | | } |
| 1463 | | } |
| 1464 | | |
| 1465 | | /* fast RAM qword read */ |
| 1466 | | else if (size == 8) |
| 1467 | | { |
| 1468 | | /* read rax-relative */ |
| 1469 | | if (raxrel) |
| 1470 | | emit_mov_r64_m64(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // mov rax,[p1 + rax] |
| 1471 | | |
| 1472 | | /* read drc-relative */ |
| 1473 | | else |
| 1474 | | emit_mov_r64_m64(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // mov rax,[p1 + adjbase] |
| 1475 | | |
| 1476 | | /* adjust for endianness */ |
| 1477 | | if (mips3.core->bigendian) |
| 1478 | | emit_ror_r64_imm(DRCTOP, REG_RAX, 32); // ror rax,32 |
| 1479 | | } |
| 1480 | | } |
| 1481 | | |
| 1482 | | |
| 1483 | | /*------------------------------------------------------------------ |
| 1484 | | append_direct_ram_write |
| 1485 | | ------------------------------------------------------------------*/ |
| 1486 | | |
| 1487 | | static void append_direct_ram_write(drc_core *drc, int size, UINT8 flags, void *rambase, offs_t ramstart) |
| 1488 | | { |
| 1489 | | void *adjbase = (UINT8 *)rambase - ramstart; |
| 1490 | | INT64 adjdisp = (UINT8 *)adjbase - (UINT8 *)drc->baseptr; |
| 1491 | | int raxrel = ((INT32)adjdisp != adjdisp); |
| 1492 | | |
| 1493 | | /* if we can't fit the delta to adjbase within an INT32, load RAX with the full address here */ |
| 1494 | | if (raxrel) |
| 1495 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)adjbase); |
| 1496 | | |
| 1497 | | /* fast RAM byte write */ |
| 1498 | | if (size == 1) |
| 1499 | | { |
| 1500 | | /* adjust for endianness */ |
| 1501 | | if (mips3.core->bigendian) |
| 1502 | | emit_xor_r32_imm(DRCTOP, REG_P1, 3); // xor p1,3 |
| 1503 | | |
| 1504 | | /* write either rax-relative or drc-relative */ |
| 1505 | | if (raxrel) |
| 1506 | | emit_mov_m8_r8(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2 |
| 1507 | | else |
| 1508 | | emit_mov_m8_r8(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2 |
| 1509 | | } |
| 1510 | | |
| 1511 | | /* fast RAM halfword write */ |
| 1512 | | else if (size == 2) |
| 1513 | | { |
| 1514 | | /* adjust for endianness */ |
| 1515 | | if (mips3.core->bigendian) |
| 1516 | | emit_xor_r32_imm(DRCTOP, REG_P1, 2); // xor p1,2 |
| 1517 | | |
| 1518 | | /* write either rax-relative or drc-relative */ |
| 1519 | | if (raxrel) |
| 1520 | | emit_mov_m16_r16(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2 |
| 1521 | | else |
| 1522 | | emit_mov_m16_r16(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2 |
| 1523 | | } |
| 1524 | | |
| 1525 | | /* fast RAM dword write */ |
| 1526 | | else if (size == 4) |
| 1527 | | { |
| 1528 | | /* unmasked */ |
| 1529 | | if (!(flags & ARW_MASKED)) |
| 1530 | | { |
| 1531 | | if (raxrel) |
| 1532 | | emit_mov_m32_r32(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2 |
| 1533 | | else |
| 1534 | | emit_mov_m32_r32(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2 |
| 1535 | | } |
| 1536 | | |
| 1537 | | /* masked */ |
| 1538 | | else |
| 1539 | | { |
| 1540 | | emit_mov_r32_r32(DRCTOP, REG_P4, REG_P3); // mov p4,p3 |
| 1541 | | emit_not_r32(DRCTOP, REG_P3); // not p3 |
| 1542 | | emit_and_r32_r32(DRCTOP, REG_P4, REG_P2); // and p4,p2 |
| 1543 | | if (raxrel) |
| 1544 | | emit_and_r32_m32(DRCTOP, REG_P3, MBISD(REG_RAX, REG_P1, 1, 0)); // and p3,[p1 + rax] |
| 1545 | | else |
| 1546 | | emit_and_r32_m32(DRCTOP, REG_P3, MDRCISD(adjbase, REG_P1, 1, 0)); // and p3,[p1 + adjbase] |
| 1547 | | emit_or_r32_r32(DRCTOP, REG_P4, REG_P3); // or p4,p3 |
| 1548 | | if (raxrel) |
| 1549 | | emit_mov_m32_r32(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P4); // mov [p1 + rax],p4 |
| 1550 | | else |
| 1551 | | emit_mov_m32_r32(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P4); // mov [p1 + adjbase],p4 |
| 1552 | | } |
| 1553 | | } |
| 1554 | | |
| 1555 | | /* fast RAM qword write */ |
| 1556 | | else if (size == 8) |
| 1557 | | { |
| 1558 | | /* adjust for endianness */ |
| 1559 | | if (mips3.core->bigendian) |
| 1560 | | emit_ror_r64_imm(DRCTOP, REG_P2, 32); // ror p2,32 |
| 1561 | | |
| 1562 | | /* unmasked */ |
| 1563 | | if (!(flags & ARW_MASKED)) |
| 1564 | | { |
| 1565 | | if (raxrel) |
| 1566 | | emit_mov_m64_r64(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2 |
| 1567 | | else |
| 1568 | | emit_mov_m64_r64(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2 |
| 1569 | | } |
| 1570 | | |
| 1571 | | /* masked */ |
| 1572 | | else |
| 1573 | | { |
| 1574 | | if (mips3.core->bigendian) |
| 1575 | | emit_ror_r64_imm(DRCTOP, REG_P3, 32); // ror p3,32 |
| 1576 | | emit_mov_r64_r64(DRCTOP, REG_P4, REG_P3); // mov p4,p3 |
| 1577 | | emit_not_r64(DRCTOP, REG_P3); // not p3 |
| 1578 | | emit_and_r64_r64(DRCTOP, REG_P4, REG_P2); // and p4,p2 |
| 1579 | | if (raxrel) |
| 1580 | | emit_and_r64_m64(DRCTOP, REG_P3, MBISD(REG_RAX, REG_P1, 1, 0)); // and p3,[p1 + rax] |
| 1581 | | else |
| 1582 | | emit_and_r64_m64(DRCTOP, REG_P3, MDRCISD(adjbase, REG_P1, 1, 0)); // and p3,[p1 + adjbase] |
| 1583 | | emit_or_r64_r64(DRCTOP, REG_P4, REG_P3); // or p4,p3 |
| 1584 | | if (raxrel) |
| 1585 | | emit_mov_m64_r64(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P4); // mov [p1 + rax],p4 |
| 1586 | | else |
| 1587 | | emit_mov_m64_r64(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P4); // mov [p1 + adjbase],p4 |
| 1588 | | } |
| 1589 | | } |
| 1590 | | } |
| 1591 | | |
| 1592 | | |
| 1593 | | /*------------------------------------------------------------------ |
| 1594 | | append_readwrite_and_translate |
| 1595 | | ------------------------------------------------------------------*/ |
| 1596 | | |
| 1597 | | static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags, UINT32 ptroffs) |
| 1598 | | { |
| 1599 | | UINT32 base = ((flags & ARW_CACHED) ? 0x80000000 : (flags & ARW_UNCACHED) ? 0xa0000000 : 0); |
| 1600 | | emit_link page_fault = { 0 }, handle_kernel = { 0 }, wrong_handler = { 0 }; |
| 1601 | | x86code *continue_mapped = NULL; |
| 1602 | | int ramnum; |
| 1603 | | |
| 1604 | | /* if the base is 0, this is a general case which may be paged; perform the translation first */ |
| 1605 | | /* the result of the translation produces the physical address inline in P1 */ |
| 1606 | | /* if a page fault occurs, we have to keep an original copy of the address in EAX */ |
| 1607 | | /* note that we use RAX and P4 as scratch registers */ |
| 1608 | | if (base == 0) |
| 1609 | | { |
| 1610 | | emit_test_r32_r32(DRCTOP, REG_P1, REG_P1); // test p1,p1 |
| 1611 | | emit_mov_r32_r32(DRCTOP, REG_P4, REG_P1); // mov p4,p1d |
| 1612 | | emit_jcc_near_link(DRCTOP, COND_S, &handle_kernel); // js handle_kernel |
| 1613 | | continue_mapped = drc->cache_top; // continue_mapped: |
| 1614 | | emit_mov_r32_r32(DRCTOP, REG_V5, REG_P1); // mov v5,p1 |
| 1615 | | emit_shr_r32_imm(DRCTOP, REG_P1, 12); // shr p1,12 |
| 1616 | | emit_mov_r32_m32(DRCTOP, REG_P1, MDRCISD(mips3.core->tlb_table, REG_P1, 4, 0)); // mov p1,tlb_table[p1*4] |
| 1617 | | emit_and_r32_imm(DRCTOP, REG_P4, 0xfff); // and p4,0xfff |
| 1618 | | emit_shr_r32_imm(DRCTOP, REG_P1, (flags & ARW_WRITE) ? 1 : 2); // shr p1,2/1 (read/write) |
| 1619 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(REG_P4, REG_P1, (flags & ARW_WRITE) ? 2 : 4, 0)); |
| 1620 | | // lea p1,[p4 + p1 * 4/2 (read/write)] |
| 1621 | | emit_jcc_near_link(DRCTOP, COND_C, &page_fault); // jc page_fault |
| 1622 | | } |
| 1623 | | |
| 1624 | | /* if the base is non-zero, this is a cached/uncached direct-mapped case; no translation necessary */ |
| 1625 | | /* just subtract the base from the address to get the physcial address */ |
| 1626 | | else |
| 1627 | | emit_sub_r32_imm(DRCTOP, REG_P1, base); // sub p1,base |
| 1628 | | |
| 1629 | | /* iterate over all fast RAM ranges looking for matches that can be handled directly */ |
| 1630 | | for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) |
| 1631 | | { |
| 1632 | | const fast_ram_info *raminfo = &mips3.fastram[ramnum]; |
| 1633 | | if (!COMPARE_AGAINST_C && !Machine->debug_mode && raminfo->base != NULL && (!(flags & ARW_WRITE) || !raminfo->readonly)) |
| 1634 | | { |
| 1635 | | emit_link notram1 = { 0 }, notram2 = { 0 }; |
| 1636 | | |
| 1637 | | /* if we have an end, check it first */ |
| 1638 | | if (raminfo->end != 0xffffffff) |
| 1639 | | { |
| 1640 | | emit_cmp_r32_imm(DRCTOP, REG_P1, raminfo->end); // cmp p1,fastram_end |
| 1641 | | emit_jcc_short_link(DRCTOP, COND_A, ¬ram1); // ja notram1 |
| 1642 | | } |
| 1643 | | |
| 1644 | | /* if we have a non-0 start, check it next */ |
| 1645 | | if (raminfo->start != 0x00000000) |
| 1646 | | { |
| 1647 | | emit_cmp_r32_imm(DRCTOP, REG_P1, raminfo->start); // cmp p1,fastram_start |
| 1648 | | emit_jcc_short_link(DRCTOP, COND_B, ¬ram2); // jb notram2 |
| 1649 | | } |
| 1650 | | |
| 1651 | | /* handle a fast RAM read */ |
| 1652 | | if (!(flags & ARW_WRITE)) |
| 1653 | | { |
| 1654 | | append_direct_ram_read(drc, size, flags, raminfo->base, raminfo->start); // <direct read> |
| 1655 | | emit_ret(DRCTOP); // ret |
| 1656 | | } |
| 1657 | | |
| 1658 | | /* handle a fast RAM write */ |
| 1659 | | else |
| 1660 | | { |
| 1661 | | append_direct_ram_write(drc, size, flags, raminfo->base, raminfo->start); // <direct write> |
| 1662 | | emit_ret(DRCTOP); // ret |
| 1663 | | } |
| 1664 | | |
| 1665 | | /* resolve links that skipped over us */ |
| 1666 | | if (raminfo->end != 0xffffffff) |
| 1667 | | resolve_link(DRCTOP, ¬ram1); // notram1: |
| 1668 | | if (raminfo->start != 0x00000000) |
| 1669 | | resolve_link(DRCTOP, ¬ram2); // notram2: |
| 1670 | | } |
| 1671 | | } |
| 1672 | | |
| 1673 | | /* failed to find it in fast RAM; make sure we are within our expected range */ |
| 1674 | | if (base != 0) |
| 1675 | | { |
| 1676 | | emit_cmp_r32_imm(DRCTOP, REG_P1, 0x20000000); // cmp p1,0x20000000 |
| 1677 | | emit_jcc_short_link(DRCTOP, COND_AE, &wrong_handler); // jae wrong_handler |
| 1678 | | } |
| 1679 | | |
| 1680 | | /* handle a write */ |
| 1681 | | if (flags & ARW_WRITE) |
| 1682 | | { |
| 1683 | | if (size == 1) |
| 1684 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writebyte)); // jmp writebyte |
| 1685 | | else if (size == 2) |
| 1686 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writehalf)); // jmp writehalf |
| 1687 | | else if (size == 4) |
| 1688 | | { |
| 1689 | | if (!(flags & ARW_MASKED)) |
| 1690 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writeword)); // jmp writeword |
| 1691 | | else |
| 1692 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writeword_masked)); // jmp writeword_masked |
| 1693 | | } |
| 1694 | | else |
| 1695 | | { |
| 1696 | | if (!(flags & ARW_MASKED)) |
| 1697 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writedouble)); // jmp writedouble |
| 1698 | | else |
| 1699 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writedouble_masked)); // jmp writedouble_masked |
| 1700 | | } |
| 1701 | | } |
| 1702 | | |
| 1703 | | /* handle a read */ |
| 1704 | | else |
| 1705 | | { |
| 1706 | | if (size == 1) |
| 1707 | | { |
| 1708 | | emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28 |
| 1709 | | emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readbyte)); // call readbyte |
| 1710 | | if (flags & ARW_SIGNED) |
| 1711 | | emit_movsx_r64_r8(DRCTOP, REG_RAX, REG_AL); // movsx rax,al |
| 1712 | | else |
| 1713 | | emit_movzx_r64_r8(DRCTOP, REG_RAX, REG_AL); // movzx rax,al |
| 1714 | | emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28 |
| 1715 | | emit_ret(DRCTOP); // ret |
| 1716 | | } |
| 1717 | | else if (size == 2) |
| 1718 | | { |
| 1719 | | emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28 |
| 1720 | | emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readhalf)); // call readhalf |
| 1721 | | if (flags & ARW_SIGNED) |
| 1722 | | emit_movsx_r64_r16(DRCTOP, REG_RAX, REG_AX); // movsx rax,ax |
| 1723 | | else |
| 1724 | | emit_movzx_r64_r16(DRCTOP, REG_RAX, REG_AX); // movzx rax,ax |
| 1725 | | emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28 |
| 1726 | | emit_ret(DRCTOP); // ret |
| 1727 | | } |
| 1728 | | else if (size == 4) |
| 1729 | | { |
| 1730 | | if (!(flags & ARW_MASKED)) |
| 1731 | | { |
| 1732 | | if (!(flags & ARW_SIGNED)) |
| 1733 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readword)); // jmp readword |
| 1734 | | else |
| 1735 | | { |
| 1736 | | emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28 |
| 1737 | | emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readword)); // call readword |
| 1738 | | emit_movsxd_r64_r32(DRCTOP, REG_RAX, REG_EAX); // movsxd rax,eax |
| 1739 | | emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28 |
| 1740 | | emit_ret(DRCTOP); // ret |
| 1741 | | } |
| 1742 | | } |
| 1743 | | else |
| 1744 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readword_masked)); // jmp readword_masked |
| 1745 | | } |
| 1746 | | else |
| 1747 | | { |
| 1748 | | if (!(flags & ARW_MASKED)) |
| 1749 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readdouble)); // jmp readdouble |
| 1750 | | else |
| 1751 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readdouble_masked)); // jmp readdouble_masked |
| 1752 | | } |
| 1753 | | } |
| 1754 | | |
| 1755 | | /* handle wrong handlers */ |
| 1756 | | if (base == 0) |
| 1757 | | { |
| 1758 | | resolve_link(DRCTOP, &handle_kernel); // handle_kernel: |
| 1759 | | emit_cmp_r32_imm(DRCTOP, REG_P1, 0xc0000000); // cmp p1,0xc0000000 |
| 1760 | | emit_jcc(DRCTOP, COND_AE, continue_mapped); // jae continue_mapped |
| 1761 | | emit_test_r32_imm(DRCTOP, REG_P1, 0x20000000); // test p1,0x20000000 |
| 1762 | | emit_cmovcc_r64_m64(DRCTOP, COND_Z, REG_RAX, MDRCD(&mips3.drcdata->cached, ptroffs)); |
| 1763 | | // mov rax,<cached version> |
| 1764 | | emit_cmovcc_r64_m64(DRCTOP, COND_NZ, REG_RAX, MDRCD(&mips3.drcdata->uncached, ptroffs)); |
| 1765 | | // mov rax,<uncached version> |
| 1766 | | emit_mov_r64_m64(DRCTOP, REG_P4, MBD(REG_RSP, 0)); // mov p4,[rsp] |
| 1767 | | emit_push_r64(DRCTOP, REG_RAX); // push rax |
| 1768 | | emit_sub_r64_r64(DRCTOP, REG_RAX, REG_P4); // sub rax,p4 |
| 1769 | | emit_mov_m32_r32(DRCTOP, MBD(REG_P4, -4), REG_EAX); // mov [p4-4],eax |
| 1770 | | emit_ret(DRCTOP); // ret |
| 1771 | | } |
| 1772 | | else |
| 1773 | | { |
| 1774 | | resolve_link(DRCTOP, &wrong_handler); // wrong_handler: |
| 1775 | | emit_mov_r64_m64(DRCTOP, REG_RAX, MDRCD(&mips3.drcdata->general, ptroffs)); |
| 1776 | | // mov rax,<general version> |
| 1777 | | emit_mov_r64_m64(DRCTOP, REG_P4, MBD(REG_RSP, 0)); // mov p4,[rsp] |
| 1778 | | emit_push_r64(DRCTOP, REG_RAX); // push rax |
| 1779 | | emit_sub_r64_r64(DRCTOP, REG_RAX, REG_P4); // sub rax,p4 |
| 1780 | | emit_mov_m32_r32(DRCTOP, MBD(REG_P4, -4), REG_EAX); // mov [p4-4],eax |
| 1781 | | emit_add_r32_imm(DRCTOP, REG_P1, base); // add p1,base |
| 1782 | | emit_ret(DRCTOP); // ret |
| 1783 | | } |
| 1784 | | |
| 1785 | | /* handle page faults */ |
| 1786 | | if (base == 0) |
| 1787 | | { |
| 1788 | | resolve_link(DRCTOP, &page_fault); // page_fault: |
| 1789 | | emit_mov_r32_r32(DRCTOP, REG_P2, REG_V5); // mov p2,v5 |
| 1790 | | emit_jmp(DRCTOP, mips3.drcdata->find_exception_handler); // jmp find_exception_handler |
| 1791 | | } |
| 1792 | | } |
| 1793 | | |
| 1794 | | |
| 1795 | | /*------------------------------------------------------------------ |
| 1796 | | append_explode_ccr31 |
| 1797 | | ------------------------------------------------------------------*/ |
| 1798 | | |
| 1799 | | static void append_explode_ccr31(drc_core *drc) |
| 1800 | | { |
| 1801 | | emit_link link1; |
| 1802 | | int i; |
| 1803 | | |
| 1804 | | /* new CCR31 value in EAX */ |
| 1805 | | emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1 << 23 |
| 1806 | | emit_mov_m32_r32(DRCTOP, CCR1ADDR(31), REG_EAX); // mov ccr[31],eax |
| 1807 | | emit_setcc_m8(DRCTOP, COND_NZ, CF1ADDR(0)); // setnz fcc[0] |
| 1808 | | if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) |
| 1809 | | for (i = 1; i <= 7; i++) |
| 1810 | | { |
| 1811 | | emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24 + i)); // test eax,1 << (24+i) |
| 1812 | | emit_setcc_m8(DRCTOP, COND_NZ, CF1ADDR(i)); // setnz fcc[i] |
| 1813 | | } |
| 1814 | | emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3 |
| 1815 | | emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1 |
| 1816 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1817 | | emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2 |
| 1818 | | resolve_link(DRCTOP, &link1); // skip: |
| 1819 | | drc_append_set_sse_rounding(drc, REG_EAX); // set_rounding(EAX) |
| 1820 | | emit_ret(DRCTOP); // ret |
| 1821 | | } |
| 1822 | | |
| 1823 | | |
| 1824 | | /*------------------------------------------------------------------ |
| 1825 | | append_recover_ccr31 |
| 1826 | | ------------------------------------------------------------------*/ |
| 1827 | | |
| 1828 | | static void append_recover_ccr31(drc_core *drc) |
| 1829 | | { |
| 1830 | | int i; |
| 1831 | | |
| 1832 | | emit_movsxd_r64_m32(DRCTOP, REG_RAX, CCR1ADDR(31)); // movsxd rax,ccr1[rd] |
| 1833 | | emit_and_r64_imm(DRCTOP, REG_RAX, ~0xfe800000); // and rax,~0xfe800000 |
| 1834 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 1835 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR(0), 0); // cmp fcc[0],0 |
| 1836 | | emit_setcc_r8(DRCTOP, COND_NZ, REG_DL); // setnz dl |
| 1837 | | emit_shl_r32_imm(DRCTOP, REG_EDX, 23); // shl edx,23 |
| 1838 | | emit_or_r64_r64(DRCTOP, REG_RAX, REG_RDX); // or rax,rdx |
| 1839 | | if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) |
| 1840 | | for (i = 1; i <= 7; i++) |
| 1841 | | { |
| 1842 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR(i), 0); // cmp fcc[i],0 |
| 1843 | | emit_setcc_r8(DRCTOP, COND_NZ, REG_DL); // setnz dl |
| 1844 | | emit_shl_r32_imm(DRCTOP, REG_EDX, 24+i); // shl edx,24+i |
| 1845 | | emit_or_r64_r64(DRCTOP, REG_RAX, REG_RDX); // or rax,rdx |
| 1846 | | } |
| 1847 | | emit_ret(DRCTOP); // ret |
| 1848 | | } |
| 1849 | | |
| 1850 | | |
| 1851 | | /*------------------------------------------------------------------ |
| 1852 | | append_check_interrupts |
| 1853 | | ------------------------------------------------------------------*/ |
| 1854 | | |
| 1855 | | static void append_check_interrupts(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 1856 | | { |
| 1857 | | emit_link link1, link2, link3 = { 0 }; |
| 1858 | | |
| 1859 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[Cause] |
| 1860 | | emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[Status] |
| 1861 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00 |
| 1862 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1863 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [Status],SR_IE |
| 1864 | | emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip |
| 1865 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [Status],SR_EXL | SR_ERL |
| 1866 | | if (desc == NULL) |
| 1867 | | { |
| 1868 | | emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc] |
| 1869 | | emit_jcc_short_link(DRCTOP, COND_NZ, &link3); // jnz skip |
| 1870 | | emit_jmp_m64(DRCTOP, MDRC(&mips3.drcdata->generate_interrupt_exception)); // jmp generate_interrupt_exception |
| 1871 | | } |
| 1872 | | else |
| 1873 | | oob_request_callback(drc, COND_Z, oob_interrupt_cleanup, compiler, desc, mips3.drcdata->generate_interrupt_exception); |
| 1874 | | resolve_link(DRCTOP, &link1); // skip: |
| 1875 | | resolve_link(DRCTOP, &link2); |
| 1876 | | if (desc == NULL) |
| 1877 | | resolve_link(DRCTOP, &link3); |
| 1878 | | } |
| 1879 | | |
| 1880 | | |
| 1881 | | |
| 1882 | | /*************************************************************************** |
| 1883 | | RECOMPILATION HELPERS |
| 1884 | | ***************************************************************************/ |
| 1885 | | |
| 1886 | | /*------------------------------------------------- |
| 1887 | | emit_load_register_value - load a register |
| 1888 | | either as a constant or as a register |
| 1889 | | -------------------------------------------------*/ |
| 1890 | | |
| 1891 | | static void emit_load_register_value(drc_core *drc, compiler_state *compiler, UINT8 dstreg, mipsreg_state regstate) |
| 1892 | | { |
| 1893 | | /* must be live or constant */ |
| 1894 | | assert(ISCONST(regstate) || ISLIVE(regstate)); |
| 1895 | | |
| 1896 | | /* if the register is constant, do an immediate load */ |
| 1897 | | if (ISCONST(regstate)) |
| 1898 | | { |
| 1899 | | INT32 mipsval = CONSTVAL(regstate); |
| 1900 | | if (mipsval != 0) |
| 1901 | | emit_mov_r64_imm(DRCTOP, dstreg, mipsval); |
| 1902 | | else |
| 1903 | | emit_xor_r32_r32(DRCTOP, dstreg, dstreg); |
| 1904 | | } |
| 1905 | | |
| 1906 | | /* otherwise, load from the allocated register, but only if different */ |
| 1907 | | else |
| 1908 | | { |
| 1909 | | UINT8 srcreg = X86REG(regstate); |
| 1910 | | if (dstreg != srcreg) |
| 1911 | | emit_mov_r64_r64(DRCTOP, dstreg, srcreg); |
| 1912 | | } |
| 1913 | | } |
| 1914 | | |
| 1915 | | |
| 1916 | | /*------------------------------------------------- |
| 1917 | | emit_set_constant_value - set a constant |
| 1918 | | value; if it is too large, allocate a |
| 1919 | | register and populate it |
| 1920 | | -------------------------------------------------*/ |
| 1921 | | |
| 1922 | | static void emit_set_constant_value(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT64 constval) |
| 1923 | | { |
| 1924 | | /* ignore reigster 0 destination */ |
| 1925 | | if (mipsreg == 0) |
| 1926 | | return; |
| 1927 | | |
| 1928 | | /* if we fit in 32-bits, just continue the constant charade */ |
| 1929 | | if ((INT32)constval == (INT64)constval) |
| 1930 | | compiler_register_set_constant(compiler, mipsreg, constval); |
| 1931 | | |
| 1932 | | /* otherwise, allocate a new register and move the result into it */ |
| 1933 | | else |
| 1934 | | { |
| 1935 | | mipsreg_state resultreg = compiler_register_allocate(drc, compiler, desc, mipsreg, ALLOC_DST | ALLOC_DIRTY); |
| 1936 | | emit_mov_r64_imm(DRCTOP, X86REG(resultreg), constval); // mov <rt>,result |
| 1937 | | } |
| 1938 | | } |
| 1939 | | |
| 1940 | | |
| 1941 | | /*------------------------------------------------------------------ |
| 1942 | | emit_flush_cycles_before_instruction |
| 1943 | | ------------------------------------------------------------------*/ |
| 1944 | | |
| 1945 | | static void emit_flush_cycles_before_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT32 cycles_to_leave) |
| 1946 | | { |
| 1947 | | /* if we have cycles, subtract them now */ |
| 1948 | | if (compiler->cycles - cycles_to_leave != 0) |
| 1949 | | emit_sub_m32_imm(DRCTOP, ICOUNTADDR, compiler->cycles - cycles_to_leave); // sub [icount],cycles |
| 1950 | | |
| 1951 | | /* clear out compiler counts */ |
| 1952 | | compiler->cycles = cycles_to_leave; |
| 1953 | | } |
| 1954 | | |
| 1955 | | |
| 1956 | | /*------------------------------------------------------------------ |
| 1957 | | emit_update_cycles_pc_and_flush |
| 1958 | | ------------------------------------------------------------------*/ |
| 1959 | | |
| 1960 | | static void emit_update_cycles_pc_and_flush(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, offs_t destpc) |
| 1961 | | { |
| 1962 | | /* if we have cycles, subtract them now */ |
| 1963 | | emit_sub_m32_imm(DRCTOP, ICOUNTADDR, compiler->cycles); // sub [icount],cycles |
| 1964 | | |
| 1965 | | /* clear out compiler counts */ |
| 1966 | | compiler->cycles = 0; |
| 1967 | | |
| 1968 | | /* if we have an opcode descriptor, make this an oob */ |
| 1969 | | if (desc != NULL) |
| 1970 | | oob_request_callback(drc, COND_S, oob_interrupt_cleanup, compiler, desc, mips3.drc->exit_point); |
| 1971 | | |
| 1972 | | /* otherwise, do it inline */ |
| 1973 | | else |
| 1974 | | { |
| 1975 | | /* load the target PC into P1 */ |
| 1976 | | if (destpc != BRANCH_TARGET_DYNAMIC) |
| 1977 | | emit_mov_r32_imm(DRCTOP, REG_P1, destpc); // mov p1,destpc |
| 1978 | | else |
| 1979 | | emit_mov_r32_m32(DRCTOP, REG_P1, MBD(REG_RSP, SPOFFS_NEXTPC)); // mov p1,[esp+nextpc] |
| 1980 | | |
| 1981 | | /* flush any live registers */ |
| 1982 | | compiler_register_flush_all(drc, compiler); |
| 1983 | | |
| 1984 | | /* if we subtracted cycles and went negative, time to exit */ |
| 1985 | | emit_jcc(DRCTOP, COND_S, mips3.drc->exit_point); // js exit_point |
| 1986 | | } |
| 1987 | | } |
| 1988 | | |
| 1989 | | |
| 1990 | | /*------------------------------------------------------------------ |
| 1991 | | emit_delay_slot_and_branch |
| 1992 | | ------------------------------------------------------------------*/ |
| 1993 | | |
| 1994 | | static void emit_delay_slot_and_branch(drc_core *drc, const compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg) |
| 1995 | | { |
| 1996 | | compiler_state compiler_temp = *compiler; |
| 1997 | | |
| 1998 | | /* set the link if needed */ |
| 1999 | | if (linkreg != 0) |
| 2000 | | compiler_register_set_constant(&compiler_temp, linkreg, (INT32)(desc->pc + 8)); // <link> = pc + 8 |
| 2001 | | |
| 2002 | | /* compile the delay slot using temporary compiler state */ |
| 2003 | | assert(desc->delay != NULL); |
| 2004 | | compile_one(drc, &compiler_temp, desc->delay); // <next instruction> |
| 2005 | | |
| 2006 | | /* update the cycles and load the new PC in case we need to stop here */ |
| 2007 | | emit_update_cycles_pc_and_flush(drc, &compiler_temp, NULL, desc->targetpc); |
| 2008 | | |
| 2009 | | /* otherwise, append a dispatcher */ |
| 2010 | | if (desc->targetpc != BRANCH_TARGET_DYNAMIC) |
| 2011 | | drc_append_tentative_fixed_dispatcher(drc, desc->targetpc, FALSE); // <redispatch> |
| 2012 | | else |
| 2013 | | drc_append_dispatcher(drc); // <redispatch> |
| 2014 | | } |
| 2015 | | |
| 2016 | | |
| 2017 | | /*------------------------------------------------------------------ |
| 2018 | | emit_fixed_byte_read |
| 2019 | | ------------------------------------------------------------------*/ |
| 2020 | | |
| 2021 | | static int emit_fixed_byte_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address) |
| 2022 | | { |
| 2023 | | void *fastram = fastram_ptr(address, 1, FALSE); |
| 2024 | | |
| 2025 | | /* if we can't do fast RAM, we need to make the call */ |
| 2026 | | if (fastram == NULL) |
| 2027 | | { |
| 2028 | | emit_mov_r32_imm(DRCTOP, REG_P1, address); // mov p1,address |
| 2029 | | if (is_unsigned) |
| 2030 | | emit_call(DRCTOP, mips3.drcdata->general.read_byte_unsigned); // call read_byte_unsigned |
| 2031 | | else |
| 2032 | | emit_call(DRCTOP, mips3.drcdata->general.read_byte_signed); // call read_byte_signed |
| 2033 | | |
| 2034 | | /* handle exceptions */ |
| 2035 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 2036 | | if (destreg != REG_RAX) |
| 2037 | | emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax |
| 2038 | | } |
| 2039 | | |
| 2040 | | /* if we can do fastram, emit the right form */ |
| 2041 | | else |
| 2042 | | { |
| 2043 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2044 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2045 | | |
| 2046 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2047 | | if (raxrel) |
| 2048 | | { |
| 2049 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2050 | | if (is_unsigned) |
| 2051 | | emit_movzx_r64_m8(DRCTOP, destreg, MBD(REG_RAX, 0)); // movzx destreg,byte ptr [rax] |
| 2052 | | else |
| 2053 | | emit_movsx_r64_m8(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsx destreg,byte ptr [rax] |
| 2054 | | } |
| 2055 | | |
| 2056 | | /* read drc-relative */ |
| 2057 | | else |
| 2058 | | { |
| 2059 | | if (is_unsigned) |
| 2060 | | emit_movzx_r64_m8(DRCTOP, destreg, MDRC(fastram)); // movzx destreg,byte ptr [p1 + adjbase] |
| 2061 | | else |
| 2062 | | emit_movsx_r64_m8(DRCTOP, destreg, MDRC(fastram)); // movsx destreg,byte ptr [p1 + adjbase] |
| 2063 | | } |
| 2064 | | } |
| 2065 | | return (fastram != NULL); |
| 2066 | | } |
| 2067 | | |
| 2068 | | |
| 2069 | | /*------------------------------------------------------------------ |
| 2070 | | emit_fixed_half_read |
| 2071 | | ------------------------------------------------------------------*/ |
| 2072 | | |
| 2073 | | static int emit_fixed_half_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address) |
| 2074 | | { |
| 2075 | | void *fastram = fastram_ptr(address & ~1, 2, FALSE); |
| 2076 | | |
| 2077 | | /* if we can't do fast RAM, we need to make the call */ |
| 2078 | | if (fastram == NULL) |
| 2079 | | { |
| 2080 | | emit_mov_r32_imm(DRCTOP, REG_P1, address & ~1); // mov p1,address & ~1 |
| 2081 | | if (is_unsigned) |
| 2082 | | emit_call(DRCTOP, mips3.drcdata->general.read_half_unsigned); // call read_half_unsigned |
| 2083 | | else |
| 2084 | | emit_call(DRCTOP, mips3.drcdata->general.read_half_signed); // call read_half_signed |
| 2085 | | |
| 2086 | | /* handle exceptions */ |
| 2087 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 2088 | | if (destreg != REG_RAX) |
| 2089 | | emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax |
| 2090 | | } |
| 2091 | | |
| 2092 | | /* if we can do fastram, emit the right form */ |
| 2093 | | else |
| 2094 | | { |
| 2095 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2096 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2097 | | |
| 2098 | | /* read rax-relative */ |
| 2099 | | if (raxrel) |
| 2100 | | { |
| 2101 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2102 | | if (is_unsigned) |
| 2103 | | emit_movzx_r64_m16(DRCTOP, destreg, MBD(REG_RAX, 0)); // movzx destreg,word ptr [rax] |
| 2104 | | else |
| 2105 | | emit_movsx_r64_m16(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsx destreg,word ptr [rax] |
| 2106 | | } |
| 2107 | | |
| 2108 | | /* read drc-relative */ |
| 2109 | | else |
| 2110 | | { |
| 2111 | | if (is_unsigned) |
| 2112 | | emit_movzx_r64_m16(DRCTOP, destreg, MDRC(fastram)); // movzx destreg,word ptr [p1 + adjbase] |
| 2113 | | else |
| 2114 | | emit_movsx_r64_m16(DRCTOP, destreg, MDRC(fastram)); // movsx destreg,word ptr [p1 + adjbase] |
| 2115 | | } |
| 2116 | | } |
| 2117 | | return (fastram != NULL); |
| 2118 | | } |
| 2119 | | |
| 2120 | | |
| 2121 | | /*------------------------------------------------------------------ |
| 2122 | | emit_fixed_word_read |
| 2123 | | ------------------------------------------------------------------*/ |
| 2124 | | |
| 2125 | | static int emit_fixed_word_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address, UINT32 mask) |
| 2126 | | { |
| 2127 | | void *fastram = fastram_ptr(address & ~3, 4, FALSE); |
| 2128 | | |
| 2129 | | /* if we can't do fast RAM, we need to make the call */ |
| 2130 | | if (fastram == NULL) |
| 2131 | | { |
| 2132 | | emit_mov_r32_imm(DRCTOP, REG_P1, address & ~3); // mov p1,address & ~3 |
| 2133 | | if (mask != 0xffffffff) |
| 2134 | | { |
| 2135 | | emit_mov_r32_imm(DRCTOP, REG_P2, (INT32)mask); // mov p2,mask |
| 2136 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_masked); // call read_word_masked |
| 2137 | | } |
| 2138 | | else if (is_unsigned) |
| 2139 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call read_word_unsigned |
| 2140 | | else |
| 2141 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_signed); // call read_word_signed |
| 2142 | | |
| 2143 | | /* handle exceptions */ |
| 2144 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 2145 | | if (destreg != REG_RAX) |
| 2146 | | emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax |
| 2147 | | } |
| 2148 | | |
| 2149 | | /* if we can do fastram, emit the right form */ |
| 2150 | | else |
| 2151 | | { |
| 2152 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2153 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2154 | | |
| 2155 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2156 | | if (raxrel) |
| 2157 | | { |
| 2158 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2159 | | if (is_unsigned) |
| 2160 | | emit_mov_r32_m32(DRCTOP, destreg, MBD(REG_RAX, 0)); // mov destreg,word ptr [rax] |
| 2161 | | else |
| 2162 | | emit_movsxd_r64_m32(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsxd destreg,dword ptr [rax] |
| 2163 | | } |
| 2164 | | |
| 2165 | | /* read drc-relative */ |
| 2166 | | else |
| 2167 | | { |
| 2168 | | if (is_unsigned) |
| 2169 | | emit_mov_r32_m32(DRCTOP, destreg, MDRC(fastram)); // mov destreg,word ptr [p1 + adjbase] |
| 2170 | | else |
| 2171 | | emit_movsxd_r64_m32(DRCTOP, destreg, MDRC(fastram)); // movsxd destreg,dword ptr [p1 + adjbase] |
| 2172 | | } |
| 2173 | | } |
| 2174 | | return (fastram != NULL); |
| 2175 | | } |
| 2176 | | |
| 2177 | | |
| 2178 | | /*------------------------------------------------------------------ |
| 2179 | | emit_fixed_double_read |
| 2180 | | ------------------------------------------------------------------*/ |
| 2181 | | |
| 2182 | | static int emit_fixed_double_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, offs_t address, UINT64 mask) |
| 2183 | | { |
| 2184 | | void *fastram = fastram_ptr(address & ~7, 8, FALSE); |
| 2185 | | |
| 2186 | | /* if we can't do fast RAM, we need to make the call */ |
| 2187 | | if (fastram == NULL) |
| 2188 | | { |
| 2189 | | emit_mov_r32_imm(DRCTOP, REG_P1, address & ~7); // mov p1,address & ~7 |
| 2190 | | if (mask != U64(0xffffffffffffffff)) |
| 2191 | | { |
| 2192 | | emit_mov_r64_imm(DRCTOP, REG_P2, mask); // mov p2,mask |
| 2193 | | emit_call(DRCTOP, mips3.drcdata->general.read_double_masked); // call read_double_masked |
| 2194 | | } |
| 2195 | | else |
| 2196 | | emit_call(DRCTOP, mips3.drcdata->general.read_double); // call read_double |
| 2197 | | |
| 2198 | | /* handle exceptions */ |
| 2199 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 2200 | | if (destreg != REG_RAX) |
| 2201 | | emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax |
| 2202 | | } |
| 2203 | | |
| 2204 | | /* if we can do fastram, emit the right form */ |
| 2205 | | else |
| 2206 | | { |
| 2207 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2208 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2209 | | |
| 2210 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2211 | | if (raxrel) |
| 2212 | | { |
| 2213 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2214 | | emit_mov_r64_m64(DRCTOP, destreg, MBD(REG_RAX, 0)); // mov destreg,[rax] |
| 2215 | | } |
| 2216 | | |
| 2217 | | /* read drc-relative */ |
| 2218 | | else |
| 2219 | | emit_mov_r64_m64(DRCTOP, destreg, MDRC(fastram)); // mov destreg,[p1 + adjbase] |
| 2220 | | |
| 2221 | | /* adjust for endianness */ |
| 2222 | | if (mips3.core->bigendian) |
| 2223 | | emit_ror_r64_imm(DRCTOP, destreg, 32); // ror destreg,32 |
| 2224 | | } |
| 2225 | | return (fastram != NULL); |
| 2226 | | } |
| 2227 | | |
| 2228 | | |
| 2229 | | /*------------------------------------------------------------------ |
| 2230 | | emit_fixed_byte_write |
| 2231 | | ------------------------------------------------------------------*/ |
| 2232 | | |
| 2233 | | static int emit_fixed_byte_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address) |
| 2234 | | { |
| 2235 | | void *fastram = fastram_ptr(address, 1, TRUE); |
| 2236 | | |
| 2237 | | assert(ISCONST(srcreg) || X86REG(srcreg != REG_P1)); |
| 2238 | | |
| 2239 | | /* if we can't do fast RAM, we need to make the call */ |
| 2240 | | if (fastram == NULL) |
| 2241 | | { |
| 2242 | | emit_mov_r32_imm(DRCTOP, REG_P1, address); // mov p1,address |
| 2243 | | if (ISCONST(srcreg)) |
| 2244 | | emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,<srcreg> |
| 2245 | | else if (X86REG(srcreg) != REG_P2) |
| 2246 | | emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,<srcreg> |
| 2247 | | emit_call(DRCTOP, mips3.drcdata->general.write_byte); // call write_byte |
| 2248 | | |
| 2249 | | /* handle exceptions */ |
| 2250 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 2251 | | } |
| 2252 | | |
| 2253 | | /* if we can do fastram, emit the right form */ |
| 2254 | | else |
| 2255 | | { |
| 2256 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2257 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2258 | | |
| 2259 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2260 | | if (raxrel) |
| 2261 | | { |
| 2262 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2263 | | if (ISCONST(srcreg)) |
| 2264 | | emit_mov_m8_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval |
| 2265 | | else |
| 2266 | | emit_mov_m8_r8(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],<srcreg> |
| 2267 | | } |
| 2268 | | |
| 2269 | | /* write drc-relative */ |
| 2270 | | else |
| 2271 | | { |
| 2272 | | if (ISCONST(srcreg)) |
| 2273 | | emit_mov_m8_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval |
| 2274 | | else |
| 2275 | | emit_mov_m8_r8(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg |
| 2276 | | } |
| 2277 | | } |
| 2278 | | return (fastram != NULL); |
| 2279 | | } |
| 2280 | | |
| 2281 | | |
| 2282 | | /*------------------------------------------------------------------ |
| 2283 | | emit_fixed_half_write |
| 2284 | | ------------------------------------------------------------------*/ |
| 2285 | | |
| 2286 | | static int emit_fixed_half_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address) |
| 2287 | | { |
| 2288 | | void *fastram = fastram_ptr(address & ~1, 2, TRUE); |
| 2289 | | |
| 2290 | | assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1); |
| 2291 | | |
| 2292 | | /* if we can't do fast RAM, we need to make the call */ |
| 2293 | | if (fastram == NULL) |
| 2294 | | { |
| 2295 | | emit_mov_r32_imm(DRCTOP, REG_P1, address & ~1); // mov p1,address & ~1 |
| 2296 | | if (ISCONST(srcreg)) |
| 2297 | | emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval |
| 2298 | | else if (X86REG(srcreg) != REG_P2) |
| 2299 | | emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg |
| 2300 | | emit_call(DRCTOP, mips3.drcdata->general.write_half); // call write_half |
| 2301 | | |
| 2302 | | /* handle exceptions */ |
| 2303 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 2304 | | } |
| 2305 | | |
| 2306 | | /* if we can do fastram, emit the right form */ |
| 2307 | | else |
| 2308 | | { |
| 2309 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2310 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2311 | | |
| 2312 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2313 | | if (raxrel) |
| 2314 | | { |
| 2315 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2316 | | if (ISCONST(srcreg)) |
| 2317 | | emit_mov_m16_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval |
| 2318 | | else |
| 2319 | | emit_mov_m16_r16(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg |
| 2320 | | } |
| 2321 | | |
| 2322 | | /* write drc-relative */ |
| 2323 | | else |
| 2324 | | { |
| 2325 | | if (ISCONST(srcreg)) |
| 2326 | | emit_mov_m16_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval |
| 2327 | | else |
| 2328 | | emit_mov_m16_r16(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg |
| 2329 | | } |
| 2330 | | } |
| 2331 | | return (fastram != NULL); |
| 2332 | | } |
| 2333 | | |
| 2334 | | |
| 2335 | | /*------------------------------------------------------------------ |
| 2336 | | emit_fixed_word_write |
| 2337 | | ------------------------------------------------------------------*/ |
| 2338 | | |
| 2339 | | static int emit_fixed_word_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address, UINT32 mask) |
| 2340 | | { |
| 2341 | | void *fastram = fastram_ptr(address & ~3, 4, TRUE); |
| 2342 | | |
| 2343 | | assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1); |
| 2344 | | assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P3); |
| 2345 | | |
| 2346 | | /* if we can't do fast RAM, we need to make the call */ |
| 2347 | | if (fastram == NULL) |
| 2348 | | { |
| 2349 | | emit_mov_r32_imm(DRCTOP, REG_P1, address & ~3); // mov p1,address & ~3 |
| 2350 | | if (ISCONST(srcreg)) |
| 2351 | | emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval |
| 2352 | | else if (X86REG(srcreg) != REG_P2) |
| 2353 | | emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg |
| 2354 | | if (mask == 0xffffffff) |
| 2355 | | emit_call(DRCTOP, mips3.drcdata->general.write_word); // call write_word |
| 2356 | | else |
| 2357 | | { |
| 2358 | | emit_mov_r32_imm(DRCTOP, REG_P3, mask); // mov p3,mask |
| 2359 | | emit_call(DRCTOP, mips3.drcdata->general.write_word_masked); // call write_word_masked |
| 2360 | | } |
| 2361 | | |
| 2362 | | /* handle exceptions */ |
| 2363 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 2364 | | } |
| 2365 | | |
| 2366 | | /* if we can do fastram, emit the right form */ |
| 2367 | | else |
| 2368 | | { |
| 2369 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2370 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2371 | | |
| 2372 | | /* non-masked case */ |
| 2373 | | if (mask == 0xffffffff) |
| 2374 | | { |
| 2375 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2376 | | if (raxrel) |
| 2377 | | { |
| 2378 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2379 | | if (ISCONST(srcreg)) |
| 2380 | | emit_mov_m32_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval |
| 2381 | | else |
| 2382 | | emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg |
| 2383 | | } |
| 2384 | | |
| 2385 | | /* write drc-relative */ |
| 2386 | | else |
| 2387 | | { |
| 2388 | | if (ISCONST(srcreg)) |
| 2389 | | emit_mov_m32_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval |
| 2390 | | else |
| 2391 | | emit_mov_m32_r32(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg |
| 2392 | | } |
| 2393 | | } |
| 2394 | | |
| 2395 | | /* masked case */ |
| 2396 | | else |
| 2397 | | { |
| 2398 | | if (raxrel) |
| 2399 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2400 | | else |
| 2401 | | emit_lea_r64_m64(DRCTOP, REG_RAX, MDRC(fastram)); // lea rax,[fastram] |
| 2402 | | |
| 2403 | | /* always write rax-relative */ |
| 2404 | | if (ISCONST(srcreg)) |
| 2405 | | { |
| 2406 | | emit_mov_r32_m32(DRCTOP, REG_P2, MBD(REG_RAX, 0)); // mov p2,[rax] |
| 2407 | | emit_and_r32_imm(DRCTOP, REG_P2, ~mask); // and p2,~mask |
| 2408 | | emit_or_r32_imm(DRCTOP, REG_P2, CONSTVAL(srcreg) & mask); // or p2,constval & mask |
| 2409 | | emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), REG_P2); // mov [rax],p2 |
| 2410 | | } |
| 2411 | | else |
| 2412 | | { |
| 2413 | | emit_mov_r32_m32(DRCTOP, REG_P3, MBD(REG_RAX, 0)); // mov p3,[rax] |
| 2414 | | if (X86REG(srcreg) != REG_P2) |
| 2415 | | emit_mov_r32_r32(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg |
| 2416 | | emit_and_r32_imm(DRCTOP, REG_P3, ~mask); // and p3,~mask |
| 2417 | | emit_and_r32_imm(DRCTOP, REG_P2, mask); // and p2,mask |
| 2418 | | emit_or_r32_r32(DRCTOP, REG_P3, REG_P2); // or p3,p2 |
| 2419 | | emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), REG_P3); // mov [rax],p3 |
| 2420 | | } |
| 2421 | | } |
| 2422 | | } |
| 2423 | | return (fastram != NULL); |
| 2424 | | } |
| 2425 | | |
| 2426 | | |
| 2427 | | /*------------------------------------------------------------------ |
| 2428 | | emit_fixed_double_write |
| 2429 | | ------------------------------------------------------------------*/ |
| 2430 | | |
| 2431 | | static int emit_fixed_double_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address, UINT64 mask) |
| 2432 | | { |
| 2433 | | void *fastram = fastram_ptr(address & ~7, 8, TRUE); |
| 2434 | | |
| 2435 | | assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1); |
| 2436 | | assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P3); |
| 2437 | | assert((INT32)CONSTVAL(srcreg) == (INT64)CONSTVAL(srcreg)); |
| 2438 | | |
| 2439 | | /* if we can't do fast RAM, we need to make the call */ |
| 2440 | | if (fastram == NULL) |
| 2441 | | { |
| 2442 | | emit_mov_r32_imm(DRCTOP, REG_P1, address & ~7); // mov p1,address & ~7 |
| 2443 | | if (ISCONST(srcreg)) |
| 2444 | | emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval |
| 2445 | | else if (X86REG(srcreg) != REG_P2) |
| 2446 | | emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg |
| 2447 | | if (mask == U64(0xffffffffffffffff)) |
| 2448 | | emit_call(DRCTOP, mips3.drcdata->general.write_double); // call write_double |
| 2449 | | else |
| 2450 | | { |
| 2451 | | emit_mov_r64_imm(DRCTOP, REG_P3, mask); // mov p3,mask |
| 2452 | | emit_call(DRCTOP, mips3.drcdata->general.write_double_masked); // call write_double_masked |
| 2453 | | } |
| 2454 | | |
| 2455 | | /* handle exceptions */ |
| 2456 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 2457 | | } |
| 2458 | | |
| 2459 | | /* if we can do fastram, emit the right form */ |
| 2460 | | else |
| 2461 | | { |
| 2462 | | INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr; |
| 2463 | | int raxrel = ((INT32)fastdisp != fastdisp); |
| 2464 | | INT64 constval = CONSTVAL(srcreg); |
| 2465 | | |
| 2466 | | /* adjust values for endianness */ |
| 2467 | | if (mips3.core->bigendian) |
| 2468 | | { |
| 2469 | | if (ISCONST(srcreg)) |
| 2470 | | constval = (constval << 32) | (constval >> 32); |
| 2471 | | else |
| 2472 | | { |
| 2473 | | emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg |
| 2474 | | emit_ror_r64_imm(DRCTOP, REG_P2, 32); // ror p2,32 |
| 2475 | | srcreg = REG_P2; |
| 2476 | | } |
| 2477 | | mask = (mask << 32) | (mask >> 32); |
| 2478 | | } |
| 2479 | | |
| 2480 | | /* non-masked case */ |
| 2481 | | if (mask == U64(0xffffffffffffffff)) |
| 2482 | | { |
| 2483 | | /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */ |
| 2484 | | if (raxrel) |
| 2485 | | { |
| 2486 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2487 | | if (ISCONST(srcreg)) |
| 2488 | | emit_mov_m64_imm(DRCTOP, MBD(REG_RAX, 0), constval); // mov [rax],constval |
| 2489 | | else |
| 2490 | | emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg |
| 2491 | | } |
| 2492 | | |
| 2493 | | /* write drc-relative */ |
| 2494 | | else |
| 2495 | | { |
| 2496 | | if (ISCONST(srcreg)) |
| 2497 | | emit_mov_m64_imm(DRCTOP, MDRC(fastram), constval); // mov [fastram],constval |
| 2498 | | else |
| 2499 | | emit_mov_m64_r64(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg |
| 2500 | | } |
| 2501 | | } |
| 2502 | | |
| 2503 | | /* masked case */ |
| 2504 | | else |
| 2505 | | { |
| 2506 | | if (raxrel) |
| 2507 | | emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram |
| 2508 | | else |
| 2509 | | emit_lea_r64_m64(DRCTOP, REG_RAX, MDRC(fastram)); // lea rax,[fastram] |
| 2510 | | emit_mov_r64_imm(DRCTOP, REG_P4, ~mask); // mov p4,~mask |
| 2511 | | |
| 2512 | | /* always write rax-relative */ |
| 2513 | | if (ISCONST(srcreg)) |
| 2514 | | { |
| 2515 | | emit_and_r64_m64(DRCTOP, REG_P4, MBD(REG_RAX, 0)); // and p4,[rax] |
| 2516 | | emit_mov_r64_imm(DRCTOP, REG_P3, constval & mask); // mov p3,constval & mask |
| 2517 | | emit_or_r64_r64(DRCTOP, REG_P4, REG_P3); // or p4,p3 |
| 2518 | | emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_P4); // mov [rax],p4 |
| 2519 | | } |
| 2520 | | else |
| 2521 | | { |
| 2522 | | emit_mov_r64_m64(DRCTOP, REG_P3, MBD(REG_RAX, 0)); // mov p3,[rax] |
| 2523 | | if (X86REG(srcreg) != REG_P2) |
| 2524 | | emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg |
| 2525 | | emit_and_r64_r64(DRCTOP, REG_P3, REG_P4); // and p3,p4 |
| 2526 | | emit_not_r64(DRCTOP, REG_P4); // not p4 |
| 2527 | | emit_and_r64_r64(DRCTOP, REG_P2, REG_P4); // and p2,p4 |
| 2528 | | emit_or_r64_r64(DRCTOP, REG_P3, REG_P2); // or p3,p2 |
| 2529 | | emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_P3); // mov [rax],p3 |
| 2530 | | } |
| 2531 | | } |
| 2532 | | } |
| 2533 | | return (fastram != NULL); |
| 2534 | | } |
| 2535 | | |
| 2536 | | |
| 2537 | | |
| 2538 | | /*************************************************************************** |
| 2539 | | CORE RECOMPILATION |
| 2540 | | ***************************************************************************/ |
| 2541 | | |
| 2542 | | /*------------------------------------------------- |
| 2543 | | compile_instruction - master switch statement |
| 2544 | | for compiling a given opcode |
| 2545 | | -------------------------------------------------*/ |
| 2546 | | |
| 2547 | | static int compile_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 2548 | | { |
| 2549 | | UINT32 op = *desc->opptr.l; |
| 2550 | | UINT8 opswitch = op >> 26; |
| 2551 | | |
| 2552 | | switch (opswitch) |
| 2553 | | { |
| 2554 | | /* ----- sub-groups ----- */ |
| 2555 | | |
| 2556 | | case 0x00: /* SPECIAL */ |
| 2557 | | return compile_special(drc, compiler, desc); |
| 2558 | | |
| 2559 | | case 0x01: /* REGIMM */ |
| 2560 | | return compile_regimm(drc, compiler, desc); |
| 2561 | | |
| 2562 | | case 0x1c: /* IDT-specific */ |
| 2563 | | return compile_idt(drc, compiler, desc); |
| 2564 | | |
| 2565 | | |
| 2566 | | /* ----- jumps and branches ----- */ |
| 2567 | | |
| 2568 | | case 0x02: /* J */ |
| 2569 | | case 0x03: /* JAL */ |
| 2570 | | emit_delay_slot_and_branch(drc, compiler, desc, (opswitch == 0x02) ? 0 : 31); // <next instruction + redispatch> |
| 2571 | | return TRUE; |
| 2572 | | |
| 2573 | | case 0x04: /* BEQ */ |
| 2574 | | case 0x14: /* BEQL */ |
| 2575 | | case 0x05: /* BNE */ |
| 2576 | | case 0x15: /* BNEL */ |
| 2577 | | return compile_branchcc(drc, compiler, desc, (opswitch & 1) ? COND_NE : COND_E); |
| 2578 | | |
| 2579 | | case 0x06: /* BLEZ */ |
| 2580 | | case 0x16: /* BLEZL */ |
| 2581 | | case 0x07: /* BGTZ */ |
| 2582 | | case 0x17: /* BGTZL */ |
| 2583 | | return compile_branchcz(drc, compiler, desc, (opswitch & 1) ? COND_G : COND_LE, FALSE); |
| 2584 | | |
| 2585 | | |
| 2586 | | /* ----- immediate arithmetic ----- */ |
| 2587 | | |
| 2588 | | case 0x0f: /* LUI */ |
| 2589 | | if (RTREG != 0) |
| 2590 | | emit_set_constant_value(drc, compiler, desc, RTREG, SIMMVAL << 16); |
| 2591 | | return TRUE; |
| 2592 | | |
| 2593 | | case 0x08: /* ADDI */ |
| 2594 | | case 0x09: /* ADDIU */ |
| 2595 | | return compile_add(drc, compiler, desc, opswitch & 1, TRUE); |
| 2596 | | |
| 2597 | | case 0x18: /* DADDI */ |
| 2598 | | case 0x19: /* DADDIU */ |
| 2599 | | return compile_dadd(drc, compiler, desc, opswitch & 1, TRUE); |
| 2600 | | |
| 2601 | | case 0x0c: /* ANDI */ |
| 2602 | | case 0x0d: /* ORI */ |
| 2603 | | case 0x0e: /* XORI */ |
| 2604 | | return compile_logical(drc, compiler, desc, opswitch & 3, TRUE); |
| 2605 | | |
| 2606 | | case 0x0a: /* SLTI */ |
| 2607 | | case 0x0b: /* SLTIU */ |
| 2608 | | return compile_slt(drc, compiler, desc, opswitch & 1, TRUE); |
| 2609 | | |
| 2610 | | |
| 2611 | | /* ----- memory load operations ----- */ |
| 2612 | | |
| 2613 | | case 0x20: /* LB */ |
| 2614 | | case 0x21: /* LH */ |
| 2615 | | case 0x23: /* LW */ |
| 2616 | | case 0x24: /* LBU */ |
| 2617 | | case 0x25: /* LHU */ |
| 2618 | | case 0x27: /* LWU */ |
| 2619 | | return compile_load(drc, compiler, desc, (opswitch & 3) + 1, opswitch & 4); |
| 2620 | | |
| 2621 | | case 0x37: /* LD */ |
| 2622 | | return compile_load(drc, compiler, desc, 8, FALSE); |
| 2623 | | |
| 2624 | | case 0x31: /* LWC1 */ |
| 2625 | | return compile_load_cop(drc, compiler, desc, 4, FPR32(RTREG)); |
| 2626 | | |
| 2627 | | case 0x35: /* LDC1 */ |
| 2628 | | return compile_load_cop(drc, compiler, desc, 8, FPR64(RTREG)); |
| 2629 | | |
| 2630 | | case 0x32: /* LWC2 */ |
| 2631 | | case 0x36: /* LDC2 */ |
| 2632 | | return compile_load_cop(drc, compiler, desc, (opswitch & 4) ? 8 : 4, &mips3.core->cpr[2][RTREG]); |
| 2633 | | |
| 2634 | | case 0x1a: /* LDL */ |
| 2635 | | case 0x1b: /* LDR */ |
| 2636 | | return compile_load_double_partial(drc, compiler, desc, opswitch & 1); |
| 2637 | | |
| 2638 | | case 0x22: /* LWL */ |
| 2639 | | case 0x26: /* LWR */ |
| 2640 | | return compile_load_word_partial(drc, compiler, desc, opswitch & 4); |
| 2641 | | |
| 2642 | | |
| 2643 | | /* ----- memory store operations ----- */ |
| 2644 | | |
| 2645 | | case 0x28: /* SB */ |
| 2646 | | case 0x29: /* SH */ |
| 2647 | | case 0x2b: /* SW */ |
| 2648 | | return compile_store(drc, compiler, desc, (opswitch & 3) + 1); |
| 2649 | | |
| 2650 | | case 0x3f: /* SD */ |
| 2651 | | return compile_store(drc, compiler, desc, 8); |
| 2652 | | |
| 2653 | | case 0x39: /* SWC1 */ |
| 2654 | | return compile_store_cop(drc, compiler, desc, 4, FPR32(RTREG)); |
| 2655 | | |
| 2656 | | case 0x3d: /* SDC1 */ |
| 2657 | | return compile_store_cop(drc, compiler, desc, 8, FPR64(RTREG)); |
| 2658 | | |
| 2659 | | case 0x3a: /* SWC2 */ |
| 2660 | | return compile_store_cop(drc, compiler, desc, (opswitch & 4) ? 8 : 4, &mips3.core->cpr[2][RTREG]); |
| 2661 | | |
| 2662 | | case 0x2a: /* SWL */ |
| 2663 | | case 0x2e: /* SWR */ |
| 2664 | | return compile_store_word_partial(drc, compiler, desc, opswitch & 4); |
| 2665 | | |
| 2666 | | case 0x2c: /* SDL */ |
| 2667 | | case 0x2d: /* SDR */ |
| 2668 | | return compile_store_double_partial(drc, compiler, desc, opswitch & 1); |
| 2669 | | |
| 2670 | | |
| 2671 | | /* ----- effective no-ops ----- */ |
| 2672 | | |
| 2673 | | case 0x2f: /* CACHE */ |
| 2674 | | case 0x33: /* PREF */ |
| 2675 | | return TRUE; |
| 2676 | | |
| 2677 | | |
| 2678 | | /* ----- coprocessor instructions ----- */ |
| 2679 | | |
| 2680 | | case 0x10: /* COP0 */ |
| 2681 | | return compile_cop0(drc, compiler, desc); |
| 2682 | | |
| 2683 | | case 0x11: /* COP1 */ |
| 2684 | | return compile_cop1(drc, compiler, desc); |
| 2685 | | |
| 2686 | | case 0x13: /* COP1X - R5000 */ |
| 2687 | | return compile_cop1x(drc, compiler, desc); |
| 2688 | | |
| 2689 | | case 0x12: /* COP2 */ |
| 2690 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_invalidop_exception); |
| 2691 | | // jmp generate_invalidop_exception |
| 2692 | | return TRUE; |
| 2693 | | |
| 2694 | | |
| 2695 | | /* ----- unimplemented/illegal instructions ----- */ |
| 2696 | | |
| 2697 | | // case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break; |
| 2698 | | // case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break; |
| 2699 | | // case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break; |
| 2700 | | // case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break; |
| 2701 | | // case 0x3b: /* SWC3 */ invalid_instruction(op); break; |
| 2702 | | // default: /* ??? */ invalid_instruction(op); break; |
| 2703 | | } |
| 2704 | | |
| 2705 | | return FALSE; |
| 2706 | | } |
| 2707 | | |
| 2708 | | |
| 2709 | | /*------------------------------------------------- |
| 2710 | | compile_special - compile opcodes in the |
| 2711 | | 'SPECIAL' group |
| 2712 | | -------------------------------------------------*/ |
| 2713 | | |
| 2714 | | static int compile_special(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 2715 | | { |
| 2716 | | UINT32 op = *desc->opptr.l; |
| 2717 | | UINT8 opswitch = op & 63; |
| 2718 | | emit_link link1 = { 0 }; |
| 2719 | | |
| 2720 | | switch (opswitch) |
| 2721 | | { |
| 2722 | | /* ----- shift instructions ----- */ |
| 2723 | | |
| 2724 | | case 0x00: /* SLL - MIPS I */ |
| 2725 | | case 0x02: /* SRL - MIPS I */ |
| 2726 | | case 0x03: /* SRA - MIPS I */ |
| 2727 | | case 0x04: /* SLLV - MIPS I */ |
| 2728 | | case 0x06: /* SRLV - MIPS I */ |
| 2729 | | case 0x07: /* SRAV - MIPS I */ |
| 2730 | | return compile_shift(drc, compiler, desc, opswitch & 0x03, opswitch & 0x04); |
| 2731 | | |
| 2732 | | case 0x14: /* DSLLV - MIPS III */ |
| 2733 | | case 0x16: /* DSRLV - MIPS III */ |
| 2734 | | case 0x17: /* DSRAV - MIPS III */ |
| 2735 | | case 0x38: /* DSLL - MIPS III */ |
| 2736 | | case 0x3a: /* DSRL - MIPS III */ |
| 2737 | | case 0x3b: /* DSRA - MIPS III */ |
| 2738 | | case 0x3c: /* DSLL32 - MIPS III */ |
| 2739 | | case 0x3e: /* DSRL32 - MIPS III */ |
| 2740 | | case 0x3f: /* DSRA32 - MIPS III */ |
| 2741 | | return compile_dshift(drc, compiler, desc, opswitch & 0x03, ~opswitch & 0x20, opswitch & 0x04); |
| 2742 | | |
| 2743 | | |
| 2744 | | /* ----- basic arithmetic ----- */ |
| 2745 | | |
| 2746 | | case 0x20: /* ADD - MIPS I */ |
| 2747 | | case 0x21: /* ADDU - MIPS I */ |
| 2748 | | return compile_add(drc, compiler, desc, opswitch & 1, FALSE); |
| 2749 | | |
| 2750 | | case 0x2c: /* DADD - MIPS III */ |
| 2751 | | case 0x2d: /* DADDU - MIPS III */ |
| 2752 | | return compile_dadd(drc, compiler, desc, opswitch & 1, FALSE); |
| 2753 | | |
| 2754 | | case 0x22: /* SUB - MIPS I */ |
| 2755 | | case 0x23: /* SUBU - MIPS I */ |
| 2756 | | return compile_sub(drc, compiler, desc, opswitch & 1); |
| 2757 | | |
| 2758 | | case 0x2e: /* DSUB - MIPS III */ |
| 2759 | | case 0x2f: /* DSUBU - MIPS III */ |
| 2760 | | return compile_dsub(drc, compiler, desc, opswitch & 1); |
| 2761 | | |
| 2762 | | case 0x18: /* MULT - MIPS I */ |
| 2763 | | case 0x19: /* MULTU - MIPS I */ |
| 2764 | | return compile_mult(drc, compiler, desc, opswitch & 1); |
| 2765 | | |
| 2766 | | case 0x1c: /* DMULT - MIPS III */ |
| 2767 | | case 0x1d: /* DMULTU - MIPS III */ |
| 2768 | | return compile_dmult(drc, compiler, desc, opswitch & 1); |
| 2769 | | |
| 2770 | | case 0x1a: /* DIV - MIPS I */ |
| 2771 | | case 0x1b: /* DIVU - MIPS I */ |
| 2772 | | return compile_div(drc, compiler, desc, opswitch & 1); |
| 2773 | | |
| 2774 | | case 0x1e: /* DDIV - MIPS III */ |
| 2775 | | case 0x1f: /* DDIVU - MIPS III */ |
| 2776 | | return compile_ddiv(drc, compiler, desc, opswitch & 1); |
| 2777 | | |
| 2778 | | |
| 2779 | | /* ----- basic logical ops ----- */ |
| 2780 | | |
| 2781 | | case 0x24: /* AND - MIPS I */ |
| 2782 | | case 0x25: /* OR - MIPS I */ |
| 2783 | | case 0x26: /* XOR - MIPS I */ |
| 2784 | | case 0x27: /* NOR - MIPS I */ |
| 2785 | | return compile_logical(drc, compiler, desc, opswitch & 3, FALSE); |
| 2786 | | |
| 2787 | | |
| 2788 | | /* ----- basic comparisons ----- */ |
| 2789 | | |
| 2790 | | case 0x2a: /* SLT - MIPS I */ |
| 2791 | | case 0x2b: /* SLTU - MIPS I */ |
| 2792 | | return compile_slt(drc, compiler, desc, opswitch & 1, FALSE); |
| 2793 | | |
| 2794 | | |
| 2795 | | /* ----- conditional traps ----- */ |
| 2796 | | |
| 2797 | | case 0x30: /* TGE - MIPS II */ |
| 2798 | | case 0x31: /* TGEU - MIPS II */ |
| 2799 | | case 0x32: /* TLT - MIPS II */ |
| 2800 | | case 0x33: /* TLTU - MIPS II */ |
| 2801 | | case 0x34: /* TEQ - MIPS II */ |
| 2802 | | case 0x36: /* TNE - MIPS II */ |
| 2803 | | return compile_trapcc(drc, compiler, desc, opswitch & 7, FALSE); |
| 2804 | | |
| 2805 | | |
| 2806 | | /* ----- conditional moves ----- */ |
| 2807 | | |
| 2808 | | case 0x0a: /* MOVZ - MIPS IV */ |
| 2809 | | case 0x0b: /* MOVN - MIPS IV */ |
| 2810 | | return compile_movzn(drc, compiler, desc, opswitch & 1); |
| 2811 | | |
| 2812 | | case 0x01: /* MOVF - MIPS IV */ |
| 2813 | | if (RDREG != 0) |
| 2814 | | { |
| 2815 | | mipsreg_state rs, rd; |
| 2816 | | |
| 2817 | | /* allocate source registers */ |
| 2818 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 2819 | | rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY); |
| 2820 | | |
| 2821 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[x],0 |
| 2822 | | emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip |
| 2823 | | emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs> |
| 2824 | | } |
| 2825 | | resolve_link(DRCTOP, &link1); // skip: |
| 2826 | | return TRUE; |
| 2827 | | |
| 2828 | | |
| 2829 | | /* ----- jumps and branches ----- */ |
| 2830 | | |
| 2831 | | case 0x08: /* JR - MIPS I */ |
| 2832 | | case 0x09: /* JALR - MIPS I */ |
| 2833 | | { |
| 2834 | | mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 2835 | | if (ISCONST(rs)) |
| 2836 | | emit_mov_m32_imm(DRCTOP, MBD(REG_RSP, SPOFFS_NEXTPC), CONSTVAL(rs)); // mov [esp+nextpc],rs |
| 2837 | | else |
| 2838 | | emit_mov_m32_r32(DRCTOP, MBD(REG_RSP, SPOFFS_NEXTPC), X86REG(rs)); // mov [esp+nextpc],rs |
| 2839 | | emit_delay_slot_and_branch(drc, compiler, desc, (opswitch == 0x09) ? RDREG : 0); |
| 2840 | | // <next instruction + redispatch> |
| 2841 | | } |
| 2842 | | return TRUE; |
| 2843 | | |
| 2844 | | |
| 2845 | | /* ----- system calls ----- */ |
| 2846 | | |
| 2847 | | case 0x0c: /* SYSCALL - MIPS I */ |
| 2848 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_syscall_exception); |
| 2849 | | // jmp generate_syscall_exception |
| 2850 | | return TRUE; |
| 2851 | | |
| 2852 | | case 0x0d: /* BREAK - MIPS I */ |
| 2853 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_break_exception); |
| 2854 | | // jmp generate_break_exception |
| 2855 | | return TRUE; |
| 2856 | | |
| 2857 | | |
| 2858 | | /* ----- effective no-ops ----- */ |
| 2859 | | |
| 2860 | | case 0x0f: /* SYNC - MIPS II */ |
| 2861 | | return TRUE; |
| 2862 | | |
| 2863 | | |
| 2864 | | /* ----- hi/lo register access ----- */ |
| 2865 | | |
| 2866 | | case 0x10: /* MFHI - MIPS I */ |
| 2867 | | if (RDREG != 0) |
| 2868 | | { |
| 2869 | | mipsreg_state hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_SRC); |
| 2870 | | mipsreg_state rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY); |
| 2871 | | emit_load_register_value(drc, compiler, X86REG(rd), hi); // mov <rd>,<hi> |
| 2872 | | } |
| 2873 | | return TRUE; |
| 2874 | | |
| 2875 | | case 0x11: /* MTHI - MIPS I */ |
| 2876 | | if (RSREG != 0) |
| 2877 | | { |
| 2878 | | mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 2879 | | mipsreg_state hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY); |
| 2880 | | emit_load_register_value(drc, compiler, X86REG(hi), rs); // mov hi,<rs> |
| 2881 | | } |
| 2882 | | return TRUE; |
| 2883 | | |
| 2884 | | case 0x12: /* MFLO - MIPS I */ |
| 2885 | | if (RDREG != 0) |
| 2886 | | { |
| 2887 | | mipsreg_state lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_SRC); |
| 2888 | | mipsreg_state rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY); |
| 2889 | | emit_load_register_value(drc, compiler, X86REG(rd), lo); // mov <rd>,<lo> |
| 2890 | | } |
| 2891 | | return TRUE; |
| 2892 | | |
| 2893 | | case 0x13: /* MTLO - MIPS I */ |
| 2894 | | if (RSREG != 0) |
| 2895 | | { |
| 2896 | | mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 2897 | | mipsreg_state lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY); |
| 2898 | | emit_load_register_value(drc, compiler, X86REG(lo), rs); // mov lo,<rs> |
| 2899 | | } |
| 2900 | | return TRUE; |
| 2901 | | } |
| 2902 | | return FALSE; |
| 2903 | | } |
| 2904 | | |
| 2905 | | |
| 2906 | | /*------------------------------------------------- |
| 2907 | | compile_regimm - compile opcodes in the |
| 2908 | | 'REGIMM' group |
| 2909 | | -------------------------------------------------*/ |
| 2910 | | |
| 2911 | | static int compile_regimm(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 2912 | | { |
| 2913 | | UINT32 op = *desc->opptr.l; |
| 2914 | | UINT8 opswitch = RTREG; |
| 2915 | | |
| 2916 | | switch (opswitch) |
| 2917 | | { |
| 2918 | | case 0x00: /* BLTZ */ |
| 2919 | | case 0x01: /* BGEZ */ |
| 2920 | | case 0x02: /* BLTZL */ |
| 2921 | | case 0x03: /* BGEZL */ |
| 2922 | | case 0x10: /* BLTZAL */ |
| 2923 | | case 0x11: /* BGEZAL */ |
| 2924 | | case 0x12: /* BLTZALL */ |
| 2925 | | case 0x13: /* BGEZALL */ |
| 2926 | | return compile_branchcz(drc, compiler, desc, (opswitch & 1) ? COND_GE : COND_L, opswitch & 0x10); |
| 2927 | | |
| 2928 | | case 0x08: /* TGEI */ |
| 2929 | | case 0x09: /* TGEIU */ |
| 2930 | | case 0x0a: /* TLTI */ |
| 2931 | | case 0x0b: /* TLTIU */ |
| 2932 | | case 0x0c: /* TEQI */ |
| 2933 | | case 0x0e: /* TNEI */ |
| 2934 | | return compile_trapcc(drc, compiler, desc, opswitch & 7, TRUE); |
| 2935 | | } |
| 2936 | | return FALSE; |
| 2937 | | } |
| 2938 | | |
| 2939 | | |
| 2940 | | /*------------------------------------------------- |
| 2941 | | compile_idt - compile opcodes in the IDT- |
| 2942 | | specific group |
| 2943 | | -------------------------------------------------*/ |
| 2944 | | |
| 2945 | | static int compile_idt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 2946 | | { |
| 2947 | | fatalerror("Unimplemented IDT instructions"); |
| 2948 | | #if 0 |
| 2949 | | UINT32 op = *desc->opptr.l; |
| 2950 | | UINT8 opswitch = op & 0x1f; |
| 2951 | | |
| 2952 | | switch (opswitch) |
| 2953 | | { |
| 2954 | | case 0: /* MAD */ |
| 2955 | | if (RSREG != 0 && RTREG != 0) |
| 2956 | | { |
| 2957 | | emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg] |
| 2958 | | emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg] |
| 2959 | | emit_imul_r32(DRCTOP, REG_EDX); // imul edx |
| 2960 | | emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo] |
| 2961 | | emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi] |
| 2962 | | emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx |
| 2963 | | emit_cdq(DRCTOP); // cdq |
| 2964 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EAX); // mov [lo],edx:eax |
| 2965 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx |
| 2966 | | emit_cdq(DRCTOP); // cdq |
| 2967 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EAX); // mov [hi],edx:eax |
| 2968 | | } |
| 2969 | | return compile_SUCCESSFUL_CP(3,4); |
| 2970 | | |
| 2971 | | case 1: /* MADU */ |
| 2972 | | if (RSREG != 0 && RTREG != 0) |
| 2973 | | { |
| 2974 | | emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg] |
| 2975 | | emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg] |
| 2976 | | emit_mul_r32(DRCTOP, REG_EDX); // mul edx |
| 2977 | | emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo] |
| 2978 | | emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi] |
| 2979 | | emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx |
| 2980 | | emit_cdq(DRCTOP); // cdq |
| 2981 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 2982 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx |
| 2983 | | emit_cdq(DRCTOP); // cdq |
| 2984 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 2985 | | } |
| 2986 | | return compile_SUCCESSFUL_CP(3,4); |
| 2987 | | |
| 2988 | | case 2: /* MUL */ |
| 2989 | | if (RDREG != 0) |
| 2990 | | { |
| 2991 | | if (RSREG != 0 && RTREG != 0) |
| 2992 | | { |
| 2993 | | emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg] |
| 2994 | | emit_imul_r32_m32(REG_EAX, REGADDR(RTREG)); // imul eax,[rtreg] |
| 2995 | | emit_cdq(DRCTOP); // cdq |
| 2996 | | emit_mov_m64_r64(REG_ESI, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rd],edx:eax |
| 2997 | | } |
| 2998 | | else |
| 2999 | | emit_zero_m64(REG_ESI, REGADDR(RDREG)); |
| 3000 | | } |
| 3001 | | return compile_SUCCESSFUL_CP(3,4); |
| 3002 | | } |
| 3003 | | #endif |
| 3004 | | return FALSE; |
| 3005 | | } |
| 3006 | | |
| 3007 | | |
| 3008 | | |
| 3009 | | /*************************************************************************** |
| 3010 | | COP0 RECOMPILATION |
| 3011 | | ***************************************************************************/ |
| 3012 | | |
| 3013 | | /*------------------------------------------------- |
| 3014 | | compile_set_cop0_reg - generate code to |
| 3015 | | handle special COP0 registers |
| 3016 | | -------------------------------------------------*/ |
| 3017 | | |
| 3018 | | static int compile_set_cop0_reg(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 reg) |
| 3019 | | { |
| 3020 | | emit_link link1; |
| 3021 | | |
| 3022 | | switch (reg) |
| 3023 | | { |
| 3024 | | case COP0_Cause: |
| 3025 | | emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Cause)); // mov edx,[Cause] |
| 3026 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00 |
| 3027 | | emit_and_r32_imm(DRCTOP, REG_EDX, 0xfc00); // and edx,0xfc00 |
| 3028 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); // or eax,edx |
| 3029 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [Cause],eax |
| 3030 | | emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[SR] |
| 3031 | | emit_test_r32_imm(DRCTOP, REG_EAX, 0x300); // test eax,0x300 |
| 3032 | | oob_request_callback(drc, COND_NZ, oob_interrupt_cleanup, compiler, desc, mips3.drcdata->generate_interrupt_exception); |
| 3033 | | // jnz generate_interrupt_exception |
| 3034 | | return TRUE; |
| 3035 | | |
| 3036 | | case COP0_Status: |
| 3037 | | emit_flush_cycles_before_instruction(drc, compiler, desc, 1); |
| 3038 | | emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Status)); // mov edx,[Status] |
| 3039 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [Status],eax |
| 3040 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EAX); // xor edx,eax |
| 3041 | | emit_test_r32_imm(DRCTOP, REG_EDX, SR_IMEX5); // test edx,0x8000 |
| 3042 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 3043 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3044 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting |
| 3045 | | resolve_link(DRCTOP, &link1); // skip: |
| 3046 | | append_check_interrupts(drc, compiler, desc); // <check interrupts> |
| 3047 | | return TRUE; |
| 3048 | | |
| 3049 | | case COP0_Count: |
| 3050 | | emit_flush_cycles_before_instruction(drc, compiler, desc, 1); |
| 3051 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [Count],eax |
| 3052 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles)); // call activecpu_gettotalcycles |
| 3053 | | emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Count)); // mov edx,[Count] |
| 3054 | | emit_sub_r64_r64(DRCTOP, REG_RAX, REG_RDX); // sub rax,rdx |
| 3055 | | emit_sub_r64_r64(DRCTOP, REG_RAX, REG_RDX); // sub rax,rdx |
| 3056 | | emit_mov_m64_r64(DRCTOP, MDRC(&mips3.core->count_zero_time), REG_RAX); // mov [count_zero_time],rax |
| 3057 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3058 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting |
| 3059 | | return TRUE; |
| 3060 | | |
| 3061 | | case COP0_Compare: |
| 3062 | | emit_flush_cycles_before_instruction(drc, compiler, desc, 1); |
| 3063 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [Compare],eax |
| 3064 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [Cause],~0x8000 |
| 3065 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3066 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting |
| 3067 | | return TRUE; |
| 3068 | | |
| 3069 | | case COP0_PRId: |
| 3070 | | return TRUE; |
| 3071 | | |
| 3072 | | case COP0_Config: |
| 3073 | | emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Config)); // mov edx,[Config] |
| 3074 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007 |
| 3075 | | emit_and_r32_imm(DRCTOP, REG_EDX, ~0x0007); // and edx,~0x0007 |
| 3076 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); // or eax,edx |
| 3077 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [Config],eax |
| 3078 | | return TRUE; |
| 3079 | | |
| 3080 | | default: |
| 3081 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov cpr0[reg],eax |
| 3082 | | return TRUE; |
| 3083 | | } |
| 3084 | | } |
| 3085 | | |
| 3086 | | |
| 3087 | | /*------------------------------------------------- |
| 3088 | | compile_get_cop0_reg - generate code to |
| 3089 | | read special COP0 registers |
| 3090 | | -------------------------------------------------*/ |
| 3091 | | |
| 3092 | | static int compile_get_cop0_reg(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 reg) |
| 3093 | | { |
| 3094 | | emit_link link1, link2; |
| 3095 | | |
| 3096 | | switch (reg) |
| 3097 | | { |
| 3098 | | case COP0_Count: |
| 3099 | | compiler->cycles += MIPS3_COUNT_READ_CYCLES; |
| 3100 | | emit_flush_cycles_before_instruction(drc, compiler, desc, MIPS3_COUNT_READ_CYCLES); |
| 3101 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles)); // call activecpu_gettotalcycles |
| 3102 | | emit_sub_r64_m64(DRCTOP, REG_RAX, MDRC(&mips3.core->count_zero_time)); // sub rax,[count_zero_time] |
| 3103 | | emit_shr_r64_imm(DRCTOP, REG_RAX, 1); // shr rax,1 |
| 3104 | | emit_movsxd_r64_r32(DRCTOP, REG_RAX, REG_EAX); // movsxd rax,eax |
| 3105 | | return TRUE; |
| 3106 | | |
| 3107 | | case COP0_Cause: |
| 3108 | | compiler->cycles += MIPS3_CAUSE_READ_CYCLES; |
| 3109 | | emit_movsxd_r64_m32(DRCTOP, REG_RAX, CPR0ADDR(COP0_Cause)); // movsxd rax,[Cause] |
| 3110 | | return TRUE; |
| 3111 | | |
| 3112 | | case COP0_Random: |
| 3113 | | emit_flush_cycles_before_instruction(drc, compiler, desc, 1); |
| 3114 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles)); // call activecpu_gettotalcycles |
| 3115 | | emit_mov_r32_m32(DRCTOP, REG_ECX, CPR0ADDR(COP0_Wired)); // mov ecx,[Wired] |
| 3116 | | emit_mov_r32_imm(DRCTOP, REG_R8D, 48); // mov r8d,48 |
| 3117 | | emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f); // and ecx,0x3f |
| 3118 | | emit_sub_r64_m64(DRCTOP, REG_RAX, MDRC(&mips3.core->count_zero_time)); // sub rax,[count_zero_time] |
| 3119 | | emit_sub_r32_r32(DRCTOP, REG_R8D, REG_ECX); // sub r8d,ecx |
| 3120 | | emit_jcc_short_link(DRCTOP, COND_BE, &link1); // jbe link1 |
| 3121 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 3122 | | emit_div_r64(DRCTOP, REG_R8); // div r8 |
| 3123 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx |
| 3124 | | emit_add_r32_r32(DRCTOP, REG_EAX, REG_ECX); // add eax,ecx |
| 3125 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0x3f); // and eax,0x3f |
| 3126 | | emit_jmp_short_link(DRCTOP, &link2); // jmp link2 |
| 3127 | | resolve_link(DRCTOP, &link1); // link1: |
| 3128 | | emit_mov_r32_imm(DRCTOP, REG_EAX, 47); // mov eax,47 |
| 3129 | | resolve_link(DRCTOP, &link2); // link2: |
| 3130 | | return TRUE; |
| 3131 | | |
| 3132 | | default: |
| 3133 | | emit_movsxd_r64_m32(DRCTOP, REG_RAX, CPR0ADDR(reg)); // movsxd rax,cpr0[reg] |
| 3134 | | return TRUE; |
| 3135 | | } |
| 3136 | | } |
| 3137 | | |
| 3138 | | |
| 3139 | | /*------------------------------------------------- |
| 3140 | | compile_cop0 - compile COP0 opcodes |
| 3141 | | -------------------------------------------------*/ |
| 3142 | | |
| 3143 | | static int compile_cop0(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 3144 | | { |
| 3145 | | UINT32 op = *desc->opptr.l; |
| 3146 | | UINT8 opswitch = RSREG; |
| 3147 | | |
| 3148 | | /* generate an exception if COP0 is disabled or we are not in kernel mode */ |
| 3149 | | if (mips3.drcoptions & MIPS3DRC_STRICT_COP0) |
| 3150 | | { |
| 3151 | | emit_link checklink; |
| 3152 | | |
| 3153 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [SR],SR_KSU_MASK |
| 3154 | | emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay |
| 3155 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [SR],SR_COP0 |
| 3156 | | oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception); |
| 3157 | | // jz generate_cop_exception |
| 3158 | | resolve_link(DRCTOP, &checklink); // okay: |
| 3159 | | } |
| 3160 | | |
| 3161 | | switch (opswitch) |
| 3162 | | { |
| 3163 | | case 0x00: /* MFCz */ |
| 3164 | | case 0x01: /* DMFCz */ |
| 3165 | | if (RTREG != 0) |
| 3166 | | { |
| 3167 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY); |
| 3168 | | compile_get_cop0_reg(drc, compiler, desc, RDREG); // mov eax,cpr0[rd]) |
| 3169 | | if (!(opswitch & 1)) |
| 3170 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rt), REG_EAX); // movsxd <rt>,eax |
| 3171 | | else |
| 3172 | | emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov <rt>,rax |
| 3173 | | } |
| 3174 | | return TRUE; |
| 3175 | | |
| 3176 | | case 0x02: /* CFCz */ |
| 3177 | | if (RTREG != 0) |
| 3178 | | { |
| 3179 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY); |
| 3180 | | emit_movsxd_r64_m32(DRCTOP, X86REG(rt), CCR0ADDR(RDREG)); // movsxd <rt>,ccr1[rd] |
| 3181 | | } |
| 3182 | | return TRUE; |
| 3183 | | |
| 3184 | | case 0x04: /* MTCz */ |
| 3185 | | case 0x05: /* DMTCz */ |
| 3186 | | { |
| 3187 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 3188 | | emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt> |
| 3189 | | compile_set_cop0_reg(drc, compiler, desc, RDREG); // mov cpr0[rd],rax |
| 3190 | | } |
| 3191 | | return TRUE; |
| 3192 | | |
| 3193 | | case 0x06: /* CTCz */ |
| 3194 | | { |
| 3195 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 3196 | | emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt> |
| 3197 | | emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov ccr1[rd],eax |
| 3198 | | } |
| 3199 | | return TRUE; |
| 3200 | | |
| 3201 | | case 0x10: |
| 3202 | | case 0x11: |
| 3203 | | case 0x12: |
| 3204 | | case 0x13: |
| 3205 | | case 0x14: |
| 3206 | | case 0x15: |
| 3207 | | case 0x16: |
| 3208 | | case 0x17: |
| 3209 | | case 0x18: |
| 3210 | | case 0x19: |
| 3211 | | case 0x1a: |
| 3212 | | case 0x1b: |
| 3213 | | case 0x1c: |
| 3214 | | case 0x1d: |
| 3215 | | case 0x1e: |
| 3216 | | case 0x1f: /* COP */ |
| 3217 | | switch (op & 0x01ffffff) |
| 3218 | | { |
| 3219 | | case 0x01: /* TLBR */ |
| 3220 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3221 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbr)); // call mips3com_tlbr |
| 3222 | | return TRUE; |
| 3223 | | |
| 3224 | | case 0x02: /* TLBWI */ |
| 3225 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3226 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbwi)); // call mips3com_tlbwi |
| 3227 | | return TRUE; |
| 3228 | | |
| 3229 | | case 0x06: /* TLBWR */ |
| 3230 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3231 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbwr)); // call mips3com_tlbwr |
| 3232 | | return TRUE; |
| 3233 | | |
| 3234 | | case 0x08: /* TLBP */ |
| 3235 | | emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core] |
| 3236 | | emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbp)); // call mips3com_tlbp |
| 3237 | | return TRUE; |
| 3238 | | |
| 3239 | | case 0x18: /* ERET */ |
| 3240 | | emit_mov_r32_m32(DRCTOP, REG_P1, CPR0ADDR(COP0_EPC)); // mov p1,[EPC] |
| 3241 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [SR],~SR_EXL |
| 3242 | | compiler_register_flush_all(drc, compiler); // <flush registers> |
| 3243 | | drc_append_dispatcher(drc); // <dispatch> |
| 3244 | | return TRUE; |
| 3245 | | |
| 3246 | | case 0x20: /* WAIT */ |
| 3247 | | return TRUE; |
| 3248 | | } |
| 3249 | | break; |
| 3250 | | } |
| 3251 | | |
| 3252 | | return FALSE; |
| 3253 | | } |
| 3254 | | |
| 3255 | | |
| 3256 | | |
| 3257 | | /*************************************************************************** |
| 3258 | | COP1 RECOMPILATION |
| 3259 | | ***************************************************************************/ |
| 3260 | | |
| 3261 | | /*------------------------------------------------- |
| 3262 | | compile_cop1 - compile COP1 opcodes |
| 3263 | | -------------------------------------------------*/ |
| 3264 | | |
| 3265 | | static int compile_cop1(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 3266 | | { |
| 3267 | | UINT32 op = *desc->opptr.l; |
| 3268 | | emit_link link1; |
| 3269 | | |
| 3270 | | /* generate an exception if COP1 is disabled */ |
| 3271 | | if (mips3.drcoptions & MIPS3DRC_STRICT_COP1) |
| 3272 | | { |
| 3273 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [mips3.core->cpr[0][COP0_Status]],SR_COP1 |
| 3274 | | oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception); |
| 3275 | | // jz generate_cop_exception |
| 3276 | | } |
| 3277 | | |
| 3278 | | switch (RSREG) |
| 3279 | | { |
| 3280 | | case 0x00: /* MFCz */ |
| 3281 | | if (RTREG != 0) |
| 3282 | | { |
| 3283 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY); |
| 3284 | | emit_movsxd_r64_m32(DRCTOP, X86REG(rt), FPR32ADDR(RDREG)); // movsxd <rt>,cpr[rd] |
| 3285 | | } |
| 3286 | | return TRUE; |
| 3287 | | |
| 3288 | | case 0x01: /* DMFCz */ |
| 3289 | | if (RTREG != 0) |
| 3290 | | { |
| 3291 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY); |
| 3292 | | emit_mov_r64_m64(DRCTOP, X86REG(rt), FPR64ADDR(RDREG)); // mov <rt>,cpr[rd] |
| 3293 | | } |
| 3294 | | return TRUE; |
| 3295 | | |
| 3296 | | case 0x02: /* CFCz */ |
| 3297 | | if (RTREG != 0) |
| 3298 | | { |
| 3299 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY); |
| 3300 | | if (RDREG != 31) |
| 3301 | | emit_movsxd_r64_m32(DRCTOP, X86REG(rt), CCR1ADDR(RDREG)); // movsxd <rt>,ccr1[rd] |
| 3302 | | else |
| 3303 | | { |
| 3304 | | emit_call(DRCTOP, mips3.drcdata->recover_ccr31); // call recover_ccr31 |
| 3305 | | emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov [X86REG(rt)],rax |
| 3306 | | } |
| 3307 | | } |
| 3308 | | return TRUE; |
| 3309 | | |
| 3310 | | case 0x04: /* MTCz */ |
| 3311 | | { |
| 3312 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 3313 | | UINT8 tempreg = ISCONST(rt) ? REG_EAX : X86REG(rt); |
| 3314 | | emit_load_register_value(drc, compiler, tempreg, rt); // mov <tempreg>,<rt> |
| 3315 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), tempreg); // mov cpr1[rd],<tempreg> |
| 3316 | | } |
| 3317 | | return TRUE; |
| 3318 | | |
| 3319 | | case 0x05: /* DMTCz */ |
| 3320 | | { |
| 3321 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 3322 | | UINT8 tempreg = ISCONST(rt) ? REG_EAX : X86REG(rt); |
| 3323 | | emit_load_register_value(drc, compiler, tempreg, rt); // mov <tempreg>,<rt> |
| 3324 | | emit_mov_m64_r64(DRCTOP, FPR64ADDR(RDREG), tempreg); // mov cpr1[rd],<tempreg> |
| 3325 | | } |
| 3326 | | return TRUE; |
| 3327 | | |
| 3328 | | case 0x06: /* CTCz */ |
| 3329 | | { |
| 3330 | | mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 3331 | | emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt> |
| 3332 | | if (RDREG != 31) |
| 3333 | | emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov ccr1[rd],eax |
| 3334 | | else |
| 3335 | | emit_call(DRCTOP, mips3.drcdata->explode_ccr31); // call explode_ccr31 |
| 3336 | | } |
| 3337 | | return TRUE; |
| 3338 | | |
| 3339 | | case 0x08: /* BC */ |
| 3340 | | switch ((op >> 16) & 3) |
| 3341 | | { |
| 3342 | | case 0x00: /* BCzF */ |
| 3343 | | case 0x02: /* BCzFL */ |
| 3344 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0 |
| 3345 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1 |
| 3346 | | emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch> |
| 3347 | | resolve_link(DRCTOP, &link1); // skip: |
| 3348 | | return TRUE; |
| 3349 | | |
| 3350 | | case 0x01: /* BCzT */ |
| 3351 | | case 0x03: /* BCzTL */ |
| 3352 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0 |
| 3353 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1 |
| 3354 | | emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch> |
| 3355 | | resolve_link(DRCTOP, &link1); // skip: |
| 3356 | | return TRUE; |
| 3357 | | } |
| 3358 | | break; |
| 3359 | | |
| 3360 | | default: |
| 3361 | | switch (op & 0x3f) |
| 3362 | | { |
| 3363 | | case 0x00: |
| 3364 | | if (IS_SINGLE(op)) /* ADD.S */ |
| 3365 | | { |
| 3366 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3367 | | emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg] |
| 3368 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3369 | | } |
| 3370 | | else /* ADD.D */ |
| 3371 | | { |
| 3372 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3373 | | emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg] |
| 3374 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3375 | | } |
| 3376 | | return TRUE; |
| 3377 | | |
| 3378 | | case 0x01: |
| 3379 | | if (IS_SINGLE(op)) /* SUB.S */ |
| 3380 | | { |
| 3381 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3382 | | emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg] |
| 3383 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3384 | | } |
| 3385 | | else /* SUB.D */ |
| 3386 | | { |
| 3387 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3388 | | emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg] |
| 3389 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3390 | | } |
| 3391 | | return TRUE; |
| 3392 | | |
| 3393 | | case 0x02: |
| 3394 | | if (IS_SINGLE(op)) /* MUL.S */ |
| 3395 | | { |
| 3396 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3397 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 3398 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3399 | | } |
| 3400 | | else /* MUL.D */ |
| 3401 | | { |
| 3402 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3403 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 3404 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3405 | | } |
| 3406 | | return TRUE; |
| 3407 | | |
| 3408 | | case 0x03: |
| 3409 | | if (IS_SINGLE(op)) /* DIV.S */ |
| 3410 | | { |
| 3411 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3412 | | emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg] |
| 3413 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3414 | | } |
| 3415 | | else /* DIV.D */ |
| 3416 | | { |
| 3417 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3418 | | emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg] |
| 3419 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3420 | | } |
| 3421 | | return TRUE; |
| 3422 | | |
| 3423 | | case 0x04: |
| 3424 | | if (IS_SINGLE(op)) /* SQRT.S */ |
| 3425 | | { |
| 3426 | | emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg] |
| 3427 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3428 | | } |
| 3429 | | else /* SQRT.D */ |
| 3430 | | { |
| 3431 | | emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg] |
| 3432 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3433 | | } |
| 3434 | | return TRUE; |
| 3435 | | |
| 3436 | | case 0x05: |
| 3437 | | if (IS_SINGLE(op)) /* ABS.S */ |
| 3438 | | { |
| 3439 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3440 | | emit_andps_r128_m128(DRCTOP, REG_XMM0, MDRC(mips3.drcdata->abs32mask)); |
| 3441 | | // andps xmm0,[abs32mask] |
| 3442 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3443 | | } |
| 3444 | | else /* ABS.D */ |
| 3445 | | { |
| 3446 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3447 | | emit_andps_r128_m128(DRCTOP, REG_XMM0, MDRC(mips3.drcdata->abs64mask)); |
| 3448 | | // andpd xmm0,[abs64mask] |
| 3449 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3450 | | } |
| 3451 | | return TRUE; |
| 3452 | | |
| 3453 | | case 0x06: |
| 3454 | | if (IS_SINGLE(op)) /* MOV.S */ |
| 3455 | | { |
| 3456 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3457 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3458 | | } |
| 3459 | | else /* MOV.D */ |
| 3460 | | { |
| 3461 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3462 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3463 | | } |
| 3464 | | return TRUE; |
| 3465 | | |
| 3466 | | case 0x07: |
| 3467 | | if (IS_SINGLE(op)) /* NEG.S */ |
| 3468 | | { |
| 3469 | | emit_xorps_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // xorps xmm0,xmm0 |
| 3470 | | emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // subss xmm0,[fsreg] |
| 3471 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3472 | | } |
| 3473 | | else /* NEG.D */ |
| 3474 | | { |
| 3475 | | emit_xorps_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // xorps xmm0,xmm0 |
| 3476 | | emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // subsd xmm0,[fsreg] |
| 3477 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3478 | | } |
| 3479 | | return TRUE; |
| 3480 | | |
| 3481 | | case 0x08: |
| 3482 | | /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */ |
| 3483 | | drc_append_set_temp_sse_rounding(drc, FPRND_NEAR); // ldmxcsr [round] |
| 3484 | | if (IS_SINGLE(op)) /* ROUND.L.S */ |
| 3485 | | emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg] |
| 3486 | | else /* ROUND.L.D */ |
| 3487 | | emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg] |
| 3488 | | emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax |
| 3489 | | drc_append_restore_sse_rounding(drc); // ldmxcsr [mode] |
| 3490 | | return TRUE; |
| 3491 | | |
| 3492 | | case 0x09: |
| 3493 | | if (IS_SINGLE(op)) /* TRUNC.L.S */ |
| 3494 | | emit_cvttss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvttss2si rax,[fsreg] |
| 3495 | | else /* TRUNC.L.D */ |
| 3496 | | emit_cvttsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvttsd2si rax,[fsreg] |
| 3497 | | emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax |
| 3498 | | return TRUE; |
| 3499 | | |
| 3500 | | case 0x0a: |
| 3501 | | /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */ |
| 3502 | | drc_append_set_temp_sse_rounding(drc, FPRND_UP); // ldmxcsr [round] |
| 3503 | | if (IS_SINGLE(op)) /* CEIL.L.S */ |
| 3504 | | emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg] |
| 3505 | | else /* CEIL.L.D */ |
| 3506 | | emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg] |
| 3507 | | emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax |
| 3508 | | drc_append_restore_sse_rounding(drc); // ldmxcsr [mode] |
| 3509 | | return TRUE; |
| 3510 | | |
| 3511 | | case 0x0b: |
| 3512 | | /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */ |
| 3513 | | drc_append_set_temp_sse_rounding(drc, FPRND_DOWN); // ldmxcsr [round] |
| 3514 | | if (IS_SINGLE(op)) /* FLOOR.L.S */ |
| 3515 | | emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg] |
| 3516 | | else /* FLOOR.L.D */ |
| 3517 | | emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg] |
| 3518 | | emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax |
| 3519 | | drc_append_restore_sse_rounding(drc); // ldmxcsr [mode] |
| 3520 | | return TRUE; |
| 3521 | | |
| 3522 | | case 0x0c: |
| 3523 | | /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */ |
| 3524 | | drc_append_set_temp_sse_rounding(drc, FPRND_NEAR); // ldmxcsr [round] |
| 3525 | | if (IS_SINGLE(op)) /* ROUND.W.S */ |
| 3526 | | emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg] |
| 3527 | | else /* ROUND.W.D */ |
| 3528 | | emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg] |
| 3529 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 3530 | | drc_append_restore_sse_rounding(drc); // ldmxcsr [mode] |
| 3531 | | return TRUE; |
| 3532 | | |
| 3533 | | case 0x0d: |
| 3534 | | if (IS_SINGLE(op)) /* TRUNC.W.S */ |
| 3535 | | emit_cvttss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvttss2si eax,[fsreg] |
| 3536 | | else /* TRUNC.W.D */ |
| 3537 | | emit_cvttsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvttsd2si eax,[fsreg] |
| 3538 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 3539 | | return TRUE; |
| 3540 | | |
| 3541 | | case 0x0e: |
| 3542 | | /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */ |
| 3543 | | drc_append_set_temp_sse_rounding(drc, FPRND_UP); // ldmxcsr [round] |
| 3544 | | if (IS_SINGLE(op)) /* CEIL.W.S */ |
| 3545 | | emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg] |
| 3546 | | else /* CEIL.W.D */ |
| 3547 | | emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg] |
| 3548 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 3549 | | drc_append_restore_sse_rounding(drc); // ldmxcsr [mode] |
| 3550 | | return TRUE; |
| 3551 | | |
| 3552 | | case 0x0f: |
| 3553 | | /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */ |
| 3554 | | drc_append_set_temp_sse_rounding(drc, FPRND_DOWN); // ldmxcsr [round] |
| 3555 | | if (IS_SINGLE(op)) /* FLOOR.W.S */ |
| 3556 | | emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg] |
| 3557 | | else /* FLOOR.W.D */ |
| 3558 | | emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg] |
| 3559 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 3560 | | drc_append_restore_sse_rounding(drc); // ldmxcsr [mode] |
| 3561 | | return TRUE; |
| 3562 | | |
| 3563 | | case 0x11: /* R5000 */ |
| 3564 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0 |
| 3565 | | emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); |
| 3566 | | // jz/nz skip |
| 3567 | | if (IS_SINGLE(op)) /* MOVT/F.S */ |
| 3568 | | { |
| 3569 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3570 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3571 | | } |
| 3572 | | else /* MOVT/F.D */ |
| 3573 | | { |
| 3574 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3575 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3576 | | } |
| 3577 | | resolve_link(DRCTOP, &link1); // skip: |
| 3578 | | return TRUE; |
| 3579 | | |
| 3580 | | case 0x12: /* R5000 */ |
| 3581 | | emit_cmp_m64_imm(DRCTOP, REGADDR(RTREG), 0); // cmp [X86REG(rt)],0 |
| 3582 | | emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 3583 | | if (IS_SINGLE(op)) /* MOVZ.S */ |
| 3584 | | { |
| 3585 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3586 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3587 | | } |
| 3588 | | else /* MOVZ.D */ |
| 3589 | | { |
| 3590 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3591 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3592 | | } |
| 3593 | | resolve_link(DRCTOP, &link1); // skip: |
| 3594 | | return TRUE; |
| 3595 | | |
| 3596 | | case 0x13: /* R5000 */ |
| 3597 | | emit_cmp_m64_imm(DRCTOP, REGADDR(RTREG), 0); // cmp [X86REG(rt)],0 |
| 3598 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 3599 | | if (IS_SINGLE(op)) /* MOVN.S */ |
| 3600 | | { |
| 3601 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3602 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3603 | | } |
| 3604 | | else /* MOVN.D */ |
| 3605 | | { |
| 3606 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3607 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3608 | | } |
| 3609 | | resolve_link(DRCTOP, &link1); // skip: |
| 3610 | | return TRUE; |
| 3611 | | |
| 3612 | | case 0x15: /* R5000 */ |
| 3613 | | if (IS_SINGLE(op)) /* RECIP.S */ |
| 3614 | | { |
| 3615 | | emit_rcpss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // rcpss xmm0,[fsreg] |
| 3616 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3617 | | } |
| 3618 | | else /* RECIP.D */ |
| 3619 | | { |
| 3620 | | emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsd2ss xmm0,[fsreg] |
| 3621 | | emit_rcpss_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // rcpss xmm0,xmm0 |
| 3622 | | emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // cvtss2sd xmm0,xmm0 |
| 3623 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3624 | | } |
| 3625 | | return TRUE; |
| 3626 | | |
| 3627 | | case 0x16: /* R5000 */ |
| 3628 | | if (IS_SINGLE(op)) /* RSQRT.S */ |
| 3629 | | { |
| 3630 | | emit_rsqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // rsqrtss xmm0,[fsreg] |
| 3631 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3632 | | } |
| 3633 | | else /* RSQRT.D */ |
| 3634 | | { |
| 3635 | | emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtss2sd xmm0,[fsreg] |
| 3636 | | emit_rsqrtss_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // rsqrtss xmm0,xmm0 |
| 3637 | | emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // cvtsd2ss xmm0,xmm0 |
| 3638 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3639 | | } |
| 3640 | | return TRUE; |
| 3641 | | |
| 3642 | | case 0x20: |
| 3643 | | if (IS_INTEGRAL(op)) |
| 3644 | | { |
| 3645 | | if (IS_SINGLE(op)) /* CVT.S.W */ |
| 3646 | | emit_cvtsi2ss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtsi2ss xmm0,[fsreg] |
| 3647 | | else /* CVT.S.L */ |
| 3648 | | emit_cvtsi2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsi2ss xmm0,[fsreg] |
| 3649 | | } |
| 3650 | | else /* CVT.S.D */ |
| 3651 | | emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsd2ss xmm0,[fsreg] |
| 3652 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3653 | | return TRUE; |
| 3654 | | |
| 3655 | | case 0x21: |
| 3656 | | if (IS_INTEGRAL(op)) |
| 3657 | | { |
| 3658 | | if (IS_SINGLE(op)) /* CVT.D.W */ |
| 3659 | | emit_cvtsi2sd_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtsi2sd xmm0,[fsreg] |
| 3660 | | else /* CVT.D.L */ |
| 3661 | | emit_cvtsi2sd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsi2sd xmm0,[fsreg] |
| 3662 | | } |
| 3663 | | else /* CVT.D.S */ |
| 3664 | | emit_cvtss2sd_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtss2sd xmm0,[fsreg] |
| 3665 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3666 | | return TRUE; |
| 3667 | | |
| 3668 | | case 0x24: |
| 3669 | | if (IS_SINGLE(op)) /* CVT.W.S */ |
| 3670 | | emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg] |
| 3671 | | else /* CVT.W.D */ |
| 3672 | | emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg] |
| 3673 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 3674 | | return TRUE; |
| 3675 | | |
| 3676 | | case 0x25: |
| 3677 | | if (IS_SINGLE(op)) /* CVT.L.S */ |
| 3678 | | emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg] |
| 3679 | | else /* CVT.L.D */ |
| 3680 | | emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg] |
| 3681 | | emit_mov_m64_r64(DRCTOP, FPR32ADDR(FDREG), REG_RAX); // mov [fdreg],rax |
| 3682 | | return TRUE; |
| 3683 | | |
| 3684 | | case 0x30: |
| 3685 | | case 0x38: |
| 3686 | | emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */ |
| 3687 | | return TRUE; |
| 3688 | | |
| 3689 | | case 0x31: |
| 3690 | | case 0x39: |
| 3691 | | emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */ |
| 3692 | | return TRUE; |
| 3693 | | |
| 3694 | | case 0x32: |
| 3695 | | case 0x3a: |
| 3696 | | if (IS_SINGLE(op)) /* C.EQ.S */ |
| 3697 | | { |
| 3698 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3699 | | emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] |
| 3700 | | } |
| 3701 | | else /* C.EQ.D */ |
| 3702 | | { |
| 3703 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3704 | | emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] |
| 3705 | | } |
| 3706 | | emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete fcc[x] |
| 3707 | | return TRUE; |
| 3708 | | |
| 3709 | | case 0x33: |
| 3710 | | case 0x3b: |
| 3711 | | if (IS_SINGLE(op)) /* C.UEQ.S */ |
| 3712 | | { |
| 3713 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3714 | | emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] |
| 3715 | | } |
| 3716 | | else /* C.UEQ.D */ |
| 3717 | | { |
| 3718 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3719 | | emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] |
| 3720 | | } |
| 3721 | | emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete fcc[x] |
| 3722 | | return TRUE; |
| 3723 | | |
| 3724 | | case 0x34: |
| 3725 | | case 0x3c: |
| 3726 | | if (IS_SINGLE(op)) /* C.OLT.S */ |
| 3727 | | { |
| 3728 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3729 | | emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] |
| 3730 | | } |
| 3731 | | else /* C.OLT.D */ |
| 3732 | | { |
| 3733 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3734 | | emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] |
| 3735 | | } |
| 3736 | | emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb fcc[x] |
| 3737 | | return TRUE; |
| 3738 | | |
| 3739 | | case 0x35: |
| 3740 | | case 0x3d: |
| 3741 | | if (IS_SINGLE(op)) /* C.ULT.S */ |
| 3742 | | { |
| 3743 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3744 | | emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] |
| 3745 | | } |
| 3746 | | else /* C.ULT.D */ |
| 3747 | | { |
| 3748 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3749 | | emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] |
| 3750 | | } |
| 3751 | | emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb fcc[x] |
| 3752 | | return TRUE; |
| 3753 | | |
| 3754 | | case 0x36: |
| 3755 | | case 0x3e: |
| 3756 | | if (IS_SINGLE(op)) /* C.OLE.S */ |
| 3757 | | { |
| 3758 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3759 | | emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] |
| 3760 | | } |
| 3761 | | else /* C.OLE.D */ |
| 3762 | | { |
| 3763 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3764 | | emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] |
| 3765 | | } |
| 3766 | | emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe fcc[x] |
| 3767 | | return TRUE; |
| 3768 | | |
| 3769 | | case 0x37: |
| 3770 | | case 0x3f: |
| 3771 | | if (IS_SINGLE(op)) /* C.ULE.S */ |
| 3772 | | { |
| 3773 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3774 | | emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] |
| 3775 | | } |
| 3776 | | else /* C.ULE.D */ |
| 3777 | | { |
| 3778 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3779 | | emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] |
| 3780 | | } |
| 3781 | | emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe fcc[x] |
| 3782 | | return TRUE; |
| 3783 | | } |
| 3784 | | break; |
| 3785 | | } |
| 3786 | | return FALSE; |
| 3787 | | } |
| 3788 | | |
| 3789 | | |
| 3790 | | |
| 3791 | | /*************************************************************************** |
| 3792 | | COP1X RECOMPILATION |
| 3793 | | ***************************************************************************/ |
| 3794 | | |
| 3795 | | /*------------------------------------------------- |
| 3796 | | compile_cop1x - compile COP1X opcodes |
| 3797 | | -------------------------------------------------*/ |
| 3798 | | |
| 3799 | | static int compile_cop1x(drc_core *drc, compiler_state *compiler, const opcode_desc *desc) |
| 3800 | | { |
| 3801 | | UINT32 op = *desc->opptr.l; |
| 3802 | | |
| 3803 | | if (mips3.drcoptions & MIPS3DRC_STRICT_COP1) |
| 3804 | | { |
| 3805 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [mips3.core->cpr[0][COP0_Status]],SR_COP1 |
| 3806 | | oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception); |
| 3807 | | // jz generate_cop_exception |
| 3808 | | } |
| 3809 | | |
| 3810 | | switch (op & 0x3f) |
| 3811 | | { |
| 3812 | | case 0x00: /* LWXC1 */ |
| 3813 | | return compile_loadx_cop(drc, compiler, desc, 4, FPR32(FDREG)); |
| 3814 | | |
| 3815 | | case 0x01: /* LDXC1 */ |
| 3816 | | return compile_loadx_cop(drc, compiler, desc, 8, FPR64(FDREG)); |
| 3817 | | |
| 3818 | | case 0x08: /* SWXC1 */ |
| 3819 | | return compile_storex_cop(drc, compiler, desc, 4, FPR32(FDREG)); |
| 3820 | | |
| 3821 | | case 0x09: /* SDXC1 */ |
| 3822 | | return compile_storex_cop(drc, compiler, desc, 8, FPR64(FDREG)); |
| 3823 | | |
| 3824 | | case 0x0f: /* PREFX */ |
| 3825 | | return TRUE; |
| 3826 | | |
| 3827 | | case 0x20: /* MADD.S */ |
| 3828 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3829 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 3830 | | emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg] |
| 3831 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3832 | | return TRUE; |
| 3833 | | |
| 3834 | | case 0x21: /* MADD.D */ |
| 3835 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3836 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 3837 | | emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg] |
| 3838 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3839 | | return TRUE; |
| 3840 | | |
| 3841 | | case 0x28: /* MSUB.S */ |
| 3842 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3843 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 3844 | | emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg] |
| 3845 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3846 | | return TRUE; |
| 3847 | | |
| 3848 | | case 0x29: /* MSUB.D */ |
| 3849 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3850 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 3851 | | emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg] |
| 3852 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3853 | | return TRUE; |
| 3854 | | |
| 3855 | | case 0x30: /* NMADD.S */ |
| 3856 | | emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1 |
| 3857 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3858 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 3859 | | emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg] |
| 3860 | | emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 |
| 3861 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1 |
| 3862 | | return TRUE; |
| 3863 | | |
| 3864 | | case 0x31: /* NMADD.D */ |
| 3865 | | emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1 |
| 3866 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3867 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 3868 | | emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg] |
| 3869 | | emit_subsd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subsd xmm1,xmm0 |
| 3870 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1 |
| 3871 | | return TRUE; |
| 3872 | | |
| 3873 | | case 0x38: /* NMSUB.S */ |
| 3874 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3875 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 3876 | | emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg] |
| 3877 | | emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 |
| 3878 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1 |
| 3879 | | return TRUE; |
| 3880 | | |
| 3881 | | case 0x39: /* NMSUB.D */ |
| 3882 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3883 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 3884 | | emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg] |
| 3885 | | emit_subsd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subsd xmm1,xmm0 |
| 3886 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1 |
| 3887 | | return TRUE; |
| 3888 | | |
| 3889 | | case 0x24: /* MADD.W */ |
| 3890 | | case 0x25: /* MADD.L */ |
| 3891 | | case 0x2c: /* MSUB.W */ |
| 3892 | | case 0x2d: /* MSUB.L */ |
| 3893 | | case 0x34: /* NMADD.W */ |
| 3894 | | case 0x35: /* NMADD.L */ |
| 3895 | | case 0x3c: /* NMSUB.W */ |
| 3896 | | case 0x3d: /* NMSUB.L */ |
| 3897 | | default: |
| 3898 | | fprintf(stderr, "cop1x %X\n", op); |
| 3899 | | break; |
| 3900 | | } |
| 3901 | | return FALSE; |
| 3902 | | } |
| 3903 | | |
| 3904 | | |
| 3905 | | |
| 3906 | | /*************************************************************************** |
| 3907 | | INDIVIDUAL INSTRUCTION COMPILATION |
| 3908 | | ***************************************************************************/ |
| 3909 | | |
| 3910 | | /*------------------------------------------------- |
| 3911 | | compile_shift - compile a 32-bit |
| 3912 | | shift, both fixed and variable counts |
| 3913 | | |
| 3914 | | 0: sll/sllv rD,rT,rS |
| 3915 | | 2: srl/srlv rD,rT,rS |
| 3916 | | 3: sra/srav rD,rT,rS |
| 3917 | | -------------------------------------------------*/ |
| 3918 | | |
| 3919 | | static int compile_shift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable) |
| 3920 | | { |
| 3921 | | UINT32 op = *desc->opptr.l; |
| 3922 | | mipsreg_state rd, rs, rt; |
| 3923 | | |
| 3924 | | assert(shift_type == 0 || shift_type == 2 || shift_type == 3); |
| 3925 | | |
| 3926 | | /* if the destination is r0, bail */ |
| 3927 | | if (RDREG == 0) |
| 3928 | | return TRUE; |
| 3929 | | |
| 3930 | | /* allocate source registers */ |
| 3931 | | rs = shift_variable ? compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC) : MAKE_CONST(SHIFT); |
| 3932 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 3933 | | |
| 3934 | | /* if rS and rT are both constant, we can compute the constant result */ |
| 3935 | | if (ISCONST(rs) && ISCONST(rt)) |
| 3936 | | { |
| 3937 | | if (shift_type == 0) |
| 3938 | | emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((UINT32)CONSTVAL(rt) << CONSTVAL(rs))); |
| 3939 | | else if (shift_type == 2) |
| 3940 | | emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((UINT32)CONSTVAL(rt) >> CONSTVAL(rs))); |
| 3941 | | else |
| 3942 | | emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((INT32)CONSTVAL(rt) >> CONSTVAL(rs))); |
| 3943 | | } |
| 3944 | | |
| 3945 | | /* otherwise, handle generically */ |
| 3946 | | else |
| 3947 | | { |
| 3948 | | /* allocate the register and load rT into it */ |
| 3949 | | /* if rS is non-const, must load it first in case rD == rS */ |
| 3950 | | rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY); |
| 3951 | | if (!ISCONST(rs)) |
| 3952 | | emit_load_register_value(drc, compiler, REG_ECX, rs); // mov ecx,<rs> |
| 3953 | | emit_load_register_value(drc, compiler, X86REG(rd), rt); // mov <rd>,<rt> |
| 3954 | | |
| 3955 | | /* if rs is constant, use immediate forms of the shift */ |
| 3956 | | if (ISCONST(rs)) |
| 3957 | | { |
| 3958 | | if (shift_type == 0) |
| 3959 | | emit_shl_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // shl <rd>,<rs> |
| 3960 | | else if (shift_type == 2) |
| 3961 | | emit_shr_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // shr <rd>,<rs> |
| 3962 | | else |
| 3963 | | emit_sar_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // sar <rd>,<rs> |
| 3964 | | } |
| 3965 | | |
| 3966 | | /* otherwise, load rs into cl so we can do a variable shift */ |
| 3967 | | else |
| 3968 | | { |
| 3969 | | if (shift_type == 0) |
| 3970 | | emit_shl_r32_cl(DRCTOP, X86REG(rd)); // shl <rd>,cl |
| 3971 | | else if (shift_type == 2) |
| 3972 | | emit_shr_r32_cl(DRCTOP, X86REG(rd)); // shr <rd>,cl |
| 3973 | | else |
| 3974 | | emit_sar_r32_cl(DRCTOP, X86REG(rd)); // sar <rd>,cl |
| 3975 | | } |
| 3976 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd> |
| 3977 | | } |
| 3978 | | return TRUE; |
| 3979 | | } |
| 3980 | | |
| 3981 | | |
| 3982 | | /*------------------------------------------------- |
| 3983 | | compile_dshift - compile a 64-bit |
| 3984 | | shift, both fixed and variable counts |
| 3985 | | |
| 3986 | | 0: dsll/dsll32/dsllv rD,rT,rS |
| 3987 | | 2: dsrl/dsrl32/dsrlv rD,rT,rS |
| 3988 | | 3: dsra/dsra32/dsrav rD,rT,rS |
| 3989 | | -------------------------------------------------*/ |
| 3990 | | |
| 3991 | | static int compile_dshift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable, int shift_const_plus32) |
| 3992 | | { |
| 3993 | | UINT32 op = *desc->opptr.l; |
| 3994 | | mipsreg_state rd, rs, rt; |
| 3995 | | |
| 3996 | | assert(shift_type == 0 || shift_type == 2 || shift_type == 3); |
| 3997 | | |
| 3998 | | /* if the destination is r0, bail */ |
| 3999 | | if (RDREG == 0) |
| 4000 | | return TRUE; |
| 4001 | | |
| 4002 | | /* allocate source registers */ |
| 4003 | | rs = shift_variable ? compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC) : MAKE_CONST(SHIFT + (shift_const_plus32 ? 32 : 0)); |
| 4004 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4005 | | |
| 4006 | | /* if rS and rT are both constant, we can compute the constant result */ |
| 4007 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4008 | | { |
| 4009 | | if (shift_type == 0) |
| 4010 | | emit_set_constant_value(drc, compiler, desc, RDREG, (UINT64)CONSTVAL(rt) << CONSTVAL(rs)); |
| 4011 | | else if (shift_type == 2) |
| 4012 | | emit_set_constant_value(drc, compiler, desc, RDREG, (UINT64)CONSTVAL(rt) >> CONSTVAL(rs)); |
| 4013 | | else |
| 4014 | | emit_set_constant_value(drc, compiler, desc, RDREG, (INT64)CONSTVAL(rt) >> CONSTVAL(rs)); |
| 4015 | | } |
| 4016 | | |
| 4017 | | /* otherwise, handle generically */ |
| 4018 | | else |
| 4019 | | { |
| 4020 | | /* allocate the register and load rT into it */ |
| 4021 | | /* if rS is non-const, must load it first in case rD == rS */ |
| 4022 | | rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY); |
| 4023 | | if (!ISCONST(rs)) |
| 4024 | | emit_load_register_value(drc, compiler, REG_ECX, rs); // mov ecx,<rs> |
| 4025 | | emit_load_register_value(drc, compiler, X86REG(rd), rt); // mov <rd>,<rt> |
| 4026 | | |
| 4027 | | /* if rs is constant, use immediate forms of the shift */ |
| 4028 | | if (ISCONST(rs)) |
| 4029 | | { |
| 4030 | | if (shift_type == 0) |
| 4031 | | emit_shl_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // shl <rd>,<rs> |
| 4032 | | else if (shift_type == 2) |
| 4033 | | emit_shr_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // shr <rd>,<rs> |
| 4034 | | else |
| 4035 | | emit_sar_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // sar <rd>,<rs> |
| 4036 | | } |
| 4037 | | |
| 4038 | | /* otherwise, load rs into cl so we can do a variable shift */ |
| 4039 | | else |
| 4040 | | { |
| 4041 | | if (shift_type == 0) |
| 4042 | | emit_shl_r64_cl(DRCTOP, X86REG(rd)); // shl <rd>,cl |
| 4043 | | else if (shift_type == 2) |
| 4044 | | emit_shr_r64_cl(DRCTOP, X86REG(rd)); // shr <rd>,cl |
| 4045 | | else |
| 4046 | | emit_sar_r64_cl(DRCTOP, X86REG(rd)); // sar <rd>,cl |
| 4047 | | } |
| 4048 | | } |
| 4049 | | return TRUE; |
| 4050 | | } |
| 4051 | | |
| 4052 | | |
| 4053 | | /*------------------------------------------------- |
| 4054 | | compile_movzn - compile a conditional |
| 4055 | | move based on compare against 0 |
| 4056 | | |
| 4057 | | movz/movn rD,rS,rT |
| 4058 | | -------------------------------------------------*/ |
| 4059 | | |
| 4060 | | static int compile_movzn(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_movn) |
| 4061 | | { |
| 4062 | | UINT32 op = *desc->opptr.l; |
| 4063 | | mipsreg_state rd, rs, rt; |
| 4064 | | emit_link skip = { 0 }; |
| 4065 | | |
| 4066 | | /* if the destination is r0, bail */ |
| 4067 | | if (RDREG == 0) |
| 4068 | | return TRUE; |
| 4069 | | |
| 4070 | | /* allocate source registers */ |
| 4071 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4072 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4073 | | rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY); |
| 4074 | | |
| 4075 | | /* if rT is constant and fails the condition, we're done */ |
| 4076 | | if (ISCONST(rt)) |
| 4077 | | { |
| 4078 | | INT32 rtval = CONSTVAL(rt); |
| 4079 | | if ((is_movn && rtval == 0) || (!is_movn && rtval != 0)) |
| 4080 | | return TRUE; |
| 4081 | | } |
| 4082 | | |
| 4083 | | /* if rT is not constant, check the condition */ |
| 4084 | | else |
| 4085 | | { |
| 4086 | | emit_test_r64_r64(DRCTOP, X86REG(rt), X86REG(rt)); // test <rt>,<rt> |
| 4087 | | emit_jcc_short_link(DRCTOP, is_movn ? COND_Z : COND_NZ, &skip); // jz/nz skip |
| 4088 | | } |
| 4089 | | |
| 4090 | | /* load rS into rD */ |
| 4091 | | emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs> |
| 4092 | | if (!ISCONST(rt)) |
| 4093 | | resolve_link(DRCTOP, &skip); // skip: |
| 4094 | | |
| 4095 | | return TRUE; |
| 4096 | | } |
| 4097 | | |
| 4098 | | |
| 4099 | | /*------------------------------------------------- |
| 4100 | | compile_trapcc - compile a conditional |
| 4101 | | trap comparing two registers |
| 4102 | | |
| 4103 | | 0/1: tge/tgeu rS,rT / tgei/tgeiu rS,SIMM |
| 4104 | | 2/3: tlt/tltu rS,rT / tlti/tltiu rS,SIMM |
| 4105 | | 4: teq rS,rT / teqi rS,SIMM |
| 4106 | | 6: tne rS,rT / tnei rS,SIMM |
| 4107 | | -------------------------------------------------*/ |
| 4108 | | |
| 4109 | | static int compile_trapcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int immediate) |
| 4110 | | { |
| 4111 | | static const UINT8 condtype[] = { COND_GE, COND_AE, COND_L, COND_B, COND_E, COND_NONE, COND_NE, COND_NONE }; |
| 4112 | | UINT32 op = *desc->opptr.l; |
| 4113 | | mipsreg_state rs, rt; |
| 4114 | | |
| 4115 | | assert(condition < ARRAY_LENGTH(condtype) && condtype[condition] != COND_NONE); |
| 4116 | | |
| 4117 | | /* allocate source registers */ |
| 4118 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4119 | | rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4120 | | |
| 4121 | | /* if both constant, we know the answer up front */ |
| 4122 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4123 | | { |
| 4124 | | INT32 rsval = CONSTVAL(rs); |
| 4125 | | INT32 rtval = CONSTVAL(rt); |
| 4126 | | int result = FALSE; |
| 4127 | | |
| 4128 | | /* determine the fixed answer */ |
| 4129 | | switch (condition) |
| 4130 | | { |
| 4131 | | case 0: result = ((INT64)rsval >= (INT64)rtval); break; |
| 4132 | | case 1: result = ((UINT64)rsval >= (UINT64)rtval); break; |
| 4133 | | case 2: result = ((INT64)rsval < (INT64)rtval); break; |
| 4134 | | case 3: result = ((UINT64)rsval < (UINT64)rtval); break; |
| 4135 | | case 4: result = (rsval == rtval); break; |
| 4136 | | case 6: result = (rsval != rtval); break; |
| 4137 | | } |
| 4138 | | |
| 4139 | | /* if we're not trapping, just return; otherwise, always trap */ |
| 4140 | | if (!result) |
| 4141 | | return TRUE; |
| 4142 | | condition = COND_NONE; |
| 4143 | | } |
| 4144 | | |
| 4145 | | /* if rT is constant do an immediate compare */ |
| 4146 | | else if (ISCONST(rt)) |
| 4147 | | { |
| 4148 | | emit_cmp_r64_imm(DRCTOP, X86REG(rs), CONSTVAL(rt)); // cmp <rs>,<rt> |
| 4149 | | condition = condtype[condition]; |
| 4150 | | } |
| 4151 | | |
| 4152 | | /* if rS is constant do an immediate compare with opposite condition */ |
| 4153 | | else if (ISCONST(rs)) |
| 4154 | | { |
| 4155 | | emit_cmp_r64_imm(DRCTOP, X86REG(rt), CONSTVAL(rs)); // cmp <rt>,<rs> |
| 4156 | | condition = condtype[condition] ^ 1; |
| 4157 | | } |
| 4158 | | |
| 4159 | | /* otherwise, compare the two registers with a normal condition */ |
| 4160 | | else |
| 4161 | | { |
| 4162 | | emit_cmp_r64_imm(DRCTOP, X86REG(rs), X86REG(rt)); // cmp <rs>,<rt> |
| 4163 | | condition = condtype[condition]; |
| 4164 | | } |
| 4165 | | |
| 4166 | | /* generate an OOB request if the trap is taken */ |
| 4167 | | oob_request_callback(drc, condition, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_trap_exception); |
| 4168 | | return TRUE; |
| 4169 | | } |
| 4170 | | |
| 4171 | | |
| 4172 | | /*------------------------------------------------- |
| 4173 | | compile_branchcc - compile a conditional |
| 4174 | | branch comparing two registers |
| 4175 | | |
| 4176 | | beq rS,rT,dest |
| 4177 | | bne rS,rT,dest |
| 4178 | | -------------------------------------------------*/ |
| 4179 | | |
| 4180 | | static int compile_branchcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition) |
| 4181 | | { |
| 4182 | | UINT32 op = *desc->opptr.l; |
| 4183 | | emit_link skip = { 0 }; |
| 4184 | | mipsreg_state rs, rt; |
| 4185 | | |
| 4186 | | assert(condition == COND_E || condition == COND_NE); |
| 4187 | | |
| 4188 | | /* allocate source registers */ |
| 4189 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4190 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4191 | | |
| 4192 | | /* if both constant, we know the answer up front */ |
| 4193 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4194 | | { |
| 4195 | | INT32 rsval = CONSTVAL(rs); |
| 4196 | | INT32 rtval = CONSTVAL(rt); |
| 4197 | | if ((condition == COND_E && rsval != rtval) || (condition == COND_NE && rsval == rtval)) |
| 4198 | | return TRUE; |
| 4199 | | } |
| 4200 | | |
| 4201 | | /* if rT is constant do an immediate compare */ |
| 4202 | | else if (ISCONST(rt)) |
| 4203 | | { |
| 4204 | | emit_cmp_r64_imm(DRCTOP, X86REG(rs), CONSTVAL(rt)); // cmp <rs>,<rt> |
| 4205 | | emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip |
| 4206 | | } |
| 4207 | | |
| 4208 | | /* if rS is constant do an immediate compare */ |
| 4209 | | else if (ISCONST(rs)) |
| 4210 | | { |
| 4211 | | emit_cmp_r64_imm(DRCTOP, X86REG(rt), CONSTVAL(rs)); // cmp <rt>,<rs> |
| 4212 | | emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip |
| 4213 | | } |
| 4214 | | |
| 4215 | | /* otherwise, compare the two registers with a normal condition */ |
| 4216 | | else |
| 4217 | | { |
| 4218 | | emit_cmp_r64_r64(DRCTOP, X86REG(rs), X86REG(rt)); // cmp <rs>,<rt> |
| 4219 | | emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip |
| 4220 | | } |
| 4221 | | |
| 4222 | | /* append the branch logic */ |
| 4223 | | emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch> |
| 4224 | | |
| 4225 | | if (!(ISCONST(rs) && ISCONST(rt))) |
| 4226 | | resolve_link(DRCTOP, &skip); // skip: |
| 4227 | | return TRUE; |
| 4228 | | } |
| 4229 | | |
| 4230 | | |
| 4231 | | /*------------------------------------------------- |
| 4232 | | compile_branchcz - compile a conditional |
| 4233 | | branch comparing one register against 0 |
| 4234 | | |
| 4235 | | blez rS,dest |
| 4236 | | blezl rS,dest |
| 4237 | | bgtz rS,dest |
| 4238 | | bgtzl rS,dest |
| 4239 | | bltz rS,dest |
| 4240 | | bltzl rS,dest |
| 4241 | | bltzal rS,dest |
| 4242 | | bltzall rS,dest |
| 4243 | | bgez rS,dest |
| 4244 | | bgezl rS,dest |
| 4245 | | bgezal rS,dest |
| 4246 | | bgezall rS,dest |
| 4247 | | -------------------------------------------------*/ |
| 4248 | | |
| 4249 | | static int compile_branchcz(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int link) |
| 4250 | | { |
| 4251 | | UINT32 op = *desc->opptr.l; |
| 4252 | | emit_link skip = { 0 }; |
| 4253 | | mipsreg_state rs; |
| 4254 | | |
| 4255 | | /* allocate source registers */ |
| 4256 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4257 | | |
| 4258 | | /* if the register is constant, we know the answer up front */ |
| 4259 | | if (ISCONST(rs)) |
| 4260 | | { |
| 4261 | | INT32 rsval = CONSTVAL(rs); |
| 4262 | | if ((condition == COND_LE && rsval > 0) || (condition == COND_G && rsval <= 0) || |
| 4263 | | (condition == COND_L && rsval >= 0) || (condition == COND_GE && rsval < 0)) |
| 4264 | | return TRUE; |
| 4265 | | } |
| 4266 | | |
| 4267 | | /* otherwise, perform the compare */ |
| 4268 | | else |
| 4269 | | { |
| 4270 | | emit_cmp_r64_imm(DRCTOP, X86REG(rs), 0); // cmp <rs>,0 |
| 4271 | | emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip |
| 4272 | | } |
| 4273 | | |
| 4274 | | /* append the branch logic */ |
| 4275 | | emit_delay_slot_and_branch(drc, compiler, desc, link ? 31 : 0); // <next instruction + redispatch> |
| 4276 | | |
| 4277 | | if (!ISCONST(rs)) |
| 4278 | | resolve_link(DRCTOP, &skip); // skip: |
| 4279 | | return TRUE; |
| 4280 | | } |
| 4281 | | |
| 4282 | | |
| 4283 | | /*------------------------------------------------- |
| 4284 | | compile_add - compile an add with or without |
| 4285 | | overflow |
| 4286 | | |
| 4287 | | add rD,rS,rT / addi rT,rS,SIMM |
| 4288 | | addu rD,rS,rT / addiu rT,rS,SIMM |
| 4289 | | -------------------------------------------------*/ |
| 4290 | | |
| 4291 | | static int compile_add(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate) |
| 4292 | | { |
| 4293 | | UINT32 op = *desc->opptr.l; |
| 4294 | | UINT8 destreg = immediate ? RTREG : RDREG; |
| 4295 | | mipsreg_state rd, rs, rt; |
| 4296 | | |
| 4297 | | /* note that we still must perform this operation even if destreg == 0 |
| 4298 | | in the overflow case */ |
| 4299 | | if (destreg == 0 && suppress_exceptions) |
| 4300 | | return TRUE; |
| 4301 | | |
| 4302 | | /* allocate source registers */ |
| 4303 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4304 | | rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4305 | | |
| 4306 | | /* if both constant, we know the answer up front */ |
| 4307 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4308 | | { |
| 4309 | | INT64 result = (INT64)CONSTVAL(rs) + (INT64)CONSTVAL(rt); |
| 4310 | | |
| 4311 | | /* if we overflow, always generate an exception */ |
| 4312 | | if (!suppress_exceptions && (INT32)result != result) |
| 4313 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4314 | | |
| 4315 | | /* else just set the new constant value */ |
| 4316 | | else if (destreg != 0) |
| 4317 | | emit_set_constant_value(drc, compiler, desc, destreg, (INT32)result); |
| 4318 | | } |
| 4319 | | |
| 4320 | | /* otherwise, handle generically */ |
| 4321 | | else |
| 4322 | | { |
| 4323 | | rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST); |
| 4324 | | |
| 4325 | | /* perform the operating in EAX so we don't trash rD if an exception happens */ |
| 4326 | | if (!suppress_exceptions) |
| 4327 | | { |
| 4328 | | emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs> |
| 4329 | | if (!ISCONST(rt)) |
| 4330 | | emit_add_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // add eax,<rt> |
| 4331 | | else if (CONSTVAL(rt) != 0) |
| 4332 | | emit_add_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rt)); // add eax,<rt> |
| 4333 | | oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4334 | | // jo generate_overflow_exception |
| 4335 | | if (destreg != 0) |
| 4336 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), REG_EAX); // movsxd <rd>,eax |
| 4337 | | } |
| 4338 | | else |
| 4339 | | { |
| 4340 | | if (ISCONST(rs) && CONSTVAL(rs) == 0) |
| 4341 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rt)); // movsxd <rd>,<rt> |
| 4342 | | else if (ISCONST(rt) && CONSTVAL(rt) == 0) |
| 4343 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rs)); // movsxd <rd>,<rs> |
| 4344 | | else if (ISCONST(rs)) |
| 4345 | | { |
| 4346 | | emit_lea_r32_m32(DRCTOP, X86REG(rd), MBD(X86REG(rt), CONSTVAL(rs))); // lea <rd>,[<rt> + <rs>] |
| 4347 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd> |
| 4348 | | } |
| 4349 | | else if (ISCONST(rt)) |
| 4350 | | { |
| 4351 | | emit_lea_r32_m32(DRCTOP, X86REG(rd), MBD(X86REG(rs), CONSTVAL(rt))); // lea <rd>,[<rs> + <rt>] |
| 4352 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd> |
| 4353 | | } |
| 4354 | | else |
| 4355 | | { |
| 4356 | | emit_lea_r32_m32(DRCTOP, X86REG(rd), MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea <rd>,[<rs> + <rt>] |
| 4357 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd> |
| 4358 | | } |
| 4359 | | } |
| 4360 | | |
| 4361 | | /* only mark it dirty after the exception risk is over */ |
| 4362 | | compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DIRTY); |
| 4363 | | } |
| 4364 | | return TRUE; |
| 4365 | | } |
| 4366 | | |
| 4367 | | |
| 4368 | | /*------------------------------------------------- |
| 4369 | | compile_dadd - compile an add with or without |
| 4370 | | overflow |
| 4371 | | |
| 4372 | | dadd rD,rS,rT |
| 4373 | | daddu rD,rS,rT |
| 4374 | | -------------------------------------------------*/ |
| 4375 | | |
| 4376 | | static int compile_dadd(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate) |
| 4377 | | { |
| 4378 | | UINT32 op = *desc->opptr.l; |
| 4379 | | UINT8 destreg = immediate ? RTREG : RDREG; |
| 4380 | | mipsreg_state rd, rs, rt; |
| 4381 | | |
| 4382 | | /* note that we still must perform this operation even if destreg == 0 |
| 4383 | | in the overflow case */ |
| 4384 | | if (destreg == 0 && suppress_exceptions) |
| 4385 | | return TRUE; |
| 4386 | | |
| 4387 | | /* allocate source registers */ |
| 4388 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4389 | | rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4390 | | |
| 4391 | | /* if both constant, we know the answer up front */ |
| 4392 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4393 | | { |
| 4394 | | INT64 result = (INT64)CONSTVAL(rs) + (INT64)CONSTVAL(rt); |
| 4395 | | |
| 4396 | | /* if we overflow, always generate an exception */ |
| 4397 | | if (!suppress_exceptions && (INT32)result != result) |
| 4398 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4399 | | |
| 4400 | | /* else just set the new constant value */ |
| 4401 | | else if (destreg != 0) |
| 4402 | | emit_set_constant_value(drc, compiler, desc, destreg, result); |
| 4403 | | } |
| 4404 | | |
| 4405 | | /* otherwise, handle generically */ |
| 4406 | | else |
| 4407 | | { |
| 4408 | | rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST); |
| 4409 | | |
| 4410 | | /* perform the operating in EAX so we don't trash RTREG if an exception happens */ |
| 4411 | | if (!suppress_exceptions) |
| 4412 | | { |
| 4413 | | emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs> |
| 4414 | | if (!ISCONST(rt)) |
| 4415 | | emit_add_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // add rax,<rt> |
| 4416 | | else if (CONSTVAL(rt) != 0) |
| 4417 | | emit_add_r64_imm(DRCTOP, REG_RAX, CONSTVAL(rt)); // add rax,<rt> |
| 4418 | | oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4419 | | // jo generate_overflow_exception |
| 4420 | | if (destreg != 0) |
| 4421 | | emit_mov_r64_r64(DRCTOP, X86REG(rd), REG_RAX); // mov <rd>,rax |
| 4422 | | } |
| 4423 | | else |
| 4424 | | { |
| 4425 | | if (ISCONST(rs)) |
| 4426 | | emit_lea_r64_m64(DRCTOP, X86REG(rd), MBD(X86REG(rt), CONSTVAL(rs))); // lea <rd>,[<rt> + <rs>] |
| 4427 | | else if (ISCONST(rt)) |
| 4428 | | emit_lea_r64_m64(DRCTOP, X86REG(rd), MBD(X86REG(rs), CONSTVAL(rt))); // lea <rd>,[<rs> + <rt>] |
| 4429 | | else |
| 4430 | | emit_lea_r64_m64(DRCTOP, X86REG(rd), MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea <rd>,[<rs> + <rt>] |
| 4431 | | } |
| 4432 | | |
| 4433 | | /* only mark it dirty after the exception risk is over */ |
| 4434 | | compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DIRTY); |
| 4435 | | } |
| 4436 | | return TRUE; |
| 4437 | | } |
| 4438 | | |
| 4439 | | |
| 4440 | | /*------------------------------------------------- |
| 4441 | | compile_sub - compile an add with or without |
| 4442 | | overflow |
| 4443 | | |
| 4444 | | sub rD,rS,rT |
| 4445 | | subu rD,rS,rT |
| 4446 | | -------------------------------------------------*/ |
| 4447 | | |
| 4448 | | static int compile_sub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions) |
| 4449 | | { |
| 4450 | | UINT32 op = *desc->opptr.l; |
| 4451 | | mipsreg_state rd, rs, rt; |
| 4452 | | |
| 4453 | | /* note that we still must perform this operation even if RDREG == 0 |
| 4454 | | in the overflow case */ |
| 4455 | | if (RDREG == 0 && suppress_exceptions) |
| 4456 | | return TRUE; |
| 4457 | | |
| 4458 | | /* allocate source registers */ |
| 4459 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4460 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4461 | | |
| 4462 | | /* if both constant, we know the answer up front */ |
| 4463 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4464 | | { |
| 4465 | | INT64 result = (INT64)CONSTVAL(rs) - (INT64)CONSTVAL(rt); |
| 4466 | | |
| 4467 | | /* if we overflow, always generate an exception */ |
| 4468 | | if (!suppress_exceptions && (INT32)result != result) |
| 4469 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4470 | | |
| 4471 | | /* else just set the new constant value */ |
| 4472 | | else if (RDREG != 0) |
| 4473 | | emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)result); |
| 4474 | | } |
| 4475 | | |
| 4476 | | /* if rS == rT, the result is 0 */ |
| 4477 | | else if (RSREG == RTREG) |
| 4478 | | { |
| 4479 | | if (RDREG != 0) |
| 4480 | | emit_set_constant_value(drc, compiler, desc, RDREG, 0); |
| 4481 | | } |
| 4482 | | |
| 4483 | | /* otherwise, handle generically */ |
| 4484 | | else |
| 4485 | | { |
| 4486 | | rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST); |
| 4487 | | |
| 4488 | | /* perform the operating in EAX so we don't trash RTREG if an exception happens */ |
| 4489 | | if (!suppress_exceptions) |
| 4490 | | { |
| 4491 | | emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs> |
| 4492 | | if (!ISCONST(rt)) |
| 4493 | | emit_sub_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // sub eax,<rt> |
| 4494 | | else if (CONSTVAL(rt) != 0) |
| 4495 | | emit_sub_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rt)); // sub eax,<rt> |
| 4496 | | if (!ISCONST(rt) || CONSTVAL(rt) != 0) |
| 4497 | | oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4498 | | // jo generate_overflow_exception |
| 4499 | | if (RDREG != 0) |
| 4500 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), REG_EAX); // movsxd <rd>,eax |
| 4501 | | } |
| 4502 | | else |
| 4503 | | { |
| 4504 | | /* if rD and rT aren't the same, it is pretty basic */ |
| 4505 | | if (X86REG(rd) != X86REG(rt)) |
| 4506 | | { |
| 4507 | | emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs> |
| 4508 | | if (!ISCONST(rt)) |
| 4509 | | emit_sub_r32_r32(DRCTOP, X86REG(rd), X86REG(rt)); // sub <rd>,<rt> |
| 4510 | | else if (CONSTVAL(rt) != 0) |
| 4511 | | emit_sub_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // sub <rd>,<rt> |
| 4512 | | } |
| 4513 | | |
| 4514 | | /* otherwise, we negate rT and add rS */ |
| 4515 | | else |
| 4516 | | { |
| 4517 | | emit_neg_r32(DRCTOP, X86REG(rd)); // neg <rd> |
| 4518 | | if (!ISCONST(rs)) |
| 4519 | | emit_add_r32_r32(DRCTOP, X86REG(rd), X86REG(rs)); // add <rd>,<rs> |
| 4520 | | else if (CONSTVAL(rs) != 0) |
| 4521 | | emit_add_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs)); // add <rd>,<rs> |
| 4522 | | } |
| 4523 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd> |
| 4524 | | } |
| 4525 | | |
| 4526 | | /* only mark it dirty after the exception risk is over */ |
| 4527 | | compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DIRTY); |
| 4528 | | } |
| 4529 | | return TRUE; |
| 4530 | | } |
| 4531 | | |
| 4532 | | |
| 4533 | | /*------------------------------------------------- |
| 4534 | | compile_dsub - compile an add with or without |
| 4535 | | overflow |
| 4536 | | |
| 4537 | | dsub rD,rS,rT |
| 4538 | | dsubu rD,rS,rT |
| 4539 | | -------------------------------------------------*/ |
| 4540 | | |
| 4541 | | static int compile_dsub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions) |
| 4542 | | { |
| 4543 | | UINT32 op = *desc->opptr.l; |
| 4544 | | mipsreg_state rd, rs, rt; |
| 4545 | | |
| 4546 | | /* note that we still must perform this operation even if RDREG == 0 |
| 4547 | | in the overflow case */ |
| 4548 | | if (RDREG == 0 && suppress_exceptions) |
| 4549 | | return TRUE; |
| 4550 | | |
| 4551 | | /* allocate source registers */ |
| 4552 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4553 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4554 | | |
| 4555 | | /* if both constant, we know the answer up front */ |
| 4556 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4557 | | { |
| 4558 | | INT64 result = (INT64)CONSTVAL(rs) - (INT64)CONSTVAL(rt); |
| 4559 | | |
| 4560 | | /* if we overflow, always generate an exception */ |
| 4561 | | if (!suppress_exceptions && (INT32)result != result) |
| 4562 | | oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4563 | | |
| 4564 | | /* else just set the new constant value */ |
| 4565 | | else if (RDREG != 0) |
| 4566 | | emit_set_constant_value(drc, compiler, desc, RDREG, result); |
| 4567 | | } |
| 4568 | | |
| 4569 | | /* if rS == rT, the result is 0 */ |
| 4570 | | else if (RSREG == RTREG) |
| 4571 | | { |
| 4572 | | if (RDREG != 0) |
| 4573 | | emit_set_constant_value(drc, compiler, desc, RDREG, 0); |
| 4574 | | } |
| 4575 | | |
| 4576 | | /* otherwise, handle generically */ |
| 4577 | | else |
| 4578 | | { |
| 4579 | | rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST); |
| 4580 | | |
| 4581 | | /* perform the operating in EAX so we don't trash RTREG if an exception happens */ |
| 4582 | | if (!suppress_exceptions) |
| 4583 | | { |
| 4584 | | emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs> |
| 4585 | | if (!ISCONST(rt)) |
| 4586 | | emit_sub_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // sub rax,<rt> |
| 4587 | | else if (CONSTVAL(rt) != 0) |
| 4588 | | emit_sub_r64_imm(DRCTOP, REG_RAX, CONSTVAL(rt)); // sub rax,<rt> |
| 4589 | | if (!ISCONST(rt) || CONSTVAL(rt) != 0) |
| 4590 | | oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception); |
| 4591 | | // jo generate_overflow_exception |
| 4592 | | if (RDREG != 0) |
| 4593 | | emit_mov_r64_r64(DRCTOP, X86REG(rd), REG_RAX); // mov <rd>,rax |
| 4594 | | } |
| 4595 | | else |
| 4596 | | { |
| 4597 | | /* if rD and rT aren't the same, it is pretty basic */ |
| 4598 | | if (X86REG(rd) != X86REG(rt)) |
| 4599 | | { |
| 4600 | | emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs> |
| 4601 | | if (!ISCONST(rt)) |
| 4602 | | emit_sub_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // sub <rd>,<rt> |
| 4603 | | else if (CONSTVAL(rt) != 0) |
| 4604 | | emit_sub_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // sub <rd>,<rt> |
| 4605 | | } |
| 4606 | | |
| 4607 | | /* otherwise, we negate rT and add rS */ |
| 4608 | | else |
| 4609 | | { |
| 4610 | | emit_neg_r64(DRCTOP, X86REG(rd)); // neg <rd> |
| 4611 | | if (!ISCONST(rs)) |
| 4612 | | emit_add_r64_r64(DRCTOP, X86REG(rd), X86REG(rs)); // add <rd>,<rs> |
| 4613 | | else if (CONSTVAL(rs) != 0) |
| 4614 | | emit_add_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs)); // add <rd>,<rs> |
| 4615 | | } |
| 4616 | | } |
| 4617 | | |
| 4618 | | /* only mark it dirty after the exception risk is over */ |
| 4619 | | compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DIRTY); |
| 4620 | | } |
| 4621 | | return TRUE; |
| 4622 | | } |
| 4623 | | |
| 4624 | | |
| 4625 | | /*------------------------------------------------- |
| 4626 | | compile_mult - compile a 32-bit multiply |
| 4627 | | instruction |
| 4628 | | |
| 4629 | | mult rS,rT |
| 4630 | | multu rS,rT |
| 4631 | | -------------------------------------------------*/ |
| 4632 | | |
| 4633 | | static int compile_mult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned) |
| 4634 | | { |
| 4635 | | UINT32 op = *desc->opptr.l; |
| 4636 | | mipsreg_state rs, rt, lo, hi; |
| 4637 | | |
| 4638 | | /* allocate source registers */ |
| 4639 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4640 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4641 | | |
| 4642 | | /* if both constant, we know the answer up front */ |
| 4643 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4644 | | { |
| 4645 | | UINT64 result = is_unsigned ? ((UINT64)CONSTVAL(rs) * (UINT64)CONSTVAL(rt)) : ((INT64)CONSTVAL(rs) * (INT64)CONSTVAL(rt)); |
| 4646 | | emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result); |
| 4647 | | emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)(result >> 32)); |
| 4648 | | } |
| 4649 | | |
| 4650 | | /* otherwise, handle generically */ |
| 4651 | | else |
| 4652 | | { |
| 4653 | | UINT8 mulreg = ISCONST(rt) ? REG_ECX : X86REG(rt); |
| 4654 | | |
| 4655 | | hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY); |
| 4656 | | lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY); |
| 4657 | | |
| 4658 | | emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs> |
| 4659 | | emit_load_register_value(drc, compiler, mulreg, rt); // mov <mulreg>,<rt> |
| 4660 | | if (is_unsigned) |
| 4661 | | emit_mul_r32(DRCTOP, mulreg); // mul <mulreg> |
| 4662 | | else |
| 4663 | | emit_imul_r32(DRCTOP, mulreg); // imul <mulreg> |
| 4664 | | emit_movsxd_r64_r32(DRCTOP, X86REG(hi), REG_EDX); // movsxd <hireg>,edx |
| 4665 | | emit_movsxd_r64_r32(DRCTOP, X86REG(lo), REG_EAX); // movsxd <loreg>,eax |
| 4666 | | } |
| 4667 | | return TRUE; |
| 4668 | | } |
| 4669 | | |
| 4670 | | |
| 4671 | | /*------------------------------------------------- |
| 4672 | | compile_dmult - compile a 64-bit multiply |
| 4673 | | instruction |
| 4674 | | |
| 4675 | | dmult rS,rT |
| 4676 | | dmultu rS,rT |
| 4677 | | -------------------------------------------------*/ |
| 4678 | | |
| 4679 | | static int compile_dmult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned) |
| 4680 | | { |
| 4681 | | UINT32 op = *desc->opptr.l; |
| 4682 | | mipsreg_state rs, rt, lo, hi; |
| 4683 | | |
| 4684 | | /* allocate source registers */ |
| 4685 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4686 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4687 | | |
| 4688 | | /* if both constant, we know the answer up front */ |
| 4689 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4690 | | { |
| 4691 | | UINT64 result = is_unsigned ? ((UINT64)CONSTVAL(rs) * (UINT64)CONSTVAL(rt)) : ((INT64)CONSTVAL(rs) * (INT64)CONSTVAL(rt)); |
| 4692 | | emit_set_constant_value(drc, compiler, desc, REG_LO, (INT64)result); |
| 4693 | | emit_set_constant_value(drc, compiler, desc, REG_HI, (INT64)(result >> 63)); |
| 4694 | | } |
| 4695 | | |
| 4696 | | /* otherwise, handle generically */ |
| 4697 | | else |
| 4698 | | { |
| 4699 | | UINT8 mulreg = ISCONST(rt) ? REG_ECX : X86REG(rt); |
| 4700 | | |
| 4701 | | hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY); |
| 4702 | | lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY); |
| 4703 | | |
| 4704 | | emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs> |
| 4705 | | emit_load_register_value(drc, compiler, mulreg, rt); // mov <mulreg>,<rt> |
| 4706 | | if (is_unsigned) |
| 4707 | | emit_mul_r64(DRCTOP, mulreg); // mul <mulreg> |
| 4708 | | else |
| 4709 | | emit_imul_r64(DRCTOP, mulreg); // imul <mulreg> |
| 4710 | | emit_mov_r64_r64(DRCTOP, X86REG(hi), REG_RDX); // mov <hi>,rdx |
| 4711 | | emit_mov_r64_r64(DRCTOP, X86REG(lo), REG_RAX); // mov <lo>,rax |
| 4712 | | } |
| 4713 | | return TRUE; |
| 4714 | | } |
| 4715 | | |
| 4716 | | |
| 4717 | | /*------------------------------------------------- |
| 4718 | | compile_div - compile a 32-bit divide |
| 4719 | | instruction |
| 4720 | | |
| 4721 | | div rS,rT |
| 4722 | | divu rS,rT |
| 4723 | | -------------------------------------------------*/ |
| 4724 | | |
| 4725 | | static int compile_div(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned) |
| 4726 | | { |
| 4727 | | UINT32 op = *desc->opptr.l; |
| 4728 | | mipsreg_state rs, rt, lo, hi; |
| 4729 | | |
| 4730 | | /* allocate source registers */ |
| 4731 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4732 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4733 | | |
| 4734 | | /* if rT is constant and 0, just skip */ |
| 4735 | | if (ISCONST(rt) && CONSTVAL(rt) == 0) |
| 4736 | | return TRUE; |
| 4737 | | |
| 4738 | | /* if both constant, we know the answer up front */ |
| 4739 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4740 | | { |
| 4741 | | UINT32 result = is_unsigned ? ((UINT32)CONSTVAL(rs) / (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) / (INT32)CONSTVAL(rt)); |
| 4742 | | UINT32 remainder = is_unsigned ? ((UINT32)CONSTVAL(rs) % (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) % (INT32)CONSTVAL(rt)); |
| 4743 | | |
| 4744 | | emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result); |
| 4745 | | emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)remainder); |
| 4746 | | } |
| 4747 | | |
| 4748 | | /* otherwise, handle generically */ |
| 4749 | | else |
| 4750 | | { |
| 4751 | | UINT8 divreg = ISCONST(rt) ? REG_ECX : X86REG(rt); |
| 4752 | | emit_link skip = { 0 }; |
| 4753 | | |
| 4754 | | hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY); |
| 4755 | | lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY); |
| 4756 | | |
| 4757 | | emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs> |
| 4758 | | emit_load_register_value(drc, compiler, divreg, rt); // mov <divreg>,<rt> |
| 4759 | | if (!ISCONST(rt)) |
| 4760 | | { |
| 4761 | | emit_test_r32_r32(DRCTOP, divreg, divreg); // test <divreg>,<divreg> |
| 4762 | | emit_jcc_short_link(DRCTOP, COND_Z, &skip); // jz skip |
| 4763 | | } |
| 4764 | | if (is_unsigned) |
| 4765 | | { |
| 4766 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 4767 | | emit_div_r32(DRCTOP, divreg); // div <divreg> |
| 4768 | | } |
| 4769 | | else |
| 4770 | | { |
| 4771 | | emit_cdq(DRCTOP); // cdq |
| 4772 | | emit_idiv_r32(DRCTOP, divreg); // idiv <divreg> |
| 4773 | | } |
| 4774 | | emit_movsxd_r64_r32(DRCTOP, X86REG(hi), REG_EDX); // movsxd <hi>,edx |
| 4775 | | emit_movsxd_r64_r32(DRCTOP, X86REG(lo), REG_EAX); // movsxd <lo>,eax |
| 4776 | | if (!ISCONST(rt)) |
| 4777 | | resolve_link(DRCTOP, &skip); // skip: |
| 4778 | | } |
| 4779 | | return TRUE; |
| 4780 | | } |
| 4781 | | |
| 4782 | | |
| 4783 | | /*------------------------------------------------- |
| 4784 | | compile_ddiv - compile a 64-bit divide |
| 4785 | | instruction |
| 4786 | | |
| 4787 | | ddiv rS,rT |
| 4788 | | ddivu rS,rT |
| 4789 | | -------------------------------------------------*/ |
| 4790 | | |
| 4791 | | static int compile_ddiv(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned) |
| 4792 | | { |
| 4793 | | UINT32 op = *desc->opptr.l; |
| 4794 | | mipsreg_state rs, rt, lo, hi; |
| 4795 | | |
| 4796 | | /* allocate source registers */ |
| 4797 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4798 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4799 | | |
| 4800 | | /* if rT is constant and 0, just skip */ |
| 4801 | | if (ISCONST(rt) && CONSTVAL(rt) == 0) |
| 4802 | | return TRUE; |
| 4803 | | |
| 4804 | | /* if both constant, we know the answer up front */ |
| 4805 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4806 | | { |
| 4807 | | UINT32 result = is_unsigned ? ((UINT32)CONSTVAL(rs) / (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) / (INT32)CONSTVAL(rt)); |
| 4808 | | UINT32 remainder = is_unsigned ? ((UINT32)CONSTVAL(rs) % (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) % (INT32)CONSTVAL(rt)); |
| 4809 | | |
| 4810 | | emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result); |
| 4811 | | emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)remainder); |
| 4812 | | } |
| 4813 | | |
| 4814 | | /* if one is a constant, load the constant into EAX and multiple from there */ |
| 4815 | | else |
| 4816 | | { |
| 4817 | | UINT8 divreg = ISCONST(rt) ? REG_ECX : X86REG(rt); |
| 4818 | | emit_link skip = { 0 }; |
| 4819 | | |
| 4820 | | hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY); |
| 4821 | | lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY); |
| 4822 | | |
| 4823 | | emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs> |
| 4824 | | emit_load_register_value(drc, compiler, divreg, rt); // mov <divreg>,<rt> |
| 4825 | | emit_test_r64_r64(DRCTOP, divreg, divreg); // test <divreg>,<divreg> |
| 4826 | | emit_jcc_short_link(DRCTOP, COND_Z, &skip); // jz skip |
| 4827 | | if (is_unsigned) |
| 4828 | | { |
| 4829 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 4830 | | emit_div_r64(DRCTOP, divreg); // div <divreg> |
| 4831 | | } |
| 4832 | | else |
| 4833 | | { |
| 4834 | | emit_cqo(DRCTOP); // cqo |
| 4835 | | emit_idiv_r64(DRCTOP, divreg); // idiv <divreg> |
| 4836 | | } |
| 4837 | | emit_mov_r64_r64(DRCTOP, X86REG(hi), REG_EDX); // mov <hi>,edx |
| 4838 | | emit_mov_r64_r64(DRCTOP, X86REG(lo), REG_EAX); // mov <loreg>,eax |
| 4839 | | resolve_link(DRCTOP, &skip); // skip: |
| 4840 | | } |
| 4841 | | return TRUE; |
| 4842 | | } |
| 4843 | | |
| 4844 | | |
| 4845 | | /*------------------------------------------------- |
| 4846 | | compile_logical - compile a logical |
| 4847 | | operation between two registers |
| 4848 | | |
| 4849 | | 0: and rD,rS,rT / and rT,rS,UIMM |
| 4850 | | 1: or rD,rS,rT / or rT,rS,UIMM |
| 4851 | | 2: xor rD,rS,rT / xor rT,rS,UIMM |
| 4852 | | 3: nor rD,rS,rT |
| 4853 | | -------------------------------------------------*/ |
| 4854 | | |
| 4855 | | static int compile_logical(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int operation, int immediate) |
| 4856 | | { |
| 4857 | | UINT32 op = *desc->opptr.l; |
| 4858 | | UINT8 destreg = immediate ? RTREG : RDREG; |
| 4859 | | mipsreg_state rd, rs, rt; |
| 4860 | | |
| 4861 | | assert(operation >= 0 && operation <= 3); |
| 4862 | | assert(!immediate || operation != 3); |
| 4863 | | |
| 4864 | | /* if the destination is r0, bail */ |
| 4865 | | if (destreg == 0) |
| 4866 | | return TRUE; |
| 4867 | | |
| 4868 | | /* allocate source registers */ |
| 4869 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4870 | | rt = immediate ? MAKE_CONST(UIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4871 | | |
| 4872 | | /* if both constant, we know the answer up front */ |
| 4873 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4874 | | { |
| 4875 | | UINT64 result = (operation == 0) ? (CONSTVAL(rs) & CONSTVAL(rt)) : (operation == 1) ? (CONSTVAL(rs) | CONSTVAL(rt)) : (operation == 2) ? (CONSTVAL(rs) ^ CONSTVAL(rt)) : ~(CONSTVAL(rs) | CONSTVAL(rt)); |
| 4876 | | emit_set_constant_value(drc, compiler, desc, destreg, result); |
| 4877 | | } |
| 4878 | | |
| 4879 | | /* an AND against 0 is constant as well */ |
| 4880 | | else if (operation == 0 && ISCONST(rt) && CONSTVAL(rt) == 0) |
| 4881 | | emit_set_constant_value(drc, compiler, desc, destreg, 0); |
| 4882 | | |
| 4883 | | /* else do the operation in code */ |
| 4884 | | else |
| 4885 | | { |
| 4886 | | rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST | ALLOC_DIRTY); |
| 4887 | | |
| 4888 | | /* if rD matches rT, or if rS is const and rT isn't, then swap rT and rS */ |
| 4889 | | if (X86REG(rd) == X86REG(rt) || (ISCONST(rs) && !ISCONST(rt))) |
| 4890 | | { |
| 4891 | | mipsreg_state temp = rs; |
| 4892 | | rs = rt; |
| 4893 | | rt = temp; |
| 4894 | | } |
| 4895 | | |
| 4896 | | /* load rS into rD */ |
| 4897 | | emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs> |
| 4898 | | |
| 4899 | | /* if rD does not match rT, we can work directly in rD */ |
| 4900 | | if (!ISCONST(rt)) |
| 4901 | | { |
| 4902 | | if (operation == 0) |
| 4903 | | emit_and_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // and <rd>,<rt> |
| 4904 | | else if (operation == 1) |
| 4905 | | emit_or_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // or <rd>,<rt> |
| 4906 | | else if (operation == 2) |
| 4907 | | emit_xor_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // xor <rd>,<rt> |
| 4908 | | else if (operation == 3) |
| 4909 | | { |
| 4910 | | emit_or_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // or <rd>,<rt> |
| 4911 | | emit_not_r64(DRCTOP, X86REG(rd)); // not <rd> |
| 4912 | | } |
| 4913 | | } |
| 4914 | | else |
| 4915 | | { |
| 4916 | | if (operation == 0) |
| 4917 | | emit_and_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // and <rd>,CONSTVAL(rt) |
| 4918 | | else if (operation == 1 && CONSTVAL(rt) != 0) |
| 4919 | | emit_or_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // or <rd>,CONSTVAL(rt) |
| 4920 | | else if (operation == 2 && CONSTVAL(rt) != 0) |
| 4921 | | emit_xor_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // xor <rd>,CONSTVAL(rt) |
| 4922 | | else if (operation == 3) |
| 4923 | | { |
| 4924 | | if (CONSTVAL(rt) != 0) |
| 4925 | | emit_or_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // or <rd>,CONSTVAL(rt) |
| 4926 | | emit_not_r64(DRCTOP, X86REG(rd)); // not <rd> |
| 4927 | | } |
| 4928 | | } |
| 4929 | | } |
| 4930 | | return TRUE; |
| 4931 | | } |
| 4932 | | |
| 4933 | | |
| 4934 | | /*------------------------------------------------- |
| 4935 | | compile_slt - compile a set if less |
| 4936 | | than btween two registers |
| 4937 | | |
| 4938 | | slti rD,rS,rT / slti rT,rS,SIMM |
| 4939 | | sltiu rD,rS,rT / sltiu rT,rS,SIMM |
| 4940 | | -------------------------------------------------*/ |
| 4941 | | |
| 4942 | | static int compile_slt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned, int immediate) |
| 4943 | | { |
| 4944 | | UINT32 op = *desc->opptr.l; |
| 4945 | | UINT8 destreg = immediate ? RTREG : RDREG; |
| 4946 | | mipsreg_state rd, rs, rt; |
| 4947 | | |
| 4948 | | /* if the destination is r0, bail */ |
| 4949 | | if (destreg == 0) |
| 4950 | | return TRUE; |
| 4951 | | |
| 4952 | | /* allocate source registers */ |
| 4953 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 4954 | | rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 4955 | | |
| 4956 | | /* if the source is constant, compute as constant */ |
| 4957 | | if (ISCONST(rs) && ISCONST(rt)) |
| 4958 | | { |
| 4959 | | INT64 result = is_unsigned ? ((UINT32)CONSTVAL(rs) < (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) < (INT32)CONSTVAL(rt)); |
| 4960 | | emit_set_constant_value(drc, compiler, desc, destreg, result); |
| 4961 | | } |
| 4962 | | |
| 4963 | | /* else do the operation in code */ |
| 4964 | | else |
| 4965 | | { |
| 4966 | | UINT8 rsreg = ISCONST(rs) ? REG_RAX : X86REG(rs); |
| 4967 | | |
| 4968 | | rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST | ALLOC_DIRTY); |
| 4969 | | |
| 4970 | | emit_load_register_value(drc, compiler, rsreg, rs); // mov <rsreg>,<rs> |
| 4971 | | if (ISCONST(rt)) |
| 4972 | | emit_cmp_r64_imm(DRCTOP, rsreg, CONSTVAL(rt)); // cmp <rsreg>,<rt> |
| 4973 | | else |
| 4974 | | emit_cmp_r64_r64(DRCTOP, rsreg, X86REG(rt)); // cmp <rsreg>,<rt> |
| 4975 | | emit_setcc_r8(DRCTOP, is_unsigned ? COND_B : COND_L, X86REG(rd)); // setb/l <rd> |
| 4976 | | emit_movzx_r32_r8(DRCTOP, X86REG(rd), X86REG(rd)); // movzx <rd>,<rd> |
| 4977 | | } |
| 4978 | | return TRUE; |
| 4979 | | } |
| 4980 | | |
| 4981 | | |
| 4982 | | /*------------------------------------------------- |
| 4983 | | compile_load - compile a memory load |
| 4984 | | instruction |
| 4985 | | |
| 4986 | | lb rT,SIMM(rS) |
| 4987 | | lbu rT,SIMM(rS) |
| 4988 | | lh rT,SIMM(rS) |
| 4989 | | lhu rT,SIMM(rS) |
| 4990 | | lw rT,SIMM(rS) |
| 4991 | | lwu rT,SIMM(rS) |
| 4992 | | ld rT,SIMM(rS) |
| 4993 | | -------------------------------------------------*/ |
| 4994 | | |
| 4995 | | static int compile_load(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, int is_unsigned) |
| 4996 | | { |
| 4997 | | UINT32 op = *desc->opptr.l; |
| 4998 | | mipsreg_state rs, rt; |
| 4999 | | int was_fixed = FALSE; |
| 5000 | | |
| 5001 | | /* allocate source registers */ |
| 5002 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5003 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST); |
| 5004 | | |
| 5005 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5006 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD) |
| 5007 | | { |
| 5008 | | UINT8 destreg = (RTREG == 0) ? REG_RAX : X86REG(rt); |
| 5009 | | |
| 5010 | | /* perform a fixed read if we can */ |
| 5011 | | if (size == 1) |
| 5012 | | was_fixed = emit_fixed_byte_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL); |
| 5013 | | else if (size == 2) |
| 5014 | | was_fixed = emit_fixed_half_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL); |
| 5015 | | else if (size == 4) |
| 5016 | | was_fixed = emit_fixed_word_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL, 0xffffffff); |
| 5017 | | else |
| 5018 | | was_fixed = emit_fixed_double_read(drc, compiler, desc, destreg, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff)); |
| 5019 | | } |
| 5020 | | |
| 5021 | | /* otherwise, we just need to call the appropriate subroutine */ |
| 5022 | | else |
| 5023 | | { |
| 5024 | | if (ISCONST(rs)) |
| 5025 | | emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL |
| 5026 | | else |
| 5027 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL] |
| 5028 | | if (size == 1 && is_unsigned) |
| 5029 | | emit_call(DRCTOP, mips3.drcdata->general.read_byte_unsigned); // call general.read_byte_unsigned |
| 5030 | | else if (size == 1 && !is_unsigned) |
| 5031 | | emit_call(DRCTOP, mips3.drcdata->general.read_byte_signed); // call general.read_byte_signed |
| 5032 | | else if (size == 2 && is_unsigned) |
| 5033 | | emit_call(DRCTOP, mips3.drcdata->general.read_half_unsigned); // call general.read_half_unsigned |
| 5034 | | else if (size == 2 && !is_unsigned) |
| 5035 | | emit_call(DRCTOP, mips3.drcdata->general.read_half_signed); // call general.read_half_signed |
| 5036 | | else if (size == 4 && is_unsigned) |
| 5037 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned |
| 5038 | | else if (size == 4 && !is_unsigned) |
| 5039 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_signed); // call general.read_word_signed |
| 5040 | | else |
| 5041 | | emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double |
| 5042 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 5043 | | if (RTREG != 0) |
| 5044 | | emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov <rt>,rax |
| 5045 | | } |
| 5046 | | |
| 5047 | | /* only mark dirty after the exception risk is over */ |
| 5048 | | compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DIRTY); |
| 5049 | | |
| 5050 | | /* update cycle counts */ |
| 5051 | | if (!was_fixed) |
| 5052 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5053 | | return TRUE; |
| 5054 | | } |
| 5055 | | |
| 5056 | | |
| 5057 | | /*------------------------------------------------- |
| 5058 | | compile_load_cop - compile a COP memory load |
| 5059 | | instruction |
| 5060 | | |
| 5061 | | lwc1 rT,SIMM(rs) |
| 5062 | | lwc2 rT,SIMM(rs) |
| 5063 | | ldc1 rT,SIMM(rs) |
| 5064 | | ldc2 rT,SIMM(rs) |
| 5065 | | -------------------------------------------------*/ |
| 5066 | | |
| 5067 | | static int compile_load_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest) |
| 5068 | | { |
| 5069 | | UINT32 op = *desc->opptr.l; |
| 5070 | | int was_fixed = FALSE; |
| 5071 | | mipsreg_state rs; |
| 5072 | | |
| 5073 | | /* allocate source registers */ |
| 5074 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5075 | | |
| 5076 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5077 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD) |
| 5078 | | { |
| 5079 | | /* perform a fixed read if we can */ |
| 5080 | | if (size == 4) |
| 5081 | | was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, CONSTVAL(rs) + SIMMVAL, 0xffffffff); |
| 5082 | | else |
| 5083 | | was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff)); |
| 5084 | | } |
| 5085 | | |
| 5086 | | /* otherwise, we just need to call the appropriate subroutine */ |
| 5087 | | else |
| 5088 | | { |
| 5089 | | if (ISCONST(rs)) |
| 5090 | | emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL |
| 5091 | | else |
| 5092 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL] |
| 5093 | | if (size == 4) |
| 5094 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned |
| 5095 | | else |
| 5096 | | emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double |
| 5097 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 5098 | | } |
| 5099 | | |
| 5100 | | /* complete the load by moving to the destination address */ |
| 5101 | | if (size == 4) |
| 5102 | | emit_mov_m32_r32(DRCTOP, MDRC(dest), REG_EAX); // mov [dest],eax |
| 5103 | | else |
| 5104 | | emit_mov_m64_r64(DRCTOP, MDRC(dest), REG_RAX); // mov [dest],rax |
| 5105 | | |
| 5106 | | /* update cycle counts */ |
| 5107 | | if (!was_fixed) |
| 5108 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5109 | | return TRUE; |
| 5110 | | } |
| 5111 | | |
| 5112 | | |
| 5113 | | /*------------------------------------------------- |
| 5114 | | compile_loadx_cop - compile a COP indexed |
| 5115 | | memory load instruction |
| 5116 | | |
| 5117 | | lwxc1 fD,rS,rT |
| 5118 | | ldxc1 fD,rS,rT |
| 5119 | | -------------------------------------------------*/ |
| 5120 | | |
| 5121 | | static int compile_loadx_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest) |
| 5122 | | { |
| 5123 | | UINT32 op = *desc->opptr.l; |
| 5124 | | int was_fixed = FALSE; |
| 5125 | | mipsreg_state rs, rt; |
| 5126 | | |
| 5127 | | /* allocate source registers */ |
| 5128 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5129 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 5130 | | |
| 5131 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5132 | | if (ISCONST(rs) && ISCONST(rt) && !DISABLE_FIXED_RAM_LOAD) |
| 5133 | | { |
| 5134 | | /* perform a fixed read if we can */ |
| 5135 | | if (size == 4) |
| 5136 | | was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, CONSTVAL(rs) + CONSTVAL(rt), 0xffffffff); |
| 5137 | | else |
| 5138 | | was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, CONSTVAL(rs) + CONSTVAL(rt), U64(0xffffffffffffffff)); |
| 5139 | | } |
| 5140 | | |
| 5141 | | /* otherwise, we just need to call the appropriate subroutine */ |
| 5142 | | else |
| 5143 | | { |
| 5144 | | if (ISCONST(rs) && ISCONST(rt)) |
| 5145 | | emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + CONSTVAL(rt)); // mov p1,<rs> + <rt> |
| 5146 | | else if (ISCONST(rs)) |
| 5147 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rt), CONSTVAL(rs))); // lea p1,[<rt> + <rs>] |
| 5148 | | else if (ISCONST(rt)) |
| 5149 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), CONSTVAL(rt))); // lea p1,[<rs> + <rt>] |
| 5150 | | else |
| 5151 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea p1,[<rs> + <rt>] |
| 5152 | | if (size == 4) |
| 5153 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned |
| 5154 | | else |
| 5155 | | emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double |
| 5156 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 5157 | | } |
| 5158 | | |
| 5159 | | /* complete the load by moving to the destination address */ |
| 5160 | | if (size == 4) |
| 5161 | | emit_mov_m32_r32(DRCTOP, MDRC(dest), REG_EAX); // mov [dest],eax |
| 5162 | | else |
| 5163 | | emit_mov_m64_r64(DRCTOP, MDRC(dest), REG_RAX); // mov [dest],rax |
| 5164 | | |
| 5165 | | /* update cycle counts */ |
| 5166 | | if (!was_fixed) |
| 5167 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5168 | | return TRUE; |
| 5169 | | } |
| 5170 | | |
| 5171 | | |
| 5172 | | /*------------------------------------------------- |
| 5173 | | compile_load_word_partial - compile a lwl/lwr |
| 5174 | | instruction |
| 5175 | | |
| 5176 | | lwl rT,SIMM(rS) |
| 5177 | | lwr rT,SIMM(rS) |
| 5178 | | -------------------------------------------------*/ |
| 5179 | | |
| 5180 | | static int compile_load_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right) |
| 5181 | | { |
| 5182 | | UINT32 op = *desc->opptr.l; |
| 5183 | | int was_fixed = FALSE; |
| 5184 | | mipsreg_state rs, rt; |
| 5185 | | |
| 5186 | | /* allocate source/dest registers */ |
| 5187 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5188 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY); |
| 5189 | | |
| 5190 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5191 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD) |
| 5192 | | { |
| 5193 | | INT32 addr = CONSTVAL(rs) + SIMMVAL; |
| 5194 | | int shift = (addr & 3) * 8; |
| 5195 | | |
| 5196 | | /* shift the opposite amount depending on right/left and endianness */ |
| 5197 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5198 | | shift ^= 0x18; |
| 5199 | | |
| 5200 | | /* read the double value into rax, handling exceptions */ |
| 5201 | | was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, addr, is_right ? ((UINT32)-1 << shift) : ((UINT32)-1 >> shift)); |
| 5202 | | |
| 5203 | | /* handle writing back the register */ |
| 5204 | | if (RTREG != 0) |
| 5205 | | { |
| 5206 | | UINT32 mask = is_right ? (~((UINT32)-1 >> shift)) : (~((UINT32)-1 << shift)); |
| 5207 | | |
| 5208 | | /* AND rT with the mask */ |
| 5209 | | emit_and_r32_imm(DRCTOP, X86REG(rt), mask); // and <rt>,mask |
| 5210 | | |
| 5211 | | /* shift and merge rax into the X86REG(rt) */ |
| 5212 | | if (!is_right) |
| 5213 | | emit_shl_r32_imm(DRCTOP, REG_EAX, shift); // shl eax,shift |
| 5214 | | else |
| 5215 | | emit_shr_r32_imm(DRCTOP, REG_EAX, shift); // shr eax,shift |
| 5216 | | emit_or_r32_r32(DRCTOP, X86REG(rt), REG_EAX); // or <rtdst>,eax |
| 5217 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rt), X86REG(rt)); // movsxd <rt>,<rt> |
| 5218 | | } |
| 5219 | | } |
| 5220 | | |
| 5221 | | /* otherwise, we need to compute everything at runtime */ |
| 5222 | | else |
| 5223 | | { |
| 5224 | | /* compute the address and mask values */ |
| 5225 | | if (ISCONST(rs)) |
| 5226 | | emit_mov_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rs) + SIMMVAL); // mov eax,<rs> + SIMMVAL |
| 5227 | | else |
| 5228 | | emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL] |
| 5229 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8] |
| 5230 | | emit_or_r32_imm(DRCTOP, REG_P2, -1); // or p2,-1 |
| 5231 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5232 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 |
| 5233 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 |
| 5234 | | if (!is_right) |
| 5235 | | emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl |
| 5236 | | else |
| 5237 | | emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl |
| 5238 | | emit_mov_m8_r8(DRCTOP, MBD(REG_RSP, SPOFFS_SAVECL), REG_CL); // mov [sp+savecl],cl |
| 5239 | | emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax |
| 5240 | | emit_call(DRCTOP, mips3.drcdata->general.read_word_masked); // call general.read_word_masked |
| 5241 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 5242 | | |
| 5243 | | /* handle writing back the register */ |
| 5244 | | if (RTREG != 0) |
| 5245 | | { |
| 5246 | | /* recompute the mask */ |
| 5247 | | emit_mov_r8_m8(DRCTOP, REG_CL, MBD(REG_RSP, SPOFFS_SAVECL)); // mov cl,[sp+savecl] |
| 5248 | | emit_or_r32_imm(DRCTOP, REG_P2, -1); // or p2,-1 |
| 5249 | | if (!is_right) |
| 5250 | | emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl |
| 5251 | | else |
| 5252 | | emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl |
| 5253 | | |
| 5254 | | /* apply the shifts and masks */ |
| 5255 | | emit_not_r32(DRCTOP, REG_P2); // not p2 |
| 5256 | | if (!is_right) |
| 5257 | | emit_shl_r32_cl(DRCTOP, REG_RAX); // shl rax,cl |
| 5258 | | else |
| 5259 | | emit_shr_r32_cl(DRCTOP, REG_RAX); // shr rax,cl |
| 5260 | | emit_and_r32_r32(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2 |
| 5261 | | emit_or_r32_r32(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax |
| 5262 | | emit_movsxd_r64_r32(DRCTOP, X86REG(rt), X86REG(rt)); // movsxd <rt>,<rt> |
| 5263 | | } |
| 5264 | | } |
| 5265 | | |
| 5266 | | /* update cycle counts */ |
| 5267 | | if (!was_fixed) |
| 5268 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5269 | | return TRUE; |
| 5270 | | } |
| 5271 | | |
| 5272 | | |
| 5273 | | /*------------------------------------------------- |
| 5274 | | compile_load_double_partial - compile a |
| 5275 | | ldl/ldr instruction |
| 5276 | | |
| 5277 | | ldl rT,SIMM(rS) |
| 5278 | | ldr rT,SIMM(rS) |
| 5279 | | -------------------------------------------------*/ |
| 5280 | | |
| 5281 | | static int compile_load_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right) |
| 5282 | | { |
| 5283 | | UINT32 op = *desc->opptr.l; |
| 5284 | | int was_fixed = FALSE; |
| 5285 | | mipsreg_state rs, rt; |
| 5286 | | |
| 5287 | | /* allocate source/dest registers */ |
| 5288 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5289 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY); |
| 5290 | | |
| 5291 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5292 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD) |
| 5293 | | { |
| 5294 | | INT32 addr = CONSTVAL(rs) + SIMMVAL; |
| 5295 | | int shift = (addr & 7) * 8; |
| 5296 | | |
| 5297 | | /* shift the opposite amount depending on right/left and endianness */ |
| 5298 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5299 | | shift ^= 0x38; |
| 5300 | | |
| 5301 | | /* read the double value into rax, handling exceptions */ |
| 5302 | | was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, addr, is_right ? ((UINT64)-1 << shift) : ((UINT64)-1 >> shift)); |
| 5303 | | |
| 5304 | | /* handle writing back the register */ |
| 5305 | | if (RTREG != 0) |
| 5306 | | { |
| 5307 | | UINT64 mask = is_right ? (~((UINT64)-1 >> shift)) : (~((UINT64)-1 << shift)); |
| 5308 | | |
| 5309 | | /* AND rT with the mask, using 32 bits if we can */ |
| 5310 | | if ((INT32)mask == (INT64)mask) |
| 5311 | | emit_and_r64_imm(DRCTOP, X86REG(rt), (INT32)mask); // and <rt>,mask |
| 5312 | | else |
| 5313 | | { |
| 5314 | | emit_mov_r64_imm(DRCTOP, REG_P2, mask); // mov p2,mask |
| 5315 | | emit_and_r64_r64(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2 |
| 5316 | | } |
| 5317 | | |
| 5318 | | /* shift and merge rax into the X86REG(rt) */ |
| 5319 | | if (!is_right) |
| 5320 | | emit_shl_r64_imm(DRCTOP, REG_RAX, shift); // shl rax,shift |
| 5321 | | else |
| 5322 | | emit_shr_r64_imm(DRCTOP, REG_RAX, shift); // shr rax,shift |
| 5323 | | emit_or_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax |
| 5324 | | } |
| 5325 | | } |
| 5326 | | |
| 5327 | | /* otherwise, we need to compute everything at runtime */ |
| 5328 | | else |
| 5329 | | { |
| 5330 | | /* compute the address and mask values */ |
| 5331 | | if (ISCONST(rs)) |
| 5332 | | emit_mov_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rs) + SIMMVAL); // mov eax,<rs> + SIMMVAL |
| 5333 | | else |
| 5334 | | emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL] |
| 5335 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8] |
| 5336 | | emit_or_r64_imm(DRCTOP, REG_P2, -1); // or p2,-1 |
| 5337 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5338 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x38); // xor ecx,0x38 |
| 5339 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 |
| 5340 | | if (!is_right) |
| 5341 | | emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl |
| 5342 | | else |
| 5343 | | emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl |
| 5344 | | emit_mov_m8_r8(DRCTOP, MBD(REG_RSP, SPOFFS_SAVECL), REG_CL); // mov [sp+savecl],cl |
| 5345 | | emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax |
| 5346 | | emit_call(DRCTOP, mips3.drcdata->general.read_double_masked); // call general.read_double_masked |
| 5347 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception); |
| 5348 | | |
| 5349 | | /* handle writing back the register */ |
| 5350 | | if (RTREG != 0) |
| 5351 | | { |
| 5352 | | /* recompute the mask */ |
| 5353 | | emit_mov_r8_m8(DRCTOP, REG_CL, MBD(REG_RSP, SPOFFS_SAVECL)); // mov cl,[sp+savecl] |
| 5354 | | emit_or_r64_imm(DRCTOP, REG_P2, -1); // or p2,-1 |
| 5355 | | if (!is_right) |
| 5356 | | emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl |
| 5357 | | else |
| 5358 | | emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl |
| 5359 | | |
| 5360 | | /* apply the shifts and masks */ |
| 5361 | | emit_not_r64(DRCTOP, REG_P2); // not p2 |
| 5362 | | if (!is_right) |
| 5363 | | emit_shl_r64_cl(DRCTOP, REG_RAX); // shl rax,cl |
| 5364 | | else |
| 5365 | | emit_shr_r64_cl(DRCTOP, REG_RAX); // shr rax,cl |
| 5366 | | emit_and_r64_r64(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2 |
| 5367 | | emit_or_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax |
| 5368 | | } |
| 5369 | | } |
| 5370 | | |
| 5371 | | /* update cycle counts */ |
| 5372 | | if (!was_fixed) |
| 5373 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5374 | | return TRUE; |
| 5375 | | } |
| 5376 | | |
| 5377 | | |
| 5378 | | /*------------------------------------------------- |
| 5379 | | compile_store - compile a memory store |
| 5380 | | instruction |
| 5381 | | |
| 5382 | | sb rT,SIMM(rS) |
| 5383 | | sh rT,SIMM(rS) |
| 5384 | | sw rT,SIMM(rS) |
| 5385 | | sd rT,SIMM(rS) |
| 5386 | | -------------------------------------------------*/ |
| 5387 | | |
| 5388 | | static int compile_store(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size) |
| 5389 | | { |
| 5390 | | UINT32 op = *desc->opptr.l; |
| 5391 | | int was_fixed = FALSE; |
| 5392 | | mipsreg_state rs, rt; |
| 5393 | | |
| 5394 | | /* allocate source registers */ |
| 5395 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5396 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 5397 | | |
| 5398 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5399 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE) |
| 5400 | | { |
| 5401 | | /* perform a fixed write if we can */ |
| 5402 | | if (size == 1) |
| 5403 | | was_fixed = emit_fixed_byte_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL); |
| 5404 | | else if (size == 2) |
| 5405 | | was_fixed = emit_fixed_half_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL); |
| 5406 | | else if (size == 4) |
| 5407 | | was_fixed = emit_fixed_word_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL, 0xffffffff); |
| 5408 | | else |
| 5409 | | was_fixed = emit_fixed_double_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff)); |
| 5410 | | } |
| 5411 | | |
| 5412 | | /* otherwise, we just need to call the appropriate subroutine */ |
| 5413 | | else |
| 5414 | | { |
| 5415 | | if (ISCONST(rs)) |
| 5416 | | emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL |
| 5417 | | else |
| 5418 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL] |
| 5419 | | emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt> |
| 5420 | | if (size == 1) |
| 5421 | | emit_call(DRCTOP, mips3.drcdata->general.write_byte); // call general.write_byte |
| 5422 | | else if (size == 2) |
| 5423 | | emit_call(DRCTOP, mips3.drcdata->general.write_half); // call general.write_half |
| 5424 | | else if (size == 4) |
| 5425 | | emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word |
| 5426 | | else if (size == 8) |
| 5427 | | emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double |
| 5428 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 5429 | | } |
| 5430 | | |
| 5431 | | /* update cycle counts */ |
| 5432 | | if (!was_fixed) |
| 5433 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5434 | | return TRUE; |
| 5435 | | } |
| 5436 | | |
| 5437 | | |
| 5438 | | /*------------------------------------------------- |
| 5439 | | compile_store_cop - compile a COP memory |
| 5440 | | store instruction |
| 5441 | | |
| 5442 | | swc1 rT,SIMM(rs) |
| 5443 | | swc2 rT,SIMM(rs) |
| 5444 | | sdc1 rT,SIMM(rs) |
| 5445 | | sdc2 rT,SIMM(rs) |
| 5446 | | -------------------------------------------------*/ |
| 5447 | | |
| 5448 | | static int compile_store_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src) |
| 5449 | | { |
| 5450 | | UINT32 op = *desc->opptr.l; |
| 5451 | | int was_fixed = FALSE; |
| 5452 | | mipsreg_state rs; |
| 5453 | | |
| 5454 | | /* allocate source registers */ |
| 5455 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5456 | | |
| 5457 | | /* load the value into P2 */ |
| 5458 | | if (size == 4) |
| 5459 | | emit_mov_r32_m32(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src] |
| 5460 | | else |
| 5461 | | emit_mov_r64_m64(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src] |
| 5462 | | |
| 5463 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5464 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE) |
| 5465 | | { |
| 5466 | | /* perform a fixed write if we can */ |
| 5467 | | if (size == 4) |
| 5468 | | was_fixed = emit_fixed_word_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + SIMMVAL, 0xffffffff); |
| 5469 | | else |
| 5470 | | was_fixed = emit_fixed_double_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff)); |
| 5471 | | } |
| 5472 | | |
| 5473 | | /* otherwise, we just need to call the appropriate subroutine */ |
| 5474 | | else |
| 5475 | | { |
| 5476 | | if (ISCONST(rs)) |
| 5477 | | emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL |
| 5478 | | else |
| 5479 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL] |
| 5480 | | if (size == 4) |
| 5481 | | emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word |
| 5482 | | else if (size == 8) |
| 5483 | | emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double |
| 5484 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 5485 | | } |
| 5486 | | |
| 5487 | | /* update cycle counts */ |
| 5488 | | if (!was_fixed) |
| 5489 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5490 | | return TRUE; |
| 5491 | | } |
| 5492 | | |
| 5493 | | |
| 5494 | | /*------------------------------------------------- |
| 5495 | | compile_storex_cop - compile a COP indexed |
| 5496 | | memory store instruction |
| 5497 | | |
| 5498 | | swxc1 fD,rS,rT |
| 5499 | | sdxc1 fD,rS,rT |
| 5500 | | -------------------------------------------------*/ |
| 5501 | | |
| 5502 | | static int compile_storex_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src) |
| 5503 | | { |
| 5504 | | UINT32 op = *desc->opptr.l; |
| 5505 | | int was_fixed = FALSE; |
| 5506 | | mipsreg_state rs, rt; |
| 5507 | | |
| 5508 | | /* allocate source registers */ |
| 5509 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5510 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 5511 | | |
| 5512 | | /* load the value into P2 */ |
| 5513 | | if (size == 4) |
| 5514 | | emit_mov_r32_m32(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src] |
| 5515 | | else |
| 5516 | | emit_mov_r64_m64(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src] |
| 5517 | | |
| 5518 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5519 | | if (ISCONST(rs) && ISCONST(rt) && !DISABLE_FIXED_RAM_STORE) |
| 5520 | | { |
| 5521 | | /* perform a fixed write if we can */ |
| 5522 | | if (size == 4) |
| 5523 | | was_fixed = emit_fixed_word_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + CONSTVAL(rt), 0xffffffff); |
| 5524 | | else |
| 5525 | | was_fixed = emit_fixed_double_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + CONSTVAL(rt), U64(0xffffffffffffffff)); |
| 5526 | | } |
| 5527 | | |
| 5528 | | /* otherwise, we just need to call the appropriate subroutine */ |
| 5529 | | else |
| 5530 | | { |
| 5531 | | if (ISCONST(rs) && ISCONST(rt)) |
| 5532 | | emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + CONSTVAL(rt)); // mov p1,<rs> + <rt> |
| 5533 | | else if (ISCONST(rs)) |
| 5534 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rt), CONSTVAL(rs))); // lea p1,[<rt> + <rs>] |
| 5535 | | else if (ISCONST(rt)) |
| 5536 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), CONSTVAL(rt))); // lea p1,[<rs> + <rt>] |
| 5537 | | else |
| 5538 | | emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea p1,[<rs> + <rt>] |
| 5539 | | if (size == 4) |
| 5540 | | emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word |
| 5541 | | else if (size == 8) |
| 5542 | | emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double |
| 5543 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 5544 | | } |
| 5545 | | |
| 5546 | | /* update cycle counts */ |
| 5547 | | if (!was_fixed) |
| 5548 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5549 | | return TRUE; |
| 5550 | | } |
| 5551 | | |
| 5552 | | |
| 5553 | | /*------------------------------------------------- |
| 5554 | | compile_store_word_partial - compile a swl/swr |
| 5555 | | instruction |
| 5556 | | |
| 5557 | | swl rT,SIMM(rS) |
| 5558 | | swr rT,SIMM(rS) |
| 5559 | | -------------------------------------------------*/ |
| 5560 | | |
| 5561 | | static int compile_store_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right) |
| 5562 | | { |
| 5563 | | UINT32 op = *desc->opptr.l; |
| 5564 | | int was_fixed = FALSE; |
| 5565 | | mipsreg_state rs, rt; |
| 5566 | | |
| 5567 | | /* allocate source registers */ |
| 5568 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5569 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 5570 | | |
| 5571 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5572 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE) |
| 5573 | | { |
| 5574 | | INT32 addr = CONSTVAL(rs) + SIMMVAL; |
| 5575 | | int shift = (addr & 3) * 8; |
| 5576 | | UINT32 mask; |
| 5577 | | |
| 5578 | | /* shift the opposite amount depending on right/left and endianness */ |
| 5579 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5580 | | shift ^= 0x18; |
| 5581 | | |
| 5582 | | /* if rT is not constant, load and shift it */ |
| 5583 | | if (!ISCONST(rt)) |
| 5584 | | { |
| 5585 | | emit_mov_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // mov eax,X86REG(rt) |
| 5586 | | emit_shr_r32_imm(DRCTOP, REG_EAX, shift); // shr eax,shift |
| 5587 | | rt = MAKE_DESTREG(REG_EAX); |
| 5588 | | } |
| 5589 | | |
| 5590 | | /* compute shifted value and mask */ |
| 5591 | | if (!is_right) |
| 5592 | | { |
| 5593 | | if (ISCONST(rt)) |
| 5594 | | rt = MAKE_CONST((UINT32)CONSTVAL(rt) >> shift); |
| 5595 | | mask = (UINT32)-1 >> shift; |
| 5596 | | } |
| 5597 | | else |
| 5598 | | { |
| 5599 | | if (ISCONST(rt)) |
| 5600 | | rt = MAKE_CONST((UINT32)CONSTVAL(rt) << shift); |
| 5601 | | mask = (UINT32)-1 << shift; |
| 5602 | | } |
| 5603 | | |
| 5604 | | /* perform a fixed write */ |
| 5605 | | was_fixed = emit_fixed_word_write(drc, compiler, desc, rt, addr & ~3, mask); |
| 5606 | | } |
| 5607 | | |
| 5608 | | /* otherwise, we need to compute everything at runtime */ |
| 5609 | | else |
| 5610 | | { |
| 5611 | | /* compute the address and mask values */ |
| 5612 | | emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL] |
| 5613 | | emit_or_r32_imm(DRCTOP, REG_P3, -1); // or p3,-1 |
| 5614 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8] |
| 5615 | | emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt> |
| 5616 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5617 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 |
| 5618 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 |
| 5619 | | if (!is_right) |
| 5620 | | { |
| 5621 | | emit_shr_r32_cl(DRCTOP, REG_P3); // shr p3,cl |
| 5622 | | emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl |
| 5623 | | } |
| 5624 | | else |
| 5625 | | { |
| 5626 | | emit_shl_r32_cl(DRCTOP, REG_P3); // shl p3,cl |
| 5627 | | emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl |
| 5628 | | } |
| 5629 | | emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax |
| 5630 | | |
| 5631 | | /* perform the write */ |
| 5632 | | emit_call(DRCTOP, mips3.drcdata->general.write_word_masked); // call general.write_word_masked |
| 5633 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 5634 | | } |
| 5635 | | |
| 5636 | | /* update cycle counts */ |
| 5637 | | if (!was_fixed) |
| 5638 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5639 | | return TRUE; |
| 5640 | | } |
| 5641 | | |
| 5642 | | |
| 5643 | | /*------------------------------------------------- |
| 5644 | | compile_store_double_partial - compile a |
| 5645 | | sdl/sdr instruction |
| 5646 | | |
| 5647 | | sdl rT,SIMM(rS) |
| 5648 | | sdr rT,SIMM(rS) |
| 5649 | | -------------------------------------------------*/ |
| 5650 | | |
| 5651 | | static int compile_store_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right) |
| 5652 | | { |
| 5653 | | UINT32 op = *desc->opptr.l; |
| 5654 | | int was_fixed = FALSE; |
| 5655 | | mipsreg_state rs, rt; |
| 5656 | | |
| 5657 | | /* allocate source registers */ |
| 5658 | | rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC); |
| 5659 | | rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC); |
| 5660 | | |
| 5661 | | /* if rS is constant, we know the address at compile time; this simplifies the code */ |
| 5662 | | if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE) |
| 5663 | | { |
| 5664 | | INT32 addr = CONSTVAL(rs) + SIMMVAL; |
| 5665 | | int shift = (addr & 7) * 8; |
| 5666 | | UINT64 mask; |
| 5667 | | |
| 5668 | | /* shift the opposite amount depending on right/left and endianness */ |
| 5669 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5670 | | shift ^= 0x38; |
| 5671 | | |
| 5672 | | /* if rT is not constant, load and shift it */ |
| 5673 | | if (!ISCONST(rt)) |
| 5674 | | { |
| 5675 | | emit_mov_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // mov rax,X86REG(rt) |
| 5676 | | emit_shr_r64_imm(DRCTOP, REG_RAX, shift); // shr rax,shift |
| 5677 | | rt = MAKE_DESTREG(REG_RAX); |
| 5678 | | } |
| 5679 | | |
| 5680 | | /* compute shifted value and mask */ |
| 5681 | | if (!is_right) |
| 5682 | | { |
| 5683 | | if (ISCONST(rt)) |
| 5684 | | rt = MAKE_CONST((UINT64)CONSTVAL(rt) >> shift); |
| 5685 | | mask = (UINT64)-1 >> shift; |
| 5686 | | } |
| 5687 | | else |
| 5688 | | { |
| 5689 | | if (ISCONST(rt)) |
| 5690 | | rt = MAKE_CONST((UINT64)CONSTVAL(rt) << shift); |
| 5691 | | mask = (UINT64)-1 << shift; |
| 5692 | | } |
| 5693 | | |
| 5694 | | /* perform a fixed write */ |
| 5695 | | was_fixed = emit_fixed_double_write(drc, compiler, desc, rt, addr & ~7, mask); |
| 5696 | | } |
| 5697 | | |
| 5698 | | /* otherwise, we need to compute everything at runtime */ |
| 5699 | | else |
| 5700 | | { |
| 5701 | | /* compute the address and mask values */ |
| 5702 | | emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL] |
| 5703 | | emit_or_r64_imm(DRCTOP, REG_P3, -1); // or p3,-1 |
| 5704 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8] |
| 5705 | | emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt> |
| 5706 | | if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right)) |
| 5707 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x38); // xor ecx,0x38 |
| 5708 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 |
| 5709 | | if (!is_right) |
| 5710 | | { |
| 5711 | | emit_shr_r64_cl(DRCTOP, REG_P3); // shr p3,cl |
| 5712 | | emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl |
| 5713 | | } |
| 5714 | | else |
| 5715 | | { |
| 5716 | | emit_shl_r64_cl(DRCTOP, REG_P3); // shl p3,cl |
| 5717 | | emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl |
| 5718 | | } |
| 5719 | | emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax |
| 5720 | | |
| 5721 | | /* perform the write */ |
| 5722 | | emit_call(DRCTOP, mips3.drcdata->general.write_double_masked); // call general.write_double_masked |
| 5723 | | oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception); |
| 5724 | | } |
| 5725 | | |
| 5726 | | /* update cycle counts */ |
| 5727 | | if (!was_fixed) |
| 5728 | | emit_update_cycles_pc_and_flush(drc, compiler, desc, 0); |
| 5729 | | return TRUE; |
| 5730 | | } |
src/emu/cpu/mips/mdrcold.c
| r2821 | r2822 | |
| 1 | | |
| 2 | | |
| 3 | | /*************************************************************************** |
| 4 | | CONFIGURATION |
| 5 | | ***************************************************************************/ |
| 6 | | |
| 7 | | #define STRIP_NOPS 1 /* 1 is faster */ |
| 8 | | #define USE_SSE 0 /* can't tell any speed difference here */ |
| 9 | | |
| 10 | | |
| 11 | | |
| 12 | | /*************************************************************************** |
| 13 | | CONSTANTS |
| 14 | | ***************************************************************************/ |
| 15 | | |
| 16 | | #define MAX_INSTRUCTIONS ((512 + 128) / 4) |
| 17 | | |
| 18 | | /* recompiler flags */ |
| 19 | | #define RECOMPILE_UNIMPLEMENTED 0x0000 |
| 20 | | #define RECOMPILE_SUCCESSFUL 0x0001 |
| 21 | | #define RECOMPILE_SUCCESSFUL_CP(c,p) (RECOMPILE_SUCCESSFUL | (((c) & 0xfff) << 8) | (((p) & 0xfff) << 20)) |
| 22 | | #define RECOMPILE_MAY_CAUSE_EXCEPTION 0x0002 |
| 23 | | #define RECOMPILE_END_OF_STRING 0x0004 |
| 24 | | #define RECOMPILE_CHECK_INTERRUPTS 0x0008 |
| 25 | | #define RECOMPILE_CHECK_SW_INTERRUPTS 0x0010 |
| 26 | | #define RECOMPILE_ADD_DISPATCH 0x0020 |
| 27 | | |
| 28 | | /* append_readwrite flags */ |
| 29 | | #define ARW_READ 0x0000 |
| 30 | | #define ARW_WRITE 0x0001 |
| 31 | | #define ARW_UNSIGNED 0x0000 |
| 32 | | #define ARW_SIGNED 0x0002 |
| 33 | | #define ARW_MASKED 0x0004 |
| 34 | | |
| 35 | | |
| 36 | | |
| 37 | | /*************************************************************************** |
| 38 | | MACROS |
| 39 | | ***************************************************************************/ |
| 40 | | |
| 41 | | #define REGDISP(reg) (offsetof(mips3_state, r[reg]) - offsetof(mips3_state, r[17])) |
| 42 | | #define REGADDR(reg) MBD(REG_ESI, REGDISP(reg)) |
| 43 | | #define REGADDRLO(reg) MBD(REG_ESI, REGDISP(reg)) |
| 44 | | #define REGADDRHI(reg) MBD(REG_ESI, REGDISP(reg)+4) |
| 45 | | |
| 46 | | #define HIADDR REGADDR(REG_HI) |
| 47 | | #define HIADDRLO REGADDRLO(REG_HI) |
| 48 | | #define HIADDRHI REGADDRHI(REG_HI) |
| 49 | | |
| 50 | | #define LOADDR REGADDR(REG_LO) |
| 51 | | #define LOADDRLO REGADDRLO(REG_LO) |
| 52 | | #define LOADDRHI REGADDRHI(REG_LO) |
| 53 | | |
| 54 | | #define CPR0ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg]) |
| 55 | | #define CPR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg]) |
| 56 | | #define CPR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg] + 4) |
| 57 | | |
| 58 | | #define CCR0ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg]) |
| 59 | | #define CCR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg]) |
| 60 | | #define CCR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg] + 4) |
| 61 | | |
| 62 | | #define CPR1ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg]) |
| 63 | | #define CPR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg]) |
| 64 | | #define CPR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg] + 4) |
| 65 | | |
| 66 | | #define CCR1ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg]) |
| 67 | | #define CCR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg]) |
| 68 | | #define CCR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg] + 4) |
| 69 | | |
| 70 | | #define CPR2ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg]) |
| 71 | | #define CPR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg]) |
| 72 | | #define CPR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg] + 4) |
| 73 | | |
| 74 | | #define CCR2ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg]) |
| 75 | | #define CCR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg]) |
| 76 | | #define CCR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg] + 4) |
| 77 | | |
| 78 | | #define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg]) |
| 79 | | #define FPR32ADDR(reg) MABS(FPR32(reg)) |
| 80 | | #define FPR32ADDRLO(reg) MABS(FPR32(reg)) |
| 81 | | #define FPR32ADDRHI(reg) MABS((UINT8 *)FPR32(reg) + 4) |
| 82 | | |
| 83 | | #define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg]) |
| 84 | | #define FPR64ADDR(reg) MABS(FPR64(reg)) |
| 85 | | #define FPR64ADDR(reg) MABS(FPR64(reg)) |
| 86 | | #define FPR64ADDRLO(reg) MABS(FPR64(reg)) |
| 87 | | #define FPR64ADDRHI(reg) MABS((UINT8 *)FPR64(reg) + 4) |
| 88 | | |
| 89 | | #define CF1ADDR(which) MABS(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)]) |
| 90 | | |
| 91 | | #define ICOUNTADDR MABS(&mips3.core->icount) |
| 92 | | |
| 93 | | |
| 94 | | /*************************************************************************** |
| 95 | | USEFUL PRIMITIVES |
| 96 | | ***************************************************************************/ |
| 97 | | |
| 98 | | INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 reghi, UINT8 reglo, DECLARE_MEMPARAMS) |
| 99 | | { |
| 100 | | emit_mov_r32_m32(emitptr, reglo, MEMPARAMS); |
| 101 | | emit_mov_r32_m32(emitptr, reghi, base, index, scale, disp+4); |
| 102 | | } |
| 103 | | |
| 104 | | INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 reghi, UINT8 reglo) |
| 105 | | { |
| 106 | | emit_mov_m32_r32(emitptr, MEMPARAMS, reglo); |
| 107 | | emit_mov_m32_r32(emitptr, base, index, scale, disp+4, reghi); |
| 108 | | } |
| 109 | | |
| 110 | | INLINE void emit_mov_m64_imm32(x86code **emitptr, DECLARE_MEMPARAMS, INT32 imm) |
| 111 | | { |
| 112 | | emit_mov_m32_imm(emitptr, MEMPARAMS, imm); |
| 113 | | emit_mov_m32_imm(emitptr, base, index, scale, disp+4, (INT32)imm >> 31); |
| 114 | | } |
| 115 | | |
| 116 | | INLINE void emit_zero_m64(x86code **emitptr, DECLARE_MEMPARAMS) |
| 117 | | { |
| 118 | | if (USE_SSE) |
| 119 | | { |
| 120 | | emit_xorpd_r128_r128(emitptr, REG_XMM0, REG_XMM0); |
| 121 | | emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0); |
| 122 | | } |
| 123 | | else |
| 124 | | emit_mov_m64_imm32(emitptr, MEMPARAMS, 0); |
| 125 | | } |
| 126 | | |
| 127 | | INLINE void emit_mov_m64_m64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 base2, UINT8 index2, UINT8 scale2, INT32 disp2) |
| 128 | | { |
| 129 | | if (USE_SSE) |
| 130 | | { |
| 131 | | emit_movsd_r128_m64(emitptr, REG_XMM0, base2, index2, scale2, disp2); |
| 132 | | emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0); |
| 133 | | } |
| 134 | | else |
| 135 | | { |
| 136 | | emit_mov_r64_m64(emitptr, REG_EDX, REG_EAX, base2, index2, scale2, disp2); |
| 137 | | emit_mov_m64_r64(emitptr, MEMPARAMS, REG_EDX, REG_EAX); |
| 138 | | } |
| 139 | | } |
| 140 | | |
| 141 | | #define emit_save_pc_before_call(e) \ |
| 142 | | do { \ |
| 143 | | if (mips3.drcoptions & MIPS3DRC_FLUSH_PC) \ |
| 144 | | emit_mov_m32_r32(e, MABS(drc->pcptr), REG_EDI); \ |
| 145 | | } while (0) |
| 146 | | |
| 147 | | |
| 148 | | |
| 149 | | |
| 150 | | /*************************************************************************** |
| 151 | | TYPEDEFS |
| 152 | | ***************************************************************************/ |
| 153 | | |
| 154 | | struct _mips3drc_data |
| 155 | | { |
| 156 | | x86code * generate_interrupt_exception; |
| 157 | | x86code * generate_cop_exception; |
| 158 | | x86code * generate_overflow_exception; |
| 159 | | x86code * generate_invalidop_exception; |
| 160 | | x86code * generate_syscall_exception; |
| 161 | | x86code * generate_break_exception; |
| 162 | | x86code * generate_trap_exception; |
| 163 | | x86code * generate_tlbload_exception; |
| 164 | | x86code * generate_tlbstore_exception; |
| 165 | | x86code * handle_pc_tlb_mismatch; |
| 166 | | x86code * read_and_translate_byte_signed; |
| 167 | | x86code * read_and_translate_byte_unsigned; |
| 168 | | x86code * read_and_translate_half_signed; |
| 169 | | x86code * read_and_translate_half_unsigned; |
| 170 | | x86code * read_and_translate_word; |
| 171 | | x86code * read_and_translate_word_masked; |
| 172 | | x86code * read_and_translate_double; |
| 173 | | x86code * read_and_translate_double_masked; |
| 174 | | x86code * write_and_translate_byte; |
| 175 | | x86code * write_and_translate_half; |
| 176 | | x86code * write_and_translate_word; |
| 177 | | x86code * write_and_translate_word_masked; |
| 178 | | x86code * write_and_translate_double; |
| 179 | | x86code * write_and_translate_double_masked; |
| 180 | | }; |
| 181 | | |
| 182 | | |
| 183 | | |
| 184 | | /*************************************************************************** |
| 185 | | FUNCTION PROTOTYPES |
| 186 | | ***************************************************************************/ |
| 187 | | |
| 188 | | static void drc_reset_callback(drc_core *drc); |
| 189 | | static void drc_recompile_callback(drc_core *drc); |
| 190 | | static void drc_entrygen_callback(drc_core *drc); |
| 191 | | |
| 192 | | static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc); |
| 193 | | |
| 194 | | static void append_generate_exception(drc_core *drc, UINT8 exception); |
| 195 | | static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags); |
| 196 | | static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target); |
| 197 | | static void append_update_cycle_counting(drc_core *drc); |
| 198 | | static void append_check_interrupts(drc_core *drc, int inline_generate); |
| 199 | | static void append_check_sw_interrupts(drc_core *drc, int inline_generate); |
| 200 | | |
| 201 | | static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc); |
| 202 | | static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op); |
| 203 | | static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op); |
| 204 | | |
| 205 | | static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op); |
| 206 | | static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op); |
| 207 | | static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op); |
| 208 | | |
| 209 | | |
| 210 | | |
| 211 | | /*************************************************************************** |
| 212 | | PRIVATE GLOBAL VARIABLES |
| 213 | | ***************************************************************************/ |
| 214 | | |
| 215 | | static UINT64 dmult_temp1; |
| 216 | | static UINT64 dmult_temp2; |
| 217 | | static UINT32 jr_temp; |
| 218 | | |
| 219 | | static UINT8 in_delay_slot = 0; |
| 220 | | |
| 221 | | |
| 222 | | |
| 223 | | /*************************************************************************** |
| 224 | | CORE RECOMPILER SYSTEMS |
| 225 | | ***************************************************************************/ |
| 226 | | |
| 227 | | /*------------------------------------------------- |
| 228 | | mips3drc_init - initialize the drc-specific |
| 229 | | state |
| 230 | | -------------------------------------------------*/ |
| 231 | | |
| 232 | | static void mips3drc_init(void) |
| 233 | | { |
| 234 | | drc_config drconfig; |
| 235 | | |
| 236 | | /* fill in the config */ |
| 237 | | memset(&drconfig, 0, sizeof(drconfig)); |
| 238 | | drconfig.cache_base = mips3.cache; |
| 239 | | drconfig.cache_size = CACHE_SIZE; |
| 240 | | drconfig.max_instructions = MAX_INSTRUCTIONS; |
| 241 | | drconfig.address_bits = 32; |
| 242 | | drconfig.lsbs_to_ignore = 2; |
| 243 | | drconfig.uses_fp = 1; |
| 244 | | drconfig.uses_sse = USE_SSE; |
| 245 | | drconfig.pc_in_memory = 0; |
| 246 | | drconfig.icount_in_memory = 0; |
| 247 | | drconfig.pcptr = (UINT32 *)&mips3.core->pc; |
| 248 | | drconfig.icountptr = (UINT32 *)&mips3.core->icount; |
| 249 | | drconfig.esiptr = NULL; |
| 250 | | drconfig.cb_reset = drc_reset_callback; |
| 251 | | drconfig.cb_recompile = drc_recompile_callback; |
| 252 | | drconfig.cb_entrygen = drc_entrygen_callback; |
| 253 | | |
| 254 | | /* initialize the compiler */ |
| 255 | | mips3.drc = drc_init(cpu_getactivecpu(), &drconfig); |
| 256 | | mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS; |
| 257 | | |
| 258 | | /* allocate our data out of the cache */ |
| 259 | | mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata)); |
| 260 | | memset(mips3.drcdata, 0, sizeof(*mips3.drcdata)); |
| 261 | | } |
| 262 | | |
| 263 | | |
| 264 | | /*------------------------------------------------- |
| 265 | | mips3drc_exit - clean up the drc-specific |
| 266 | | state |
| 267 | | -------------------------------------------------*/ |
| 268 | | |
| 269 | | static void mips3drc_exit(void) |
| 270 | | { |
| 271 | | drc_exit(mips3.drc); |
| 272 | | } |
| 273 | | |
| 274 | | |
| 275 | | |
| 276 | | /*************************************************************************** |
| 277 | | RECOMPILER CALLBACKS |
| 278 | | ***************************************************************************/ |
| 279 | | |
| 280 | | /*------------------------------------------------------------------ |
| 281 | | drc_reset_callback |
| 282 | | ------------------------------------------------------------------*/ |
| 283 | | |
| 284 | | static void drc_reset_callback(drc_core *drc) |
| 285 | | { |
| 286 | | if (LOG_CODE) |
| 287 | | { |
| 288 | | x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->out_of_cycles); |
| 289 | | x86log_disasm_code_range(mips3.log, "out_of_cycles:", drc->out_of_cycles, drc->recompile); |
| 290 | | x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch); |
| 291 | | x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush); |
| 292 | | x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top); |
| 293 | | } |
| 294 | | |
| 295 | | mips3.drcdata->generate_interrupt_exception = drc->cache_top; |
| 296 | | append_generate_exception(drc, EXCEPTION_INTERRUPT); |
| 297 | | if (LOG_CODE) |
| 298 | | x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top); |
| 299 | | |
| 300 | | mips3.drcdata->generate_cop_exception = drc->cache_top; |
| 301 | | append_generate_exception(drc, EXCEPTION_BADCOP); |
| 302 | | if (LOG_CODE) |
| 303 | | x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top); |
| 304 | | |
| 305 | | mips3.drcdata->generate_overflow_exception = drc->cache_top; |
| 306 | | append_generate_exception(drc, EXCEPTION_OVERFLOW); |
| 307 | | if (LOG_CODE) |
| 308 | | x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top); |
| 309 | | |
| 310 | | mips3.drcdata->generate_invalidop_exception = drc->cache_top; |
| 311 | | append_generate_exception(drc, EXCEPTION_INVALIDOP); |
| 312 | | if (LOG_CODE) |
| 313 | | x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top); |
| 314 | | |
| 315 | | mips3.drcdata->generate_syscall_exception = drc->cache_top; |
| 316 | | append_generate_exception(drc, EXCEPTION_SYSCALL); |
| 317 | | if (LOG_CODE) |
| 318 | | x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top); |
| 319 | | |
| 320 | | mips3.drcdata->generate_break_exception = drc->cache_top; |
| 321 | | append_generate_exception(drc, EXCEPTION_BREAK); |
| 322 | | if (LOG_CODE) |
| 323 | | x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top); |
| 324 | | |
| 325 | | mips3.drcdata->generate_trap_exception = drc->cache_top; |
| 326 | | append_generate_exception(drc, EXCEPTION_TRAP); |
| 327 | | if (LOG_CODE) |
| 328 | | x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top); |
| 329 | | |
| 330 | | mips3.drcdata->generate_tlbload_exception = drc->cache_top; |
| 331 | | append_generate_exception(drc, EXCEPTION_TLBLOAD); |
| 332 | | if (LOG_CODE) |
| 333 | | x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top); |
| 334 | | |
| 335 | | mips3.drcdata->generate_tlbstore_exception = drc->cache_top; |
| 336 | | append_generate_exception(drc, EXCEPTION_TLBSTORE); |
| 337 | | if (LOG_CODE) |
| 338 | | x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top); |
| 339 | | |
| 340 | | mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top; |
| 341 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi |
| 342 | | emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12 |
| 343 | | emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EAX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[eax*4] |
| 344 | | emit_test_r32_imm(DRCTOP, REG_EBX, 2); // test ebx,2 |
| 345 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi |
| 346 | | emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception |
| 347 | | emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI); // mov [pcptr],edi |
| 348 | | emit_jmp(DRCTOP, drc->recompile); // jmp recompile |
| 349 | | if (LOG_CODE) |
| 350 | | x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top); |
| 351 | | |
| 352 | | mips3.drcdata->read_and_translate_byte_signed = drc->cache_top; |
| 353 | | append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED); |
| 354 | | if (LOG_CODE) |
| 355 | | x86log_disasm_code_range(mips3.log, "read_and_translate_byte_signed:", mips3.drcdata->read_and_translate_byte_signed, drc->cache_top); |
| 356 | | |
| 357 | | mips3.drcdata->read_and_translate_byte_unsigned = drc->cache_top; |
| 358 | | append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED); |
| 359 | | if (LOG_CODE) |
| 360 | | x86log_disasm_code_range(mips3.log, "read_and_translate_byte_unsigned:", mips3.drcdata->read_and_translate_byte_unsigned, drc->cache_top); |
| 361 | | |
| 362 | | mips3.drcdata->read_and_translate_half_signed = drc->cache_top; |
| 363 | | append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED); |
| 364 | | if (LOG_CODE) |
| 365 | | x86log_disasm_code_range(mips3.log, "read_and_translate_half_signed:", mips3.drcdata->read_and_translate_half_signed, drc->cache_top); |
| 366 | | |
| 367 | | mips3.drcdata->read_and_translate_half_unsigned = drc->cache_top; |
| 368 | | append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED); |
| 369 | | if (LOG_CODE) |
| 370 | | x86log_disasm_code_range(mips3.log, "read_and_translate_half_unsigned:", mips3.drcdata->read_and_translate_half_unsigned, drc->cache_top); |
| 371 | | |
| 372 | | mips3.drcdata->read_and_translate_word = drc->cache_top; |
| 373 | | append_readwrite_and_translate(drc, 4, ARW_READ); |
| 374 | | if (LOG_CODE) |
| 375 | | x86log_disasm_code_range(mips3.log, "read_and_translate_word:", mips3.drcdata->read_and_translate_word, drc->cache_top); |
| 376 | | |
| 377 | | mips3.drcdata->read_and_translate_word_masked = drc->cache_top; |
| 378 | | append_readwrite_and_translate(drc, 4, ARW_READ | ARW_MASKED); |
| 379 | | if (LOG_CODE) |
| 380 | | x86log_disasm_code_range(mips3.log, "read_and_translate_word_masked:", mips3.drcdata->read_and_translate_word_masked, drc->cache_top); |
| 381 | | |
| 382 | | mips3.drcdata->read_and_translate_double = drc->cache_top; |
| 383 | | append_readwrite_and_translate(drc, 8, ARW_READ); |
| 384 | | if (LOG_CODE) |
| 385 | | x86log_disasm_code_range(mips3.log, "read_and_translate_double:", mips3.drcdata->read_and_translate_double, drc->cache_top); |
| 386 | | |
| 387 | | mips3.drcdata->read_and_translate_double_masked = drc->cache_top; |
| 388 | | append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED); |
| 389 | | if (LOG_CODE) |
| 390 | | x86log_disasm_code_range(mips3.log, "read_and_translate_double_masked:", mips3.drcdata->read_and_translate_double_masked, drc->cache_top); |
| 391 | | |
| 392 | | mips3.drcdata->write_and_translate_byte = drc->cache_top; |
| 393 | | append_readwrite_and_translate(drc, 1, ARW_WRITE); |
| 394 | | if (LOG_CODE) |
| 395 | | x86log_disasm_code_range(mips3.log, "write_and_translate_byte:", mips3.drcdata->write_and_translate_byte, drc->cache_top); |
| 396 | | |
| 397 | | mips3.drcdata->write_and_translate_half = drc->cache_top; |
| 398 | | append_readwrite_and_translate(drc, 2, ARW_WRITE); |
| 399 | | if (LOG_CODE) |
| 400 | | x86log_disasm_code_range(mips3.log, "write_and_translate_half:", mips3.drcdata->write_and_translate_half, drc->cache_top); |
| 401 | | |
| 402 | | mips3.drcdata->write_and_translate_word = drc->cache_top; |
| 403 | | append_readwrite_and_translate(drc, 4, ARW_WRITE); |
| 404 | | if (LOG_CODE) |
| 405 | | x86log_disasm_code_range(mips3.log, "write_and_translate_word:", mips3.drcdata->write_and_translate_word, drc->cache_top); |
| 406 | | |
| 407 | | mips3.drcdata->write_and_translate_word_masked = drc->cache_top; |
| 408 | | append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED); |
| 409 | | if (LOG_CODE) |
| 410 | | x86log_disasm_code_range(mips3.log, "write_and_translate_word_masked:", mips3.drcdata->write_and_translate_word_masked, drc->cache_top); |
| 411 | | |
| 412 | | mips3.drcdata->write_and_translate_double = drc->cache_top; |
| 413 | | append_readwrite_and_translate(drc, 8, ARW_WRITE); |
| 414 | | if (LOG_CODE) |
| 415 | | x86log_disasm_code_range(mips3.log, "write_and_translate_double:", mips3.drcdata->write_and_translate_double, drc->cache_top); |
| 416 | | |
| 417 | | mips3.drcdata->write_and_translate_double_masked = drc->cache_top; |
| 418 | | append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED); |
| 419 | | if (LOG_CODE) |
| 420 | | x86log_disasm_code_range(mips3.log, "write_and_translate_double_masked:", mips3.drcdata->write_and_translate_double_masked, drc->cache_top); |
| 421 | | } |
| 422 | | |
| 423 | | |
| 424 | | /*------------------------------------------------------------------ |
| 425 | | drc_recompile_callback |
| 426 | | ------------------------------------------------------------------*/ |
| 427 | | |
| 428 | | static void drc_recompile_callback(drc_core *drc) |
| 429 | | { |
| 430 | | int remaining = MAX_INSTRUCTIONS; |
| 431 | | x86code *start = drc->cache_top; |
| 432 | | UINT32 pc = mips3.core->pc; |
| 433 | | UINT32 lastpc = pc; |
| 434 | | UINT32 physpc; |
| 435 | | |
| 436 | | (void)start; |
| 437 | | |
| 438 | | /* begin the sequence */ |
| 439 | | drc_begin_sequence(drc, pc); |
| 440 | | |
| 441 | | /* make sure our FR flag matches the last time */ |
| 442 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_FR); // test [COP0_Status],SR_FR |
| 443 | | emit_jcc(DRCTOP, IS_FR0 ? COND_NZ : COND_Z, drc->recompile); // jnz/z recompile |
| 444 | | |
| 445 | | /* ensure that we are still mapped */ |
| 446 | | append_tlb_verify(drc, pc, mips3.drcdata->handle_pc_tlb_mismatch); |
| 447 | | physpc = pc; |
| 448 | | if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc)) |
| 449 | | { |
| 450 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi |
| 451 | | emit_jmp(DRCTOP, mips3.drcdata->generate_tlbload_exception); // jmp tlbload_exception |
| 452 | | goto exit; |
| 453 | | } |
| 454 | | change_pc(physpc); |
| 455 | | |
| 456 | | /* loose verification case: one verification here only */ |
| 457 | | if (!(mips3.drcoptions & MIPS3DRC_STRICT_VERIFY)) |
| 458 | | drc_append_verify_code(drc, cpu_opptr(physpc), 4); |
| 459 | | |
| 460 | | /* loop until we hit an unconditional branch */ |
| 461 | | while (--remaining != 0) |
| 462 | | { |
| 463 | | UINT32 result; |
| 464 | | |
| 465 | | /* if we crossed a page boundary, check the mapping */ |
| 466 | | if ((pc ^ lastpc) & 0xfffff000) |
| 467 | | { |
| 468 | | physpc = pc; |
| 469 | | if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc)) |
| 470 | | break; |
| 471 | | append_tlb_verify(drc, pc, drc->dispatch); |
| 472 | | change_pc(physpc); |
| 473 | | } |
| 474 | | |
| 475 | | /* compile one instruction */ |
| 476 | | physpc = (physpc & 0xfffff000) | (pc & 0xfff); |
| 477 | | result = compile_one(drc, pc, physpc); |
| 478 | | lastpc = pc; |
| 479 | | pc += (INT32)result >> 20; |
| 480 | | if (result & RECOMPILE_END_OF_STRING) |
| 481 | | break; |
| 482 | | } |
| 483 | | |
| 484 | | /* add dispatcher just in case */ |
| 485 | | if (remaining == 0) |
| 486 | | drc_append_dispatcher(drc); |
| 487 | | |
| 488 | | exit: |
| 489 | | /* end the sequence */ |
| 490 | | drc_end_sequence(drc); |
| 491 | | |
| 492 | | /* log the generated code */ |
| 493 | | if (LOG_CODE) |
| 494 | | { |
| 495 | | char label[60]; |
| 496 | | physpc = mips3.core->pc; |
| 497 | | mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc); |
| 498 | | sprintf(label, "Code @ %08X (%08X physical)", mips3.core->pc, physpc); |
| 499 | | x86log_disasm_code_range(mips3.log, label, start, drc->cache_top); |
| 500 | | } |
| 501 | | } |
| 502 | | |
| 503 | | |
| 504 | | /*------------------------------------------------------------------ |
| 505 | | drc_entrygen_callback |
| 506 | | ------------------------------------------------------------------*/ |
| 507 | | |
| 508 | | static void drc_entrygen_callback(drc_core *drc) |
| 509 | | { |
| 510 | | emit_mov_r32_imm(DRCTOP, REG_ESI, (FPTR)&mips3.core->r[17]); |
| 511 | | append_check_interrupts(drc, 1); |
| 512 | | } |
| 513 | | |
| 514 | | |
| 515 | | |
| 516 | | /*************************************************************************** |
| 517 | | RECOMPILER CORE |
| 518 | | ***************************************************************************/ |
| 519 | | |
| 520 | | /*------------------------------------------------------------------ |
| 521 | | compile_one |
| 522 | | ------------------------------------------------------------------*/ |
| 523 | | |
| 524 | | static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc) |
| 525 | | { |
| 526 | | int pcdelta, cycles, hotnum; |
| 527 | | UINT32 *opptr; |
| 528 | | UINT32 result; |
| 529 | | |
| 530 | | /* register this instruction */ |
| 531 | | drc_register_code_at_cache_top(drc, pc); |
| 532 | | |
| 533 | | /* get a pointer to the current instruction */ |
| 534 | | change_pc(physpc); |
| 535 | | opptr = cpu_opptr(physpc); |
| 536 | | |
| 537 | | /* emit debugging and self-modifying code checks */ |
| 538 | | drc_append_call_debugger(drc); |
| 539 | | if (mips3.drcoptions & MIPS3DRC_STRICT_VERIFY) |
| 540 | | drc_append_verify_code(drc, opptr, 4); |
| 541 | | |
| 542 | | /* is this a hotspot? */ |
| 543 | | for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++) |
| 544 | | if (pc == mips3.hotspot[hotnum].pc && *(UINT32 *)opptr == mips3.hotspot[hotnum].opcode) |
| 545 | | break; |
| 546 | | |
| 547 | | /* compile the instruction */ |
| 548 | | result = recompile_instruction(drc, pc, physpc); |
| 549 | | |
| 550 | | /* handle the results */ |
| 551 | | if (!(result & RECOMPILE_SUCCESSFUL)) |
| 552 | | fatalerror("Unimplemented op %08X (%02X,%02X)", *opptr, *opptr >> 26, *opptr & 0x3f); |
| 553 | | |
| 554 | | pcdelta = (INT32)result >> 20; |
| 555 | | cycles = (result >> 8) & 0xfff; |
| 556 | | |
| 557 | | /* absorb any NOPs following */ |
| 558 | | if (STRIP_NOPS && !Machine->debug_mode) |
| 559 | | { |
| 560 | | if (!(result & (RECOMPILE_END_OF_STRING | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_CHECK_SW_INTERRUPTS))) |
| 561 | | while ((((pc + pcdelta) ^ pc) & 0xfffff000) == 0 && pcdelta < 120 && opptr[pcdelta/4] == 0) |
| 562 | | { |
| 563 | | pcdelta += 4; |
| 564 | | cycles += 1; |
| 565 | | } |
| 566 | | } |
| 567 | | |
| 568 | | /* epilogue */ |
| 569 | | if (hotnum != MIPS3_MAX_HOTSPOTS) |
| 570 | | cycles += mips3.hotspot[hotnum].cycles; |
| 571 | | drc_append_standard_epilogue(drc, cycles, pcdelta, 1); |
| 572 | | |
| 573 | | /* check interrupts */ |
| 574 | | if (result & RECOMPILE_CHECK_INTERRUPTS) |
| 575 | | append_check_interrupts(drc, 0); |
| 576 | | if (result & RECOMPILE_CHECK_SW_INTERRUPTS) |
| 577 | | append_check_sw_interrupts(drc, 0); |
| 578 | | if (result & RECOMPILE_ADD_DISPATCH) |
| 579 | | drc_append_dispatcher(drc); |
| 580 | | |
| 581 | | return (result & 0xff) | ((cycles & 0xfff) << 8) | ((pcdelta & 0xfff) << 20); |
| 582 | | } |
| 583 | | |
| 584 | | |
| 585 | | |
| 586 | | /*************************************************************************** |
| 587 | | COMMON ROUTINES |
| 588 | | ***************************************************************************/ |
| 589 | | |
| 590 | | /*------------------------------------------------------------------ |
| 591 | | append_generate_exception |
| 592 | | ------------------------------------------------------------------*/ |
| 593 | | |
| 594 | | static void append_generate_exception(drc_core *drc, UINT8 exception) |
| 595 | | { |
| 596 | | UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180; |
| 597 | | emit_link link1, link2; |
| 598 | | |
| 599 | | /* assumes address is in EAX */ |
| 600 | | if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) |
| 601 | | { |
| 602 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_EAX); // mov [BadVAddr],eax |
| 603 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff |
| 604 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0xffffe000); // and eax,0xffffe000 |
| 605 | | emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_EAX); // or [EntryHi],eax |
| 606 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000 |
| 607 | | emit_shr_r32_imm(DRCTOP, REG_EAX, 9); // shr eax,9 |
| 608 | | emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_EAX); // or [Context],eax |
| 609 | | } |
| 610 | | |
| 611 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_EDI); // mov [COP0_EPC],edi |
| 612 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause] |
| 613 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff |
| 614 | | if (exception) |
| 615 | | emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2 |
| 616 | | emit_cmp_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // cmp [mips3.nextpc],~0 |
| 617 | | emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip |
| 618 | | emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // mov [mips3.nextpc],~0 |
| 619 | | emit_sub_m32_imm(DRCTOP, CPR0ADDR(COP0_EPC), 4); // sub [COP0_EPC],4 |
| 620 | | emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000 |
| 621 | | resolve_link(DRCTOP, &link1); // skip: |
| 622 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax |
| 623 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[COP0_Status] |
| 624 | | emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL |
| 625 | | emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV |
| 626 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax |
| 627 | | emit_mov_r32_imm(DRCTOP, REG_EDI, 0xbfc00200 + offset); // mov edi,0xbfc00200+offset |
| 628 | | emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2 |
| 629 | | emit_mov_r32_imm(DRCTOP, REG_EDI, 0x80000000 + offset); // mov edi,0x80000000+offset |
| 630 | | resolve_link(DRCTOP, &link2); // skip2: |
| 631 | | drc_append_dispatcher(drc); // dispatch |
| 632 | | } |
| 633 | | |
| 634 | | |
| 635 | | /*------------------------------------------------------------------ |
| 636 | | append_readwrite_and_translate |
| 637 | | ------------------------------------------------------------------*/ |
| 638 | | |
| 639 | | static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags) |
| 640 | | { |
| 641 | | emit_link link1 = { 0 }, link2 = { 0 }, link3 = { 0 }; |
| 642 | | int ramnum; |
| 643 | | |
| 644 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4] |
| 645 | | emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EAX); // mov ebx,eax |
| 646 | | emit_shr_r32_imm(DRCTOP, REG_EBX, 12); // shr ebx,12 |
| 647 | | emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EBX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[ebx*4] |
| 648 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0xfff); // and eax,0xfff |
| 649 | | emit_shr_r32_imm(DRCTOP, REG_EBX, ((flags & ARW_WRITE) ? 1 : 2)); // shr ebx,2/1 (read/write) |
| 650 | | emit_lea_r32_m32(DRCTOP, REG_EBX, MBISD(REG_EAX, REG_EBX, ((flags & ARW_WRITE) ? 2 : 4), 0)); |
| 651 | | // lea ebx,[eax+ebx*4/2] (read/write) |
| 652 | | emit_jcc_near_link(DRCTOP, COND_C, &link1); // jc error |
| 653 | | for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) |
| 654 | | if (!Machine->debug_mode && mips3.fastram[ramnum].base && (!(flags & ARW_WRITE) || !mips3.fastram[ramnum].readonly)) |
| 655 | | { |
| 656 | | UINT32 fastbase = (UINT32)((UINT8 *)mips3.fastram[ramnum].base - mips3.fastram[ramnum].start); |
| 657 | | if (mips3.fastram[ramnum].end != 0xffffffff) |
| 658 | | { |
| 659 | | emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].end); // cmp ebx,fastram_end |
| 660 | | emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja notram |
| 661 | | } |
| 662 | | if (mips3.fastram[ramnum].start != 0x00000000) |
| 663 | | { |
| 664 | | emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].start); // cmp ebx,fastram_start |
| 665 | | emit_jcc_short_link(DRCTOP, COND_B, &link3); // jb notram |
| 666 | | } |
| 667 | | |
| 668 | | if (!(flags & ARW_WRITE)) |
| 669 | | { |
| 670 | | if (size == 1) |
| 671 | | { |
| 672 | | if (mips3.core->bigendian) |
| 673 | | emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3 |
| 674 | | if (flags & ARW_SIGNED) |
| 675 | | emit_movsx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,byte ptr [ebx+fastbase] |
| 676 | | else |
| 677 | | emit_movzx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,byte ptr [ebx+fastbase] |
| 678 | | } |
| 679 | | else if (size == 2) |
| 680 | | { |
| 681 | | if (mips3.core->bigendian) |
| 682 | | emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2 |
| 683 | | if (flags & ARW_SIGNED) |
| 684 | | emit_movsx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,word ptr [ebx+fastbase] |
| 685 | | else |
| 686 | | emit_movzx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,word ptr [ebx+fastbase] |
| 687 | | } |
| 688 | | else if (size == 4) |
| 689 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // mov eax,[ebx+fastbase] |
| 690 | | else if (size == 8) |
| 691 | | { |
| 692 | | if (mips3.core->bigendian) |
| 693 | | emit_mov_r64_m64(DRCTOP, REG_EAX, REG_EDX, MBD(REG_EBX, (FPTR)fastbase)); |
| 694 | | // mov eax:edx,[ebx+fastbase] |
| 695 | | else |
| 696 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MBD(REG_EBX, (FPTR)fastbase)); |
| 697 | | // mov edx:eax,[ebx+fastbase] |
| 698 | | } |
| 699 | | emit_ret(DRCTOP); // ret |
| 700 | | } |
| 701 | | else |
| 702 | | { |
| 703 | | if (size == 1) |
| 704 | | { |
| 705 | | emit_mov_r8_m8(DRCTOP, REG_AL, MBD(REG_ESP, 8)); // mov al,[esp+8] |
| 706 | | if (mips3.core->bigendian) |
| 707 | | emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3 |
| 708 | | emit_mov_m8_r8(DRCTOP, MBD(REG_EBX, fastbase), REG_AL); // mov [ebx+fastbase],al |
| 709 | | } |
| 710 | | else if (size == 2) |
| 711 | | { |
| 712 | | emit_mov_r16_m16(DRCTOP, REG_AX, MBD(REG_ESP, 8)); // mov ax,[esp+8] |
| 713 | | if (mips3.core->bigendian) |
| 714 | | emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2 |
| 715 | | emit_mov_m16_r16(DRCTOP, MBD(REG_EBX, fastbase), REG_AX); // mov [ebx+fastbase],ax |
| 716 | | } |
| 717 | | else if (size == 4) |
| 718 | | { |
| 719 | | if (!(flags & ARW_MASKED)) |
| 720 | | { |
| 721 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8] |
| 722 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax |
| 723 | | } |
| 724 | | else |
| 725 | | { |
| 726 | | emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 12)); // mov ecx,[esp+12] |
| 727 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx |
| 728 | | emit_not_r32(DRCTOP, REG_ECX); // not ecx |
| 729 | | emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8] |
| 730 | | emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase] |
| 731 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx |
| 732 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax |
| 733 | | } |
| 734 | | } |
| 735 | | else if (size == 8) |
| 736 | | { |
| 737 | | if (!(flags & ARW_MASKED)) |
| 738 | | { |
| 739 | | if (mips3.core->bigendian) |
| 740 | | { |
| 741 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8] |
| 742 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax |
| 743 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12] |
| 744 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax |
| 745 | | } |
| 746 | | else |
| 747 | | { |
| 748 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8] |
| 749 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax |
| 750 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12] |
| 751 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax |
| 752 | | } |
| 753 | | } |
| 754 | | else |
| 755 | | { |
| 756 | | if (mips3.core->bigendian) |
| 757 | | { |
| 758 | | emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16] |
| 759 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx |
| 760 | | emit_not_r32(DRCTOP, REG_ECX); // not ecx |
| 761 | | emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8] |
| 762 | | emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4] |
| 763 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx |
| 764 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax |
| 765 | | emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20] |
| 766 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx |
| 767 | | emit_not_r32(DRCTOP, REG_ECX); // not ecx |
| 768 | | emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12] |
| 769 | | emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase] |
| 770 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx |
| 771 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax |
| 772 | | } |
| 773 | | else |
| 774 | | { |
| 775 | | emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16] |
| 776 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx |
| 777 | | emit_not_r32(DRCTOP, REG_ECX); // not ecx |
| 778 | | emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8] |
| 779 | | emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase] |
| 780 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx |
| 781 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax |
| 782 | | emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20] |
| 783 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx |
| 784 | | emit_not_r32(DRCTOP, REG_ECX); // not ecx |
| 785 | | emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12] |
| 786 | | emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4] |
| 787 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx |
| 788 | | emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax |
| 789 | | } |
| 790 | | } |
| 791 | | } |
| 792 | | emit_ret(DRCTOP); // ret |
| 793 | | } |
| 794 | | |
| 795 | | if (mips3.fastram[ramnum].end != 0xffffffff) // notram: |
| 796 | | resolve_link(DRCTOP, &link2); |
| 797 | | if (mips3.fastram[ramnum].start != 0x00000000) |
| 798 | | resolve_link(DRCTOP, &link3); |
| 799 | | } |
| 800 | | |
| 801 | | if (flags & ARW_WRITE) |
| 802 | | { |
| 803 | | emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx |
| 804 | | if (size == 1) |
| 805 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writebyte); // jmp writebyte |
| 806 | | else if (size == 2) |
| 807 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writehalf); // jmp writehalf |
| 808 | | else if (size == 4) |
| 809 | | { |
| 810 | | if (!(flags & ARW_MASKED)) |
| 811 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword); // jmp writeword |
| 812 | | else |
| 813 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword_masked); // jmp writeword_masked |
| 814 | | } |
| 815 | | else |
| 816 | | { |
| 817 | | if (!(flags & ARW_MASKED)) |
| 818 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble); // jmp writedouble |
| 819 | | else |
| 820 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble_masked); // jmp writedouble_masked |
| 821 | | } |
| 822 | | } |
| 823 | | else |
| 824 | | { |
| 825 | | if (size == 1) |
| 826 | | { |
| 827 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 828 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 829 | | emit_call(DRCTOP, (x86code *)mips3.core->memory.readbyte); // call readbyte |
| 830 | | if (flags & ARW_SIGNED) |
| 831 | | emit_movsx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movsx eax,al |
| 832 | | else |
| 833 | | emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movzx eax,al |
| 834 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 835 | | emit_ret(DRCTOP); // ret |
| 836 | | } |
| 837 | | else if (size == 2) |
| 838 | | { |
| 839 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 840 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 841 | | emit_call(DRCTOP, (x86code *)mips3.core->memory.readhalf); // call readhalf |
| 842 | | if (flags & ARW_SIGNED) |
| 843 | | emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movsx eax,ax |
| 844 | | else |
| 845 | | emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movzx eax,ax |
| 846 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 847 | | emit_ret(DRCTOP); // ret |
| 848 | | } |
| 849 | | else if (size == 4) |
| 850 | | { |
| 851 | | emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx |
| 852 | | if (!(flags & ARW_MASKED)) |
| 853 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword); // jmp readword |
| 854 | | else |
| 855 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword_masked); // jmp readword_masked |
| 856 | | } |
| 857 | | else |
| 858 | | { |
| 859 | | emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx |
| 860 | | if (!(flags & ARW_MASKED)) |
| 861 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble); // jmp readdouble |
| 862 | | else |
| 863 | | emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble_masked); // jmp readdouble_masked |
| 864 | | } |
| 865 | | } |
| 866 | | { |
| 867 | | int valuebytes = (size == 8) ? 8 : 4; |
| 868 | | int stackbytes = 4 + ((flags & ARW_WRITE) ? 4 + valuebytes : 4) + ((flags & ARW_MASKED) ? valuebytes : 0); |
| 869 | | resolve_link(DRCTOP, &link1); // error: |
| 870 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4] |
| 871 | | emit_add_r32_imm(DRCTOP, REG_ESP, stackbytes); // add esp,stack_bytes |
| 872 | | emit_jmp(DRCTOP, (flags & ARW_WRITE) ? (x86code *)mips3.drcdata->generate_tlbstore_exception : (x86code *)mips3.drcdata->generate_tlbload_exception); |
| 873 | | // jmp generate_exception |
| 874 | | } |
| 875 | | } |
| 876 | | |
| 877 | | |
| 878 | | /*------------------------------------------------------------------ |
| 879 | | append_tlb_verify |
| 880 | | ------------------------------------------------------------------*/ |
| 881 | | |
| 882 | | static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target) |
| 883 | | { |
| 884 | | /* addresses 0x80000000-0xbfffffff are direct-mapped; no checking needed */ |
| 885 | | if (pc < 0x80000000 || pc >= 0xc0000000) |
| 886 | | { |
| 887 | | emit_cmp_m32_imm(DRCTOP, MABS(&mips3.core->tlb_table[pc >> 12]), mips3.core->tlb_table[pc >> 12]); |
| 888 | | // cmp tlbtable[pc >> 12],physpc & 0xfffff000 |
| 889 | | emit_jcc(DRCTOP, COND_NE, target); // jne handle_pc_tlb_mismatch |
| 890 | | } |
| 891 | | } |
| 892 | | |
| 893 | | |
| 894 | | /*------------------------------------------------------------------ |
| 895 | | append_update_cycle_counting |
| 896 | | ------------------------------------------------------------------*/ |
| 897 | | |
| 898 | | static void append_update_cycle_counting(drc_core *drc) |
| 899 | | { |
| 900 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 901 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 902 | | emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core |
| 903 | | emit_call(DRCTOP, (x86code *)mips3com_update_cycle_counting); // call update_cycle_counting |
| 904 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 905 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 906 | | } |
| 907 | | |
| 908 | | |
| 909 | | /*------------------------------------------------------------------ |
| 910 | | append_check_interrupts |
| 911 | | ------------------------------------------------------------------*/ |
| 912 | | |
| 913 | | static void append_check_interrupts(drc_core *drc, int inline_generate) |
| 914 | | { |
| 915 | | emit_link link1, link2, link3; |
| 916 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause] |
| 917 | | emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status] |
| 918 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00 |
| 919 | | if (!inline_generate) |
| 920 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 921 | | else |
| 922 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 923 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [COP0_Status,SR_IE |
| 924 | | if (!inline_generate) |
| 925 | | emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip |
| 926 | | else |
| 927 | | emit_jcc_near_link(DRCTOP, COND_Z, &link2); // jz skip |
| 928 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [COP0_Status,SR_EXL | SR_ERL |
| 929 | | if (!inline_generate) |
| 930 | | emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_interrupt_exception); // jz generate_interrupt_exception |
| 931 | | else |
| 932 | | { |
| 933 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link3); // jnz skip |
| 934 | | append_generate_exception(drc, EXCEPTION_INTERRUPT); // <generate exception> |
| 935 | | resolve_link(DRCTOP, &link3); // skip: |
| 936 | | } |
| 937 | | resolve_link(DRCTOP, &link1); // skip: |
| 938 | | resolve_link(DRCTOP, &link2); |
| 939 | | } |
| 940 | | |
| 941 | | |
| 942 | | /*------------------------------------------------------------------ |
| 943 | | append_check_sw_interrupts |
| 944 | | ------------------------------------------------------------------*/ |
| 945 | | |
| 946 | | static void append_check_sw_interrupts(drc_core *drc, int inline_generate) |
| 947 | | { |
| 948 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), 0x300); // test [COP0_Cause],0x300 |
| 949 | | emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_interrupt_exception); // jnz generate_interrupt_exception |
| 950 | | } |
| 951 | | |
| 952 | | |
| 953 | | /*------------------------------------------------------------------ |
| 954 | | append_branch_or_dispatch |
| 955 | | ------------------------------------------------------------------*/ |
| 956 | | |
| 957 | | static void append_branch_or_dispatch(drc_core *drc, UINT32 newpc, int cycles) |
| 958 | | { |
| 959 | | void *code = drc_get_code_at_pc(drc, newpc); |
| 960 | | emit_mov_r32_imm(DRCTOP, REG_EDI, newpc); // mov edi,newpc |
| 961 | | drc_append_standard_epilogue(drc, cycles, 0, 1); // <epilogue> |
| 962 | | |
| 963 | | if (code) |
| 964 | | emit_jmp(DRCTOP, code); // jmp code |
| 965 | | else |
| 966 | | drc_append_tentative_fixed_dispatcher(drc, newpc); // <dispatch> |
| 967 | | } |
| 968 | | |
| 969 | | |
| 970 | | |
| 971 | | /*************************************************************************** |
| 972 | | CORE RECOMPILATION |
| 973 | | ***************************************************************************/ |
| 974 | | |
| 975 | | static void ddiv(INT64 *rs, INT64 *rt) |
| 976 | | { |
| 977 | | if (*rt) |
| 978 | | { |
| 979 | | mips3.core->r[REG_LO] = *rs / *rt; |
| 980 | | mips3.core->r[REG_HI] = *rs % *rt; |
| 981 | | } |
| 982 | | } |
| 983 | | |
| 984 | | static void ddivu(UINT64 *rs, UINT64 *rt) |
| 985 | | { |
| 986 | | if (*rt) |
| 987 | | { |
| 988 | | mips3.core->r[REG_LO] = *rs / *rt; |
| 989 | | mips3.core->r[REG_HI] = *rs % *rt; |
| 990 | | } |
| 991 | | } |
| 992 | | |
| 993 | | |
| 994 | | /*------------------------------------------------------------------ |
| 995 | | recompile_delay_slot |
| 996 | | ------------------------------------------------------------------*/ |
| 997 | | |
| 998 | | static int recompile_delay_slot(drc_core *drc, UINT32 pc) |
| 999 | | { |
| 1000 | | UINT8 *saved_top; |
| 1001 | | UINT32 result; |
| 1002 | | UINT32 physpc; |
| 1003 | | |
| 1004 | | #ifdef ENABLE_DEBUGGER |
| 1005 | | if (Machine->debug_mode) |
| 1006 | | { |
| 1007 | | /* emit debugging */ |
| 1008 | | emit_mov_r32_imm(DRCTOP, REG_EDI, pc); |
| 1009 | | drc_append_call_debugger(drc); |
| 1010 | | } |
| 1011 | | #endif |
| 1012 | | |
| 1013 | | saved_top = drc->cache_top; |
| 1014 | | |
| 1015 | | /* recompile the instruction as-is */ |
| 1016 | | in_delay_slot = 1; |
| 1017 | | physpc = pc; |
| 1018 | | mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc); |
| 1019 | | result = recompile_instruction(drc, pc, physpc); // <next instruction> |
| 1020 | | in_delay_slot = 0; |
| 1021 | | |
| 1022 | | /* if the instruction can cause an exception, recompile setting nextpc */ |
| 1023 | | if (result & RECOMPILE_MAY_CAUSE_EXCEPTION) |
| 1024 | | { |
| 1025 | | drc->cache_top = saved_top; |
| 1026 | | emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), 0); // bogus nextpc for exceptions |
| 1027 | | result = recompile_instruction(drc, pc, physpc); // <next instruction> |
| 1028 | | emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // reset nextpc |
| 1029 | | } |
| 1030 | | |
| 1031 | | return (result >> 8) & 0xfff; |
| 1032 | | } |
| 1033 | | |
| 1034 | | |
| 1035 | | /*------------------------------------------------------------------ |
| 1036 | | recompile_instruction |
| 1037 | | ------------------------------------------------------------------*/ |
| 1038 | | |
| 1039 | | static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc) |
| 1040 | | { |
| 1041 | | emit_link link1, link2 = { 0 }, link3; |
| 1042 | | UINT32 op = cpu_readop32(physpc); |
| 1043 | | int cycles; |
| 1044 | | |
| 1045 | | if (LOG_CODE) |
| 1046 | | log_add_disasm_comment(mips3.log, drc->cache_top, pc, op); |
| 1047 | | |
| 1048 | | switch (op >> 26) |
| 1049 | | { |
| 1050 | | case 0x00: /* SPECIAL */ |
| 1051 | | return recompile_special(drc, pc, op); |
| 1052 | | |
| 1053 | | case 0x01: /* REGIMM */ |
| 1054 | | return recompile_regimm(drc, pc, op); |
| 1055 | | |
| 1056 | | case 0x02: /* J */ |
| 1057 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1058 | | append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1059 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 1060 | | |
| 1061 | | case 0x03: /* JAL */ |
| 1062 | | emit_mov_m64_imm32(DRCTOP, REGADDR(31), pc + 8); // mov [31],pc + 8 |
| 1063 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1064 | | append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1065 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 1066 | | |
| 1067 | | case 0x04: /* BEQ */ |
| 1068 | | if (RSREG == RTREG) |
| 1069 | | { |
| 1070 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1071 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1072 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 1073 | | } |
| 1074 | | else if (RSREG == 0) |
| 1075 | | { |
| 1076 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 1077 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 1078 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 1079 | | } |
| 1080 | | else if (RTREG == 0) |
| 1081 | | { |
| 1082 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1083 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi |
| 1084 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 1085 | | } |
| 1086 | | else |
| 1087 | | { |
| 1088 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1089 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 1090 | | emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip |
| 1091 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 1092 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 1093 | | emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip |
| 1094 | | } |
| 1095 | | |
| 1096 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1097 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1098 | | resolve_link(DRCTOP, &link1); // skip: |
| 1099 | | if (RSREG != 0 && RTREG != 0) |
| 1100 | | resolve_link(DRCTOP, &link2); // skip: |
| 1101 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1102 | | |
| 1103 | | case 0x05: /* BNE */ |
| 1104 | | if (RSREG == 0) |
| 1105 | | { |
| 1106 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 1107 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 1108 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1109 | | } |
| 1110 | | else if (RTREG == 0) |
| 1111 | | { |
| 1112 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1113 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi |
| 1114 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1115 | | } |
| 1116 | | else |
| 1117 | | { |
| 1118 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1119 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 1120 | | emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit |
| 1121 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 1122 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 1123 | | emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip |
| 1124 | | resolve_link(DRCTOP, &link2); // takeit: |
| 1125 | | } |
| 1126 | | |
| 1127 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1128 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1129 | | resolve_link(DRCTOP, &link1); // skip: |
| 1130 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1131 | | |
| 1132 | | case 0x06: /* BLEZ */ |
| 1133 | | if (RSREG == 0) |
| 1134 | | { |
| 1135 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1136 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1137 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 1138 | | } |
| 1139 | | else |
| 1140 | | { |
| 1141 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 1142 | | emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip |
| 1143 | | emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit |
| 1144 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 |
| 1145 | | emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip |
| 1146 | | resolve_link(DRCTOP, &link2); // takeit: |
| 1147 | | } |
| 1148 | | |
| 1149 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1150 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1151 | | resolve_link(DRCTOP, &link1); // skip: |
| 1152 | | resolve_link(DRCTOP, &link3); // skip: |
| 1153 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1154 | | |
| 1155 | | case 0x07: /* BGTZ */ |
| 1156 | | if (RSREG == 0) |
| 1157 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1158 | | else |
| 1159 | | { |
| 1160 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 1161 | | emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip |
| 1162 | | emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit |
| 1163 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 |
| 1164 | | emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip |
| 1165 | | resolve_link(DRCTOP, &link2); // takeit: |
| 1166 | | } |
| 1167 | | |
| 1168 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1169 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1170 | | resolve_link(DRCTOP, &link1); // skip: |
| 1171 | | resolve_link(DRCTOP, &link3); // skip: |
| 1172 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1173 | | |
| 1174 | | case 0x08: /* ADDI */ |
| 1175 | | if (RSREG != 0) |
| 1176 | | { |
| 1177 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1178 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1179 | | emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception |
| 1180 | | if (RTREG != 0) |
| 1181 | | { |
| 1182 | | emit_cdq(DRCTOP); // cdq |
| 1183 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1184 | | } |
| 1185 | | } |
| 1186 | | else if (RTREG != 0) |
| 1187 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const |
| 1188 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 1189 | | |
| 1190 | | case 0x09: /* ADDIU */ |
| 1191 | | if (RTREG != 0) |
| 1192 | | { |
| 1193 | | if (RSREG != 0) |
| 1194 | | { |
| 1195 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1196 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1197 | | emit_cdq(DRCTOP); // cdq |
| 1198 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1199 | | } |
| 1200 | | else |
| 1201 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const |
| 1202 | | } |
| 1203 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1204 | | |
| 1205 | | case 0x0a: /* SLTI */ |
| 1206 | | if (RTREG != 0) |
| 1207 | | { |
| 1208 | | if (RSREG != 0) |
| 1209 | | { |
| 1210 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 1211 | | emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo |
| 1212 | | emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo |
| 1213 | | emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31 |
| 1214 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EDX); // mov [rdreg].lo,edx |
| 1215 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rdreg].hi,0 |
| 1216 | | } |
| 1217 | | else |
| 1218 | | { |
| 1219 | | emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const |
| 1220 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) |
| 1221 | | } |
| 1222 | | } |
| 1223 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1224 | | |
| 1225 | | case 0x0b: /* SLTIU */ |
| 1226 | | if (RTREG != 0) |
| 1227 | | { |
| 1228 | | if (RSREG != 0) |
| 1229 | | { |
| 1230 | | emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx |
| 1231 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); // cmp [rsreg].hi,upper |
| 1232 | | emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb takeit |
| 1233 | | emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skip |
| 1234 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower |
| 1235 | | emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skip |
| 1236 | | resolve_link(DRCTOP, &link1); // takeit: |
| 1237 | | emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1 |
| 1238 | | resolve_link(DRCTOP, &link2); // skip: |
| 1239 | | resolve_link(DRCTOP, &link3); // skip: |
| 1240 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_ECX); // mov [rtreg].lo,ecx |
| 1241 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) |
| 1242 | | } |
| 1243 | | else |
| 1244 | | { |
| 1245 | | emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const |
| 1246 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) |
| 1247 | | } |
| 1248 | | } |
| 1249 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1250 | | |
| 1251 | | case 0x0c: /* ANDI */ |
| 1252 | | if (RTREG != 0) |
| 1253 | | { |
| 1254 | | if (RSREG == RTREG) |
| 1255 | | { |
| 1256 | | emit_and_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // and [rtreg],UIMMVAL |
| 1257 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 |
| 1258 | | } |
| 1259 | | else if (RSREG != 0) |
| 1260 | | { |
| 1261 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1262 | | emit_and_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // and eax,UIMMVAL |
| 1263 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax |
| 1264 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 |
| 1265 | | } |
| 1266 | | else |
| 1267 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), 0); // mov [rtreg],0 |
| 1268 | | } |
| 1269 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1270 | | |
| 1271 | | case 0x0d: /* ORI */ |
| 1272 | | if (RTREG != 0) |
| 1273 | | { |
| 1274 | | if (RSREG == RTREG) |
| 1275 | | emit_or_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // or [rtreg].lo,UIMMVAL |
| 1276 | | else if (RSREG != 0) |
| 1277 | | { |
| 1278 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 1279 | | emit_or_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // or eax,UIMMVAL |
| 1280 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1281 | | } |
| 1282 | | else |
| 1283 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const |
| 1284 | | } |
| 1285 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1286 | | |
| 1287 | | case 0x0e: /* XORI */ |
| 1288 | | if (RTREG != 0) |
| 1289 | | { |
| 1290 | | if (RSREG == RTREG) |
| 1291 | | emit_xor_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // xor [rtreg].lo,UIMMVAL |
| 1292 | | else if (RSREG != 0) |
| 1293 | | { |
| 1294 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 1295 | | emit_xor_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // xor eax,UIMMVAL |
| 1296 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1297 | | } |
| 1298 | | else |
| 1299 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const |
| 1300 | | } |
| 1301 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1302 | | |
| 1303 | | case 0x0f: /* LUI */ |
| 1304 | | if (RTREG != 0) |
| 1305 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL << 16); // mov [rtreg],const << 16 |
| 1306 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1307 | | |
| 1308 | | case 0x10: /* COP0 */ |
| 1309 | | return recompile_cop0(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 1310 | | |
| 1311 | | case 0x11: /* COP1 */ |
| 1312 | | return recompile_cop1(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 1313 | | |
| 1314 | | case 0x12: /* COP2 */ |
| 1315 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 1316 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 1317 | | |
| 1318 | | case 0x13: /* COP1X - R5000 */ |
| 1319 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 1320 | | { |
| 1321 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 1322 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 1323 | | } |
| 1324 | | return recompile_cop1x(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 1325 | | |
| 1326 | | case 0x14: /* BEQL */ |
| 1327 | | if (RSREG == RTREG) |
| 1328 | | { |
| 1329 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1330 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1331 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 1332 | | } |
| 1333 | | else if (RSREG == 0) |
| 1334 | | { |
| 1335 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 1336 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 1337 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 1338 | | } |
| 1339 | | else if (RTREG == 0) |
| 1340 | | { |
| 1341 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1342 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi |
| 1343 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 1344 | | } |
| 1345 | | else |
| 1346 | | { |
| 1347 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1348 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 1349 | | emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip |
| 1350 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 1351 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 1352 | | emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip |
| 1353 | | } |
| 1354 | | |
| 1355 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1356 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1357 | | resolve_link(DRCTOP, &link1); // skip: |
| 1358 | | if (RSREG != 0 && RTREG != 0) |
| 1359 | | resolve_link(DRCTOP, &link2); // skip: |
| 1360 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 1361 | | |
| 1362 | | case 0x15: /* BNEL */ |
| 1363 | | if (RSREG == 0) |
| 1364 | | { |
| 1365 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 1366 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 1367 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1368 | | } |
| 1369 | | else if (RTREG == 0) |
| 1370 | | { |
| 1371 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1372 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi |
| 1373 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 1374 | | } |
| 1375 | | else |
| 1376 | | { |
| 1377 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1378 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 1379 | | emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit |
| 1380 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 1381 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 1382 | | emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip |
| 1383 | | resolve_link(DRCTOP, &link2); // takeit: |
| 1384 | | } |
| 1385 | | |
| 1386 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1387 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1388 | | resolve_link(DRCTOP, &link1); // skip: |
| 1389 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 1390 | | |
| 1391 | | case 0x16: /* BLEZL */ |
| 1392 | | if (RSREG == 0) |
| 1393 | | { |
| 1394 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1395 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1396 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 1397 | | } |
| 1398 | | else |
| 1399 | | { |
| 1400 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 1401 | | emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip |
| 1402 | | emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit |
| 1403 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 |
| 1404 | | emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip |
| 1405 | | resolve_link(DRCTOP, &link2); // takeit: |
| 1406 | | } |
| 1407 | | |
| 1408 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1409 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1410 | | resolve_link(DRCTOP, &link1); // skip: |
| 1411 | | resolve_link(DRCTOP, &link3); // skip: |
| 1412 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 1413 | | |
| 1414 | | case 0x17: /* BGTZL */ |
| 1415 | | if (RSREG == 0) |
| 1416 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 1417 | | else |
| 1418 | | { |
| 1419 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 1420 | | emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip |
| 1421 | | emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit |
| 1422 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 |
| 1423 | | emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip |
| 1424 | | resolve_link(DRCTOP, &link2); // takeit: |
| 1425 | | } |
| 1426 | | |
| 1427 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 1428 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 1429 | | resolve_link(DRCTOP, &link1); // skip: |
| 1430 | | resolve_link(DRCTOP, &link3); // skip: |
| 1431 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 1432 | | |
| 1433 | | case 0x18: /* DADDI */ |
| 1434 | | if (RSREG != 0) |
| 1435 | | { |
| 1436 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 1437 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1438 | | emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL) |
| 1439 | | emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception |
| 1440 | | if (RTREG != 0) |
| 1441 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1442 | | } |
| 1443 | | else if (RTREG != 0) |
| 1444 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const |
| 1445 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 1446 | | |
| 1447 | | case 0x19: /* DADDIU */ |
| 1448 | | if (RTREG != 0) |
| 1449 | | { |
| 1450 | | if (RSREG != 0) |
| 1451 | | { |
| 1452 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 1453 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1454 | | emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL) |
| 1455 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1456 | | } |
| 1457 | | else |
| 1458 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const |
| 1459 | | } |
| 1460 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1461 | | |
| 1462 | | case 0x1a: /* LDL */ |
| 1463 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1464 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1465 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1466 | | if (SIMMVAL) |
| 1467 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1468 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] |
| 1469 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 |
| 1470 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1471 | | emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 |
| 1472 | | if (!mips3.core->bigendian) |
| 1473 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c |
| 1474 | | emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl |
| 1475 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl |
| 1476 | | emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl |
| 1477 | | emit_push_r32(DRCTOP, REG_ECX); // push ecx |
| 1478 | | emit_push_r32(DRCTOP, REG_EBP); // push ebp |
| 1479 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1480 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1481 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked |
| 1482 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1483 | | emit_pop_r32(DRCTOP, REG_ECX); // pop ecx |
| 1484 | | |
| 1485 | | if (RTREG != 0) |
| 1486 | | { |
| 1487 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1488 | | emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 |
| 1489 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1490 | | emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl |
| 1491 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1492 | | emit_not_r32(DRCTOP, REG_EBX); // not ebx |
| 1493 | | emit_not_r32(DRCTOP, REG_EBP); // not ebp |
| 1494 | | emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl |
| 1495 | | emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl |
| 1496 | | emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl |
| 1497 | | emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl |
| 1498 | | emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo |
| 1499 | | emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi |
| 1500 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 1501 | | emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp |
| 1502 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1503 | | } |
| 1504 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1505 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1506 | | |
| 1507 | | case 0x1b: /* LDR */ |
| 1508 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1509 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1510 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1511 | | if (SIMMVAL) |
| 1512 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1513 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] |
| 1514 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 |
| 1515 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1516 | | emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 |
| 1517 | | if (mips3.core->bigendian) |
| 1518 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c |
| 1519 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1520 | | emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl |
| 1521 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1522 | | emit_push_r32(DRCTOP, REG_ECX); // push ecx |
| 1523 | | emit_push_r32(DRCTOP, REG_EBP); // push ebp |
| 1524 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1525 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1526 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked |
| 1527 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1528 | | emit_pop_r32(DRCTOP, REG_ECX); // pop ecx |
| 1529 | | |
| 1530 | | if (RTREG != 0) |
| 1531 | | { |
| 1532 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1533 | | emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 |
| 1534 | | emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl |
| 1535 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl |
| 1536 | | emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl |
| 1537 | | emit_not_r32(DRCTOP, REG_EBX); // not ebx |
| 1538 | | emit_not_r32(DRCTOP, REG_EBP); // not ebp |
| 1539 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl |
| 1540 | | emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl |
| 1541 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl |
| 1542 | | emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl |
| 1543 | | emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo |
| 1544 | | emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi |
| 1545 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 1546 | | emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp |
| 1547 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1548 | | } |
| 1549 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1550 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1551 | | |
| 1552 | | case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */ |
| 1553 | | switch (op & 0x1f) |
| 1554 | | { |
| 1555 | | case 0: /* MAD */ |
| 1556 | | if (RSREG != 0 && RTREG != 0) |
| 1557 | | { |
| 1558 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] |
| 1559 | | emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg] |
| 1560 | | emit_imul_r32(DRCTOP, REG_EDX); // imul edx |
| 1561 | | emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo] |
| 1562 | | emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi] |
| 1563 | | emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx |
| 1564 | | emit_cdq(DRCTOP); // cdq |
| 1565 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 1566 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx |
| 1567 | | emit_cdq(DRCTOP); // cdq |
| 1568 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 1569 | | } |
| 1570 | | return RECOMPILE_SUCCESSFUL_CP(3,4); |
| 1571 | | |
| 1572 | | case 1: /* MADU */ |
| 1573 | | if (RSREG != 0 && RTREG != 0) |
| 1574 | | { |
| 1575 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] |
| 1576 | | emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg] |
| 1577 | | emit_mul_r32(DRCTOP, REG_EDX); // mul edx |
| 1578 | | emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo] |
| 1579 | | emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi] |
| 1580 | | emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx |
| 1581 | | emit_cdq(DRCTOP); // cdq |
| 1582 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 1583 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx |
| 1584 | | emit_cdq(DRCTOP); // cdq |
| 1585 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 1586 | | } |
| 1587 | | return RECOMPILE_SUCCESSFUL_CP(3,4); |
| 1588 | | |
| 1589 | | case 2: /* MUL */ |
| 1590 | | if (RDREG != 0) |
| 1591 | | { |
| 1592 | | if (RSREG != 0 && RTREG != 0) |
| 1593 | | { |
| 1594 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1595 | | emit_imul_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // imul eax,[rtreg].lo |
| 1596 | | emit_cdq(DRCTOP); // cdq |
| 1597 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 1598 | | } |
| 1599 | | else |
| 1600 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); // mov [rdreg],0 |
| 1601 | | } |
| 1602 | | return RECOMPILE_SUCCESSFUL_CP(3,4); |
| 1603 | | } |
| 1604 | | break; |
| 1605 | | |
| 1606 | | case 0x20: /* LB */ |
| 1607 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1608 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1609 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 1610 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1611 | | { |
| 1612 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1613 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1614 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1615 | | } |
| 1616 | | else if (RSREG != 0) |
| 1617 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1618 | | else |
| 1619 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1620 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_signed); // call read_and_translate_byte_signed |
| 1621 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1622 | | if (RTREG != 0) |
| 1623 | | { |
| 1624 | | emit_cdq(DRCTOP); // cdq |
| 1625 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1626 | | } |
| 1627 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1628 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1629 | | |
| 1630 | | case 0x21: /* LH */ |
| 1631 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1632 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1633 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 1634 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1635 | | { |
| 1636 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1637 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1638 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1639 | | } |
| 1640 | | else if (RSREG != 0) |
| 1641 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1642 | | else |
| 1643 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1644 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_signed); // call read_and_translate_half_signed |
| 1645 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1646 | | if (RTREG != 0) |
| 1647 | | { |
| 1648 | | emit_cdq(DRCTOP); // cdq |
| 1649 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1650 | | } |
| 1651 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1652 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1653 | | |
| 1654 | | case 0x22: /* LWL */ |
| 1655 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1656 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1657 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 1658 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1659 | | if (SIMMVAL) |
| 1660 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1661 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] |
| 1662 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 |
| 1663 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1664 | | if (!mips3.core->bigendian) |
| 1665 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 |
| 1666 | | emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl |
| 1667 | | emit_push_r32(DRCTOP, REG_ECX); // push ecx |
| 1668 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1669 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1670 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked |
| 1671 | | emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8 |
| 1672 | | emit_pop_r32(DRCTOP, REG_ECX); // pop ecx |
| 1673 | | |
| 1674 | | if (RTREG != 0) |
| 1675 | | { |
| 1676 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1677 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1678 | | emit_not_r32(DRCTOP, REG_EBX); // not ebx |
| 1679 | | emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl |
| 1680 | | emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo |
| 1681 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 1682 | | emit_cdq(DRCTOP); // cdq |
| 1683 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1684 | | } |
| 1685 | | emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4 |
| 1686 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1687 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1688 | | |
| 1689 | | case 0x23: /* LW */ |
| 1690 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1691 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1692 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 1693 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1694 | | { |
| 1695 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1696 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1697 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1698 | | } |
| 1699 | | else if (RSREG != 0) |
| 1700 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1701 | | else |
| 1702 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1703 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word |
| 1704 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1705 | | if (RTREG != 0) |
| 1706 | | { |
| 1707 | | emit_cdq(DRCTOP); // cdq |
| 1708 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1709 | | } |
| 1710 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1711 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1712 | | |
| 1713 | | case 0x24: /* LBU */ |
| 1714 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1715 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1716 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 1717 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1718 | | { |
| 1719 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1720 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1721 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1722 | | } |
| 1723 | | else if (RSREG != 0) |
| 1724 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1725 | | else |
| 1726 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1727 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_unsigned); // call read_and_translate_byte_unsigned |
| 1728 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1729 | | if (RTREG != 0) |
| 1730 | | { |
| 1731 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 |
| 1732 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax |
| 1733 | | } |
| 1734 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1735 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1736 | | |
| 1737 | | case 0x25: /* LHU */ |
| 1738 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1739 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1740 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 1741 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1742 | | { |
| 1743 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1744 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1745 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1746 | | } |
| 1747 | | else if (RSREG != 0) |
| 1748 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1749 | | else |
| 1750 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1751 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_unsigned); // call read_and_translate_half_unsigned |
| 1752 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1753 | | if (RTREG != 0) |
| 1754 | | { |
| 1755 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 |
| 1756 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax |
| 1757 | | } |
| 1758 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1759 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1760 | | |
| 1761 | | case 0x26: /* LWR */ |
| 1762 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1763 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1764 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 1765 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1766 | | if (SIMMVAL) |
| 1767 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1768 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] |
| 1769 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 |
| 1770 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1771 | | if (mips3.core->bigendian) |
| 1772 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 |
| 1773 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1774 | | emit_push_r32(DRCTOP, REG_ECX); // push ecx |
| 1775 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1776 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1777 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked |
| 1778 | | emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8 |
| 1779 | | emit_pop_r32(DRCTOP, REG_ECX); // pop ecx |
| 1780 | | |
| 1781 | | if (RTREG != 0) |
| 1782 | | { |
| 1783 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1784 | | emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl |
| 1785 | | emit_not_r32(DRCTOP, REG_EBX); // not ebx |
| 1786 | | emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl |
| 1787 | | emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo |
| 1788 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 1789 | | emit_cdq(DRCTOP); // cdq |
| 1790 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 1791 | | } |
| 1792 | | emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4 |
| 1793 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1794 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1795 | | |
| 1796 | | case 0x27: /* LWU */ |
| 1797 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1798 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1799 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 1800 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1801 | | { |
| 1802 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1803 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1804 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1805 | | } |
| 1806 | | else if (RSREG != 0) |
| 1807 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1808 | | else |
| 1809 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1810 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word |
| 1811 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1812 | | if (RTREG != 0) |
| 1813 | | { |
| 1814 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 |
| 1815 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax |
| 1816 | | } |
| 1817 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1818 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1819 | | |
| 1820 | | case 0x28: /* SB */ |
| 1821 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1822 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1823 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 1824 | | if (RTREG != 0) |
| 1825 | | emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo |
| 1826 | | else |
| 1827 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1828 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1829 | | { |
| 1830 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1831 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1832 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1833 | | } |
| 1834 | | else if (RSREG != 0) |
| 1835 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1836 | | else |
| 1837 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1838 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_byte); // call writebyte |
| 1839 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1840 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1841 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1842 | | |
| 1843 | | case 0x29: /* SH */ |
| 1844 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1845 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1846 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 1847 | | if (RTREG != 0) |
| 1848 | | emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo |
| 1849 | | else |
| 1850 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1851 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1852 | | { |
| 1853 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1854 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1855 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1856 | | } |
| 1857 | | else if (RSREG != 0) |
| 1858 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1859 | | else |
| 1860 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1861 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_half); // call writehalf |
| 1862 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1863 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1864 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1865 | | |
| 1866 | | case 0x2a: /* SWL */ |
| 1867 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1868 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1869 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 1870 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1871 | | if (SIMMVAL) |
| 1872 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1873 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] |
| 1874 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 |
| 1875 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1876 | | if (!mips3.core->bigendian) |
| 1877 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 |
| 1878 | | emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl |
| 1879 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1880 | | if (RTREG != 0) |
| 1881 | | { |
| 1882 | | emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo |
| 1883 | | emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl |
| 1884 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 1885 | | } |
| 1886 | | else |
| 1887 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1888 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1889 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked |
| 1890 | | emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16 |
| 1891 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1892 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1893 | | |
| 1894 | | case 0x2b: /* SW */ |
| 1895 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1896 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1897 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 1898 | | if (RTREG != 0) |
| 1899 | | emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo |
| 1900 | | else |
| 1901 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1902 | | if (RSREG != 0 && SIMMVAL != 0) |
| 1903 | | { |
| 1904 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1905 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1906 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1907 | | } |
| 1908 | | else if (RSREG != 0) |
| 1909 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 1910 | | else |
| 1911 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 1912 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word |
| 1913 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 1914 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1915 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1916 | | |
| 1917 | | case 0x2c: /* SDL */ |
| 1918 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1919 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1920 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12 |
| 1921 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1922 | | if (SIMMVAL) |
| 1923 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1924 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] |
| 1925 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 |
| 1926 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1927 | | emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 |
| 1928 | | if (!mips3.core->bigendian) |
| 1929 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c |
| 1930 | | emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl |
| 1931 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl |
| 1932 | | emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl |
| 1933 | | emit_push_r32(DRCTOP, REG_EBP); // push ebp |
| 1934 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1935 | | if (RTREG != 0) |
| 1936 | | { |
| 1937 | | emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo |
| 1938 | | emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi |
| 1939 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl |
| 1940 | | emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl |
| 1941 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl |
| 1942 | | emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl |
| 1943 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 1944 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1945 | | } |
| 1946 | | else |
| 1947 | | { |
| 1948 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1949 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1950 | | } |
| 1951 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1952 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked |
| 1953 | | emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32 |
| 1954 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1955 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1956 | | |
| 1957 | | case 0x2d: /* SDR */ |
| 1958 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1959 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 1960 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12 |
| 1961 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 1962 | | if (SIMMVAL) |
| 1963 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 1964 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] |
| 1965 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 |
| 1966 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 1967 | | emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 |
| 1968 | | if (mips3.core->bigendian) |
| 1969 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c |
| 1970 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1971 | | emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl |
| 1972 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1973 | | emit_push_r32(DRCTOP, REG_EBP); // push ebp |
| 1974 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1975 | | if (RTREG != 0) |
| 1976 | | { |
| 1977 | | emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo |
| 1978 | | emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi |
| 1979 | | emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl |
| 1980 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1981 | | emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl |
| 1982 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 1983 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 1984 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 1985 | | } |
| 1986 | | else |
| 1987 | | { |
| 1988 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1989 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 1990 | | } |
| 1991 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 1992 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked |
| 1993 | | emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32 |
| 1994 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 1995 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 1996 | | |
| 1997 | | case 0x2e: /* SWR */ |
| 1998 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 1999 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2000 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 2001 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2002 | | if (SIMMVAL) |
| 2003 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2004 | | emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] |
| 2005 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 |
| 2006 | | emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 |
| 2007 | | if (mips3.core->bigendian) |
| 2008 | | emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 |
| 2009 | | emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl |
| 2010 | | emit_push_r32(DRCTOP, REG_EBX); // push ebx |
| 2011 | | if (RTREG != 0) |
| 2012 | | { |
| 2013 | | emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo |
| 2014 | | emit_shl_r32_cl(DRCTOP, REG_EDX); // shl edx,cl |
| 2015 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 2016 | | } |
| 2017 | | else |
| 2018 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 2019 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2020 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked |
| 2021 | | emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16 |
| 2022 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2023 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2024 | | |
| 2025 | | case 0x2f: /* CACHE */ |
| 2026 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2027 | | |
| 2028 | | // case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break; |
| 2029 | | |
| 2030 | | case 0x31: /* LWC1 */ |
| 2031 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2032 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2033 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 2034 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2035 | | { |
| 2036 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].los |
| 2037 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2038 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2039 | | } |
| 2040 | | else if (RSREG != 0) |
| 2041 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2042 | | else |
| 2043 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2044 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word |
| 2045 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2046 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(RTREG), REG_EAX); // mov [rtreg],eax |
| 2047 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2048 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2049 | | |
| 2050 | | case 0x32: /* LWC2 */ |
| 2051 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2052 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2053 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 2054 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2055 | | { |
| 2056 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2057 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2058 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2059 | | } |
| 2060 | | else if (RSREG != 0) |
| 2061 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2062 | | else |
| 2063 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2064 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word |
| 2065 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2066 | | emit_mov_m32_r32(DRCTOP, CPR2ADDR(RTREG), REG_EAX); // mov [rtreg],eax |
| 2067 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2068 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2069 | | |
| 2070 | | case 0x33: /* PREF */ |
| 2071 | | if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) |
| 2072 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2073 | | else |
| 2074 | | { |
| 2075 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 2076 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 2077 | | } |
| 2078 | | |
| 2079 | | // case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break; |
| 2080 | | |
| 2081 | | case 0x35: /* LDC1 */ |
| 2082 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2083 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2084 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 2085 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2086 | | { |
| 2087 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2088 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2089 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2090 | | } |
| 2091 | | else if (RSREG != 0) |
| 2092 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2093 | | else |
| 2094 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2095 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double |
| 2096 | | emit_mov_m64_r64(DRCTOP, FPR64ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 2097 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2098 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2099 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2100 | | |
| 2101 | | case 0x36: /* LDC2 */ |
| 2102 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2103 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2104 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 2105 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2106 | | { |
| 2107 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2108 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2109 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2110 | | } |
| 2111 | | else if (RSREG != 0) |
| 2112 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2113 | | else |
| 2114 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2115 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_word |
| 2116 | | emit_mov_m64_r64(DRCTOP, CPR2ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 2117 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2118 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2119 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2120 | | |
| 2121 | | case 0x37: /* LD */ |
| 2122 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2123 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2124 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 2125 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2126 | | { |
| 2127 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2128 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2129 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2130 | | } |
| 2131 | | else if (RSREG != 0) |
| 2132 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2133 | | else |
| 2134 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2135 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double |
| 2136 | | if (RTREG != 0) |
| 2137 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 2138 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2139 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2140 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2141 | | |
| 2142 | | // case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break; |
| 2143 | | |
| 2144 | | case 0x39: /* SWC1 */ |
| 2145 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2146 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2147 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 2148 | | emit_push_m32(DRCTOP, FPR32ADDR(RTREG)); // push dword [rtreg] |
| 2149 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2150 | | { |
| 2151 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2152 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2153 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2154 | | } |
| 2155 | | else if (RSREG != 0) |
| 2156 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2157 | | else |
| 2158 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2159 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word |
| 2160 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2161 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2162 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2163 | | |
| 2164 | | case 0x3a: /* SWC2 */ |
| 2165 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2166 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2167 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 2168 | | emit_push_m32(DRCTOP, CPR2ADDR(RTREG)); // push dword [rtreg] |
| 2169 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2170 | | { |
| 2171 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2172 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2173 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2174 | | } |
| 2175 | | else if (RSREG != 0) |
| 2176 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2177 | | else |
| 2178 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2179 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word |
| 2180 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2181 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2182 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2183 | | |
| 2184 | | // case 0x3b: /* SWC3 */ invalid_instruction(op); break; |
| 2185 | | // case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break; |
| 2186 | | |
| 2187 | | case 0x3d: /* SDC1 */ |
| 2188 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2189 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2190 | | emit_push_m32(DRCTOP, FPR64ADDRHI(RTREG)); // push dword [rtreg].hi |
| 2191 | | emit_push_m32(DRCTOP, FPR64ADDRLO(RTREG)); // push dword [rtreg].lo |
| 2192 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2193 | | { |
| 2194 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2195 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2196 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2197 | | } |
| 2198 | | else if (RSREG != 0) |
| 2199 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2200 | | else |
| 2201 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2202 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double |
| 2203 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2204 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2205 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2206 | | |
| 2207 | | case 0x3e: /* SDC2 */ |
| 2208 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2209 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2210 | | emit_push_m32(DRCTOP, CPR2ADDRHI(RTREG)); // push dword [rtreg].hi |
| 2211 | | emit_push_m32(DRCTOP, CPR2ADDRLO(RTREG)); // push dword [rtreg].lo |
| 2212 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2213 | | { |
| 2214 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2215 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2216 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2217 | | } |
| 2218 | | else if (RSREG != 0) |
| 2219 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2220 | | else |
| 2221 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2222 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double |
| 2223 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2224 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2225 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2226 | | |
| 2227 | | case 0x3f: /* SD */ |
| 2228 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 2229 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 2230 | | if (RTREG != 0) |
| 2231 | | { |
| 2232 | | emit_push_m32(DRCTOP, REGADDRHI(RTREG)); // push dword [rtreg].hi |
| 2233 | | emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo |
| 2234 | | } |
| 2235 | | else |
| 2236 | | { |
| 2237 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 2238 | | emit_push_imm(DRCTOP, 0); // push 0 |
| 2239 | | } |
| 2240 | | if (RSREG != 0 && SIMMVAL != 0) |
| 2241 | | { |
| 2242 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2243 | | emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL |
| 2244 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 2245 | | } |
| 2246 | | else if (RSREG != 0) |
| 2247 | | emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo |
| 2248 | | else |
| 2249 | | emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL |
| 2250 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double |
| 2251 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2252 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 2253 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2254 | | |
| 2255 | | // default: /* ??? */ invalid_instruction(op); break; |
| 2256 | | } |
| 2257 | | return RECOMPILE_UNIMPLEMENTED; |
| 2258 | | } |
| 2259 | | |
| 2260 | | |
| 2261 | | /*------------------------------------------------------------------ |
| 2262 | | recompile_special |
| 2263 | | ------------------------------------------------------------------*/ |
| 2264 | | |
| 2265 | | static UINT32 recompile_special1(drc_core *drc, UINT32 pc, UINT32 op) |
| 2266 | | { |
| 2267 | | emit_link link1, link2, link3; |
| 2268 | | int cycles; |
| 2269 | | |
| 2270 | | switch (op & 63) |
| 2271 | | { |
| 2272 | | case 0x00: /* SLL */ |
| 2273 | | if (RDREG != 0) |
| 2274 | | { |
| 2275 | | if (RTREG != 0) |
| 2276 | | { |
| 2277 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2278 | | if (SHIFT != 0) |
| 2279 | | emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT |
| 2280 | | emit_cdq(DRCTOP); // cdq |
| 2281 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2282 | | } |
| 2283 | | else |
| 2284 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2285 | | } |
| 2286 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2287 | | |
| 2288 | | case 0x01: /* MOVF - R5000*/ |
| 2289 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 2290 | | { |
| 2291 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 2292 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 2293 | | } |
| 2294 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 |
| 2295 | | emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip |
| 2296 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 2297 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2298 | | resolve_link(DRCTOP, &link1); // skip: |
| 2299 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2300 | | |
| 2301 | | case 0x02: /* SRL */ |
| 2302 | | if (RDREG != 0) |
| 2303 | | { |
| 2304 | | if (RTREG != 0) |
| 2305 | | { |
| 2306 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2307 | | if (SHIFT != 0) |
| 2308 | | emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT |
| 2309 | | emit_cdq(DRCTOP); // cdq |
| 2310 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2311 | | } |
| 2312 | | else |
| 2313 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2314 | | } |
| 2315 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2316 | | |
| 2317 | | case 0x03: /* SRA */ |
| 2318 | | if (RDREG != 0) |
| 2319 | | { |
| 2320 | | if (RTREG != 0) |
| 2321 | | { |
| 2322 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2323 | | if (SHIFT != 0) |
| 2324 | | emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT |
| 2325 | | emit_cdq(DRCTOP); // cdq |
| 2326 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2327 | | } |
| 2328 | | else |
| 2329 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2330 | | } |
| 2331 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2332 | | |
| 2333 | | case 0x04: /* SLLV */ |
| 2334 | | if (RDREG != 0) |
| 2335 | | { |
| 2336 | | if (RTREG != 0) |
| 2337 | | { |
| 2338 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2339 | | if (RSREG != 0) |
| 2340 | | { |
| 2341 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo |
| 2342 | | emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl |
| 2343 | | } |
| 2344 | | emit_cdq(DRCTOP); // cdq |
| 2345 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2346 | | } |
| 2347 | | else |
| 2348 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2349 | | } |
| 2350 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2351 | | |
| 2352 | | case 0x06: /* SRLV */ |
| 2353 | | if (RDREG != 0) |
| 2354 | | { |
| 2355 | | if (RTREG != 0) |
| 2356 | | { |
| 2357 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2358 | | if (RSREG != 0) |
| 2359 | | { |
| 2360 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo |
| 2361 | | emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl |
| 2362 | | } |
| 2363 | | emit_cdq(DRCTOP); // cdq |
| 2364 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2365 | | } |
| 2366 | | else |
| 2367 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2368 | | } |
| 2369 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2370 | | |
| 2371 | | case 0x07: /* SRAV */ |
| 2372 | | if (RDREG != 0) |
| 2373 | | { |
| 2374 | | if (RTREG != 0) |
| 2375 | | { |
| 2376 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2377 | | if (RSREG != 0) |
| 2378 | | { |
| 2379 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo |
| 2380 | | emit_sar_r32_cl(DRCTOP, REG_EAX); // sar eax,cl |
| 2381 | | } |
| 2382 | | emit_cdq(DRCTOP); // cdq |
| 2383 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2384 | | } |
| 2385 | | else |
| 2386 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2387 | | } |
| 2388 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2389 | | |
| 2390 | | case 0x08: /* JR */ |
| 2391 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2392 | | emit_mov_m32_r32(DRCTOP, MABS(&jr_temp), REG_EAX); // mov jr_temp,eax |
| 2393 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 2394 | | emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&jr_temp)); // mov edi,jr_temp |
| 2395 | | return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; |
| 2396 | | |
| 2397 | | case 0x09: /* JALR */ |
| 2398 | | if (RDREG != 0) |
| 2399 | | emit_mov_m64_imm32(DRCTOP, REGADDR(RDREG), pc + 8); // mov [rdreg],pc + 8 |
| 2400 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 2401 | | emit_mov_r32_m32(DRCTOP, REG_EDI, REGADDRLO(RSREG)); // mov edi,[rsreg].lo |
| 2402 | | return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; |
| 2403 | | |
| 2404 | | case 0x0a: /* MOVZ - R5000 */ |
| 2405 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 2406 | | { |
| 2407 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 2408 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 2409 | | } |
| 2410 | | if (RDREG != 0) |
| 2411 | | { |
| 2412 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2413 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 2414 | | emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 2415 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); |
| 2416 | | // mov [rdreg],[rsreg] |
| 2417 | | resolve_link(DRCTOP, &link1); // skip: |
| 2418 | | } |
| 2419 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2420 | | |
| 2421 | | case 0x0b: /* MOVN - R5000 */ |
| 2422 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 2423 | | { |
| 2424 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 2425 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 2426 | | } |
| 2427 | | if (RDREG != 0) |
| 2428 | | { |
| 2429 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2430 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 2431 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 2432 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); |
| 2433 | | // mov [rdreg],[rsreg] |
| 2434 | | resolve_link(DRCTOP, &link1); // skip: |
| 2435 | | } |
| 2436 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2437 | | |
| 2438 | | case 0x0c: /* SYSCALL */ |
| 2439 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_syscall_exception); // jmp generate_syscall_exception |
| 2440 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 2441 | | |
| 2442 | | case 0x0d: /* BREAK */ |
| 2443 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_break_exception); // jmp generate_break_exception |
| 2444 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; |
| 2445 | | |
| 2446 | | case 0x0f: /* SYNC */ |
| 2447 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2448 | | |
| 2449 | | case 0x10: /* MFHI */ |
| 2450 | | if (RDREG != 0) |
| 2451 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), HIADDR); // mov [rdreg],[hi] |
| 2452 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2453 | | |
| 2454 | | case 0x11: /* MTHI */ |
| 2455 | | emit_mov_m64_m64(DRCTOP, HIADDR, REGADDR(RSREG)); // mov [hi],[rsreg] |
| 2456 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2457 | | |
| 2458 | | case 0x12: /* MFLO */ |
| 2459 | | if (RDREG != 0) |
| 2460 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), LOADDR); // mov [rdreg],[lo] |
| 2461 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2462 | | |
| 2463 | | case 0x13: /* MTLO */ |
| 2464 | | emit_mov_m64_m64(DRCTOP, LOADDR, REGADDR(RSREG)); // mov [lo],[rsreg] |
| 2465 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2466 | | |
| 2467 | | case 0x14: /* DSLLV */ |
| 2468 | | if (RDREG != 0) |
| 2469 | | { |
| 2470 | | if (RTREG != 0) |
| 2471 | | { |
| 2472 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 2473 | | if (RSREG != 0) |
| 2474 | | { |
| 2475 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo |
| 2476 | | emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20 |
| 2477 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 2478 | | emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EAX); // mov edx,eax |
| 2479 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 2480 | | resolve_link(DRCTOP, &link1); // skip: |
| 2481 | | emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl |
| 2482 | | emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl |
| 2483 | | } |
| 2484 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2485 | | } |
| 2486 | | else |
| 2487 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2488 | | } |
| 2489 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2490 | | |
| 2491 | | case 0x16: /* DSRLV */ |
| 2492 | | if (RDREG != 0) |
| 2493 | | { |
| 2494 | | if (RTREG != 0) |
| 2495 | | { |
| 2496 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 2497 | | if (RSREG != 0) |
| 2498 | | { |
| 2499 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo |
| 2500 | | emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20 |
| 2501 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 2502 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx |
| 2503 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 2504 | | resolve_link(DRCTOP, &link1); // skip: |
| 2505 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl |
| 2506 | | emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl |
| 2507 | | } |
| 2508 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2509 | | } |
| 2510 | | else |
| 2511 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2512 | | } |
| 2513 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2514 | | |
| 2515 | | case 0x17: /* DSRAV */ |
| 2516 | | if (RDREG != 0) |
| 2517 | | { |
| 2518 | | if (RTREG != 0) |
| 2519 | | { |
| 2520 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 2521 | | if (RSREG != 0) |
| 2522 | | { |
| 2523 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo |
| 2524 | | emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20 |
| 2525 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 2526 | | emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx |
| 2527 | | emit_cdq(DRCTOP); // cdq |
| 2528 | | resolve_link(DRCTOP, &link1); // skip: |
| 2529 | | emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl |
| 2530 | | emit_sar_r32_cl(DRCTOP, REG_EDX); // sar edx,cl |
| 2531 | | } |
| 2532 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2533 | | } |
| 2534 | | else |
| 2535 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2536 | | } |
| 2537 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2538 | | |
| 2539 | | case 0x18: /* MULT */ |
| 2540 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo |
| 2541 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2542 | | emit_imul_r32(DRCTOP, REG_ECX); // imul ecx |
| 2543 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 2544 | | emit_cdq(DRCTOP); // cdq |
| 2545 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 2546 | | emit_pop_r32(DRCTOP, REG_EAX); // pop eax |
| 2547 | | emit_cdq(DRCTOP); // cdq |
| 2548 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 2549 | | return RECOMPILE_SUCCESSFUL_CP(4,4); |
| 2550 | | |
| 2551 | | case 0x19: /* MULTU */ |
| 2552 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo |
| 2553 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2554 | | emit_mul_r32(DRCTOP, REG_ECX); // mul ecx |
| 2555 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 2556 | | emit_cdq(DRCTOP); // cdq |
| 2557 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 2558 | | emit_pop_r32(DRCTOP, REG_EAX); // pop eax |
| 2559 | | emit_cdq(DRCTOP); // cdq |
| 2560 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 2561 | | return RECOMPILE_SUCCESSFUL_CP(4,4); |
| 2562 | | |
| 2563 | | case 0x1a: /* DIV */ |
| 2564 | | if (RTREG != 0) |
| 2565 | | { |
| 2566 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo |
| 2567 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2568 | | emit_cdq(DRCTOP); // cdq |
| 2569 | | emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0 |
| 2570 | | emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip |
| 2571 | | emit_idiv_r32(DRCTOP, REG_ECX); // idiv ecx |
| 2572 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 2573 | | emit_cdq(DRCTOP); // cdq |
| 2574 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 2575 | | emit_pop_r32(DRCTOP, REG_EAX); // pop eax |
| 2576 | | emit_cdq(DRCTOP); // cdq |
| 2577 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 2578 | | resolve_link(DRCTOP, &link1); // skip: |
| 2579 | | } |
| 2580 | | return RECOMPILE_SUCCESSFUL_CP(36,4); |
| 2581 | | |
| 2582 | | case 0x1b: /* DIVU */ |
| 2583 | | if (RTREG != 0) |
| 2584 | | { |
| 2585 | | emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo |
| 2586 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2587 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 2588 | | emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0 |
| 2589 | | emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip |
| 2590 | | emit_div_r32(DRCTOP, REG_ECX); // div ecx |
| 2591 | | emit_push_r32(DRCTOP, REG_EDX); // push edx |
| 2592 | | emit_cdq(DRCTOP); // cdq |
| 2593 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax |
| 2594 | | emit_pop_r32(DRCTOP, REG_EAX); // pop eax |
| 2595 | | emit_cdq(DRCTOP); // cdq |
| 2596 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax |
| 2597 | | resolve_link(DRCTOP, &link1); // skip: |
| 2598 | | } |
| 2599 | | return RECOMPILE_SUCCESSFUL_CP(36,4); |
| 2600 | | |
| 2601 | | case 0x1c: /* DMULT */ |
| 2602 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 2603 | | emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 |
| 2604 | | emit_jcc_short_link(DRCTOP, COND_GE, &link1); // jge skip1 |
| 2605 | | emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx |
| 2606 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 2607 | | emit_neg_r32(DRCTOP, REG_EAX); // neg eax |
| 2608 | | emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx |
| 2609 | | resolve_link(DRCTOP, &link1); // skip1: |
| 2610 | | emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp1), REG_EDX, REG_EAX); // mov [dmult_temp1],edx:eax |
| 2611 | | |
| 2612 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 2613 | | emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 |
| 2614 | | emit_jcc_short_link(DRCTOP, COND_GE, &link2); // jge skip2 |
| 2615 | | emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx |
| 2616 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 2617 | | emit_neg_r32(DRCTOP, REG_EAX); // neg eax |
| 2618 | | emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx |
| 2619 | | resolve_link(DRCTOP, &link2); // skip2: |
| 2620 | | emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp2), REG_EDX, REG_EAX); // mov [dmult_temp2],edx:eax |
| 2621 | | |
| 2622 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo |
| 2623 | | emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo |
| 2624 | | emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx |
| 2625 | | emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx |
| 2626 | | emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax |
| 2627 | | |
| 2628 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi |
| 2629 | | emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo |
| 2630 | | emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax |
| 2631 | | emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx |
| 2632 | | |
| 2633 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo |
| 2634 | | emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi |
| 2635 | | emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax |
| 2636 | | emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx |
| 2637 | | emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx |
| 2638 | | |
| 2639 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi |
| 2640 | | emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi |
| 2641 | | emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax |
| 2642 | | emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0 |
| 2643 | | emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx |
| 2644 | | emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx |
| 2645 | | |
| 2646 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 2647 | | emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // xor eax,[rtreg].hi |
| 2648 | | emit_jcc_short_link(DRCTOP, COND_NS, &link3); // jns noflip |
| 2649 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 2650 | | emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx |
| 2651 | | emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx |
| 2652 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 2653 | | emit_sub_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // sub eax,[lo].lo |
| 2654 | | emit_sbb_r32_m32(DRCTOP, REG_EBX, LOADDRHI); // sbb ebx,[lo].hi |
| 2655 | | emit_sbb_r32_m32(DRCTOP, REG_ECX, HIADDRLO); // sbb ecx,[hi].lo |
| 2656 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, HIADDRHI); // sbb edx,[hi].hi |
| 2657 | | emit_mov_m64_r64(DRCTOP, LOADDR, REG_EBX, REG_EAX); // mov [lo],ebx:eax |
| 2658 | | emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_ECX); // mov [hi],edx:ecx |
| 2659 | | resolve_link(DRCTOP, &link3); // noflip: |
| 2660 | | return RECOMPILE_SUCCESSFUL_CP(8,4); |
| 2661 | | |
| 2662 | | case 0x1d: /* DMULTU */ |
| 2663 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2664 | | emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo |
| 2665 | | emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx |
| 2666 | | emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx |
| 2667 | | emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax |
| 2668 | | |
| 2669 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 2670 | | emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo |
| 2671 | | emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax |
| 2672 | | emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx |
| 2673 | | |
| 2674 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2675 | | emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi |
| 2676 | | emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax |
| 2677 | | emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx |
| 2678 | | emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx |
| 2679 | | |
| 2680 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 2681 | | emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi |
| 2682 | | emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax |
| 2683 | | emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0 |
| 2684 | | emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx |
| 2685 | | emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx |
| 2686 | | return RECOMPILE_SUCCESSFUL_CP(8,4); |
| 2687 | | |
| 2688 | | case 0x1e: /* DDIV */ |
| 2689 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 2690 | | emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg] |
| 2691 | | emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg] |
| 2692 | | emit_call(DRCTOP, (x86code *)ddiv); // call ddiv |
| 2693 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2694 | | return RECOMPILE_SUCCESSFUL_CP(68,4); |
| 2695 | | |
| 2696 | | case 0x1f: /* DDIVU */ |
| 2697 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 2698 | | emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg] |
| 2699 | | emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg] |
| 2700 | | emit_call(DRCTOP, (x86code *)ddivu); // call ddivu |
| 2701 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 2702 | | return RECOMPILE_SUCCESSFUL_CP(68,4); |
| 2703 | | } |
| 2704 | | |
| 2705 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 2706 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 2707 | | } |
| 2708 | | |
| 2709 | | static UINT32 recompile_special2(drc_core *drc, UINT32 pc, UINT32 op) |
| 2710 | | { |
| 2711 | | emit_link link1, link2, link3; |
| 2712 | | |
| 2713 | | switch (op & 63) |
| 2714 | | { |
| 2715 | | case 0x20: /* ADD */ |
| 2716 | | if (RSREG != 0 && RTREG != 0) |
| 2717 | | { |
| 2718 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2719 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo |
| 2720 | | emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception |
| 2721 | | if (RDREG != 0) |
| 2722 | | { |
| 2723 | | emit_cdq(DRCTOP); // cdq |
| 2724 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2725 | | } |
| 2726 | | } |
| 2727 | | else if (RDREG != 0) |
| 2728 | | { |
| 2729 | | if (RSREG != 0) |
| 2730 | | { |
| 2731 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2732 | | emit_cdq(DRCTOP); // cdq |
| 2733 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2734 | | } |
| 2735 | | else if (RTREG != 0) |
| 2736 | | { |
| 2737 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2738 | | emit_cdq(DRCTOP); // cdq |
| 2739 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2740 | | } |
| 2741 | | else |
| 2742 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2743 | | } |
| 2744 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 2745 | | |
| 2746 | | case 0x21: /* ADDU */ |
| 2747 | | if (RDREG != 0) |
| 2748 | | { |
| 2749 | | if (RSREG != 0 && RTREG != 0) |
| 2750 | | { |
| 2751 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2752 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo |
| 2753 | | emit_cdq(DRCTOP); // cdq |
| 2754 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2755 | | } |
| 2756 | | else if (RSREG != 0) |
| 2757 | | { |
| 2758 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2759 | | emit_cdq(DRCTOP); // cdq |
| 2760 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2761 | | } |
| 2762 | | else if (RTREG != 0) |
| 2763 | | { |
| 2764 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2765 | | emit_cdq(DRCTOP); // cdq |
| 2766 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2767 | | } |
| 2768 | | else |
| 2769 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2770 | | } |
| 2771 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2772 | | |
| 2773 | | case 0x22: /* SUB */ |
| 2774 | | if (RSREG != 0 && RTREG != 0) |
| 2775 | | { |
| 2776 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2777 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 2778 | | emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception |
| 2779 | | if (RDREG != 0) |
| 2780 | | { |
| 2781 | | emit_cdq(DRCTOP); // cdq |
| 2782 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2783 | | } |
| 2784 | | } |
| 2785 | | else if (RDREG != 0) |
| 2786 | | { |
| 2787 | | if (RSREG != 0) |
| 2788 | | { |
| 2789 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2790 | | emit_cdq(DRCTOP); // cdq |
| 2791 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2792 | | } |
| 2793 | | else if (RTREG != 0) |
| 2794 | | { |
| 2795 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2796 | | emit_neg_r32(DRCTOP, REG_EAX); // neg eax |
| 2797 | | emit_cdq(DRCTOP); // cdq |
| 2798 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2799 | | } |
| 2800 | | else |
| 2801 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2802 | | } |
| 2803 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 2804 | | |
| 2805 | | case 0x23: /* SUBU */ |
| 2806 | | if (RDREG != 0) |
| 2807 | | { |
| 2808 | | if (RSREG != 0 && RTREG != 0) |
| 2809 | | { |
| 2810 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2811 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 2812 | | emit_cdq(DRCTOP); // cdq |
| 2813 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2814 | | } |
| 2815 | | else if (RSREG != 0) |
| 2816 | | { |
| 2817 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2818 | | emit_cdq(DRCTOP); // cdq |
| 2819 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2820 | | } |
| 2821 | | else if (RTREG != 0) |
| 2822 | | { |
| 2823 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 2824 | | emit_neg_r32(DRCTOP, REG_EAX); // neg eax |
| 2825 | | emit_cdq(DRCTOP); // cdq |
| 2826 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2827 | | } |
| 2828 | | else |
| 2829 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2830 | | } |
| 2831 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2832 | | |
| 2833 | | case 0x24: /* AND */ |
| 2834 | | if (RDREG != 0) |
| 2835 | | { |
| 2836 | | if (RSREG != 0 && RTREG != 0) |
| 2837 | | { |
| 2838 | | if (USE_SSE) |
| 2839 | | { |
| 2840 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg] |
| 2841 | | emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg] |
| 2842 | | emit_andpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // andpd xmm0,xmm1 |
| 2843 | | emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0 |
| 2844 | | } |
| 2845 | | else |
| 2846 | | { |
| 2847 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); |
| 2848 | | // mov edx:eax,[rsreg] |
| 2849 | | emit_and_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // and eax,[rtreg].lo |
| 2850 | | emit_and_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // and edx,[rtreg].hi |
| 2851 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2852 | | } |
| 2853 | | } |
| 2854 | | else |
| 2855 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2856 | | } |
| 2857 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2858 | | |
| 2859 | | case 0x25: /* OR */ |
| 2860 | | if (RDREG != 0) |
| 2861 | | { |
| 2862 | | if (RSREG != 0 && RTREG != 0) |
| 2863 | | { |
| 2864 | | if (USE_SSE) |
| 2865 | | { |
| 2866 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg] |
| 2867 | | emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg] |
| 2868 | | emit_orpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // orpd xmm0,xmm1 |
| 2869 | | emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0 |
| 2870 | | } |
| 2871 | | else |
| 2872 | | { |
| 2873 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); |
| 2874 | | // mov edx:eax,[rsreg] |
| 2875 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo |
| 2876 | | emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi |
| 2877 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2878 | | } |
| 2879 | | } |
| 2880 | | else if (RSREG != 0) |
| 2881 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] |
| 2882 | | else if (RTREG != 0) |
| 2883 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg] |
| 2884 | | else |
| 2885 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2886 | | } |
| 2887 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2888 | | |
| 2889 | | case 0x26: /* XOR */ |
| 2890 | | if (RDREG != 0) |
| 2891 | | { |
| 2892 | | if (RSREG != 0 && RTREG != 0) |
| 2893 | | { |
| 2894 | | if (USE_SSE) |
| 2895 | | { |
| 2896 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg] |
| 2897 | | emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg] |
| 2898 | | emit_xorpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // xorpd xmm0,xmm1 |
| 2899 | | emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0 |
| 2900 | | } |
| 2901 | | else |
| 2902 | | { |
| 2903 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); |
| 2904 | | // mov edx:eax,[rsreg] |
| 2905 | | emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // xor eax,[rtreg].lo |
| 2906 | | emit_xor_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // xor edx,[rtreg].hi |
| 2907 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2908 | | } |
| 2909 | | } |
| 2910 | | else if (RSREG != 0) |
| 2911 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] |
| 2912 | | else if (RTREG != 0) |
| 2913 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg] |
| 2914 | | else |
| 2915 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 2916 | | } |
| 2917 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2918 | | |
| 2919 | | case 0x27: /* NOR */ |
| 2920 | | if (RDREG != 0) |
| 2921 | | { |
| 2922 | | if (RSREG != 0 && RTREG != 0) |
| 2923 | | { |
| 2924 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 2925 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo |
| 2926 | | emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi |
| 2927 | | emit_not_r32(DRCTOP, REG_EDX); // not edx |
| 2928 | | emit_not_r32(DRCTOP, REG_EAX); // not eax |
| 2929 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2930 | | } |
| 2931 | | else if (RSREG != 0) |
| 2932 | | { |
| 2933 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 2934 | | emit_not_r32(DRCTOP, REG_EDX); // not edx |
| 2935 | | emit_not_r32(DRCTOP, REG_EAX); // not eax |
| 2936 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2937 | | } |
| 2938 | | else if (RTREG != 0) |
| 2939 | | { |
| 2940 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 2941 | | emit_not_r32(DRCTOP, REG_EDX); // not edx |
| 2942 | | emit_not_r32(DRCTOP, REG_EAX); // not eax |
| 2943 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 2944 | | } |
| 2945 | | else |
| 2946 | | { |
| 2947 | | emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), ~0); // mov [rtreg].lo,~0 |
| 2948 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), ~0); // mov [rtreg].hi,~0 |
| 2949 | | } |
| 2950 | | } |
| 2951 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2952 | | |
| 2953 | | case 0x2a: /* SLT */ |
| 2954 | | if (RDREG != 0) |
| 2955 | | { |
| 2956 | | if (RSREG != 0) |
| 2957 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 2958 | | else |
| 2959 | | { |
| 2960 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 2961 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 2962 | | } |
| 2963 | | if (RTREG != 0) |
| 2964 | | { |
| 2965 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 2966 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].lo |
| 2967 | | } |
| 2968 | | emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31 |
| 2969 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EDX); // mov [rdreg].lo,edx |
| 2970 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0 |
| 2971 | | } |
| 2972 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2973 | | |
| 2974 | | case 0x2b: /* SLTU */ |
| 2975 | | if (RDREG != 0) |
| 2976 | | { |
| 2977 | | emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx |
| 2978 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 2979 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 2980 | | emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb setit |
| 2981 | | emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skipit |
| 2982 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 2983 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 2984 | | emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skipit |
| 2985 | | resolve_link(DRCTOP, &link1); // setit: |
| 2986 | | emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1 |
| 2987 | | resolve_link(DRCTOP, &link2); // skipit: |
| 2988 | | resolve_link(DRCTOP, &link3); // skipit: |
| 2989 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_ECX); // mov [rdreg].lo,ecx |
| 2990 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0 |
| 2991 | | } |
| 2992 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 2993 | | |
| 2994 | | case 0x2c: /* DADD */ |
| 2995 | | if (RSREG != 0 && RTREG != 0) |
| 2996 | | { |
| 2997 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 2998 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo |
| 2999 | | emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi |
| 3000 | | emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception |
| 3001 | | if (RDREG != 0) |
| 3002 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3003 | | } |
| 3004 | | else if (RDREG != 0) |
| 3005 | | { |
| 3006 | | if (RSREG != 0) |
| 3007 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] |
| 3008 | | else if (RTREG != 0) |
| 3009 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg] |
| 3010 | | else |
| 3011 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3012 | | } |
| 3013 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3014 | | |
| 3015 | | case 0x2d: /* DADDU */ |
| 3016 | | if (RDREG != 0) |
| 3017 | | { |
| 3018 | | if (RSREG != 0 && RTREG != 0) |
| 3019 | | { |
| 3020 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3021 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo |
| 3022 | | emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi |
| 3023 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3024 | | } |
| 3025 | | else if (RSREG != 0) |
| 3026 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); |
| 3027 | | // mov [rdreg],[rsreg] |
| 3028 | | else if (RTREG != 0) |
| 3029 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); |
| 3030 | | // mov [rdreg],[rtreg] |
| 3031 | | else |
| 3032 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3033 | | } |
| 3034 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3035 | | |
| 3036 | | case 0x2e: /* DSUB */ |
| 3037 | | if (RSREG != 0 && RTREG != 0) |
| 3038 | | { |
| 3039 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3040 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 3041 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi |
| 3042 | | emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception |
| 3043 | | if (RDREG != 0) |
| 3044 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3045 | | } |
| 3046 | | else if (RDREG != 0) |
| 3047 | | { |
| 3048 | | if (RSREG != 0) |
| 3049 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] |
| 3050 | | else if (RTREG != 0) |
| 3051 | | { |
| 3052 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3053 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 3054 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 3055 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi |
| 3056 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3057 | | } |
| 3058 | | else |
| 3059 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3060 | | } |
| 3061 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3062 | | |
| 3063 | | case 0x2f: /* DSUBU */ |
| 3064 | | if (RDREG != 0) |
| 3065 | | { |
| 3066 | | if (RSREG != 0 && RTREG != 0) |
| 3067 | | { |
| 3068 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3069 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 3070 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi |
| 3071 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3072 | | } |
| 3073 | | else if (RSREG != 0) |
| 3074 | | emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] |
| 3075 | | else if (RTREG != 0) |
| 3076 | | { |
| 3077 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3078 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 3079 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 3080 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi |
| 3081 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3082 | | } |
| 3083 | | else |
| 3084 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3085 | | } |
| 3086 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3087 | | |
| 3088 | | case 0x30: /* TGE */ |
| 3089 | | if (RSREG != 0) |
| 3090 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3091 | | else |
| 3092 | | { |
| 3093 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 3094 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3095 | | } |
| 3096 | | if (RTREG != 0) |
| 3097 | | { |
| 3098 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 3099 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi |
| 3100 | | } |
| 3101 | | else |
| 3102 | | emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 |
| 3103 | | emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception |
| 3104 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3105 | | |
| 3106 | | case 0x31: /* TGEU */ |
| 3107 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 3108 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 3109 | | emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception |
| 3110 | | emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skipit |
| 3111 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 3112 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 3113 | | emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception |
| 3114 | | resolve_link(DRCTOP, &link1); // skipit: |
| 3115 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3116 | | |
| 3117 | | case 0x32: /* TLT */ |
| 3118 | | if (RSREG != 0) |
| 3119 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3120 | | else |
| 3121 | | { |
| 3122 | | emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx |
| 3123 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3124 | | } |
| 3125 | | if (RTREG != 0) |
| 3126 | | { |
| 3127 | | emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo |
| 3128 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi |
| 3129 | | } |
| 3130 | | else |
| 3131 | | emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 |
| 3132 | | emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception |
| 3133 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3134 | | |
| 3135 | | case 0x33: /* TLTU */ |
| 3136 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 3137 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 3138 | | emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception |
| 3139 | | emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skipit |
| 3140 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 3141 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 3142 | | emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception |
| 3143 | | resolve_link(DRCTOP, &link1); // skipit: |
| 3144 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3145 | | |
| 3146 | | case 0x34: /* TEQ */ |
| 3147 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 3148 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 3149 | | emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skipit |
| 3150 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 3151 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 3152 | | emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception |
| 3153 | | resolve_link(DRCTOP, &link1); // skipit: |
| 3154 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3155 | | |
| 3156 | | case 0x36: /* TNE */ |
| 3157 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi |
| 3158 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi |
| 3159 | | emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skipit |
| 3160 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo |
| 3161 | | emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo |
| 3162 | | emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception |
| 3163 | | resolve_link(DRCTOP, &link1); // skipit: |
| 3164 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3165 | | |
| 3166 | | case 0x38: /* DSLL */ |
| 3167 | | if (RDREG != 0) |
| 3168 | | { |
| 3169 | | if (RTREG != 0) |
| 3170 | | { |
| 3171 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 3172 | | if (SHIFT != 0) |
| 3173 | | { |
| 3174 | | emit_shld_r32_r32_imm(DRCTOP, REG_EDX, REG_EAX, SHIFT); // shld edx,eax,SHIFT |
| 3175 | | emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT |
| 3176 | | } |
| 3177 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3178 | | } |
| 3179 | | else |
| 3180 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3181 | | } |
| 3182 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3183 | | |
| 3184 | | case 0x3a: /* DSRL */ |
| 3185 | | if (RDREG != 0) |
| 3186 | | { |
| 3187 | | if (RTREG != 0) |
| 3188 | | { |
| 3189 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 3190 | | if (SHIFT != 0) |
| 3191 | | { |
| 3192 | | emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT |
| 3193 | | emit_shr_r32_imm(DRCTOP, REG_EDX, SHIFT); // shr edx,SHIFT |
| 3194 | | } |
| 3195 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3196 | | } |
| 3197 | | else |
| 3198 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3199 | | } |
| 3200 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3201 | | |
| 3202 | | case 0x3b: /* DSRA */ |
| 3203 | | if (RDREG != 0) |
| 3204 | | { |
| 3205 | | if (RTREG != 0) |
| 3206 | | { |
| 3207 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] |
| 3208 | | if (SHIFT != 0) |
| 3209 | | { |
| 3210 | | emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT |
| 3211 | | emit_sar_r32_imm(DRCTOP, REG_EDX, SHIFT); // sar edx,SHIFT |
| 3212 | | } |
| 3213 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3214 | | } |
| 3215 | | else |
| 3216 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3217 | | } |
| 3218 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3219 | | |
| 3220 | | case 0x3c: /* DSLL32 */ |
| 3221 | | if (RDREG != 0) |
| 3222 | | { |
| 3223 | | if (RTREG != 0) |
| 3224 | | { |
| 3225 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 3226 | | if (SHIFT != 0) |
| 3227 | | emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT |
| 3228 | | emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), 0); // mov [rdreg].lo,0 |
| 3229 | | emit_mov_m32_r32(DRCTOP, REGADDRHI(RDREG), REG_EAX); // mov [rdreg].hi,eax |
| 3230 | | } |
| 3231 | | else |
| 3232 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3233 | | } |
| 3234 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3235 | | |
| 3236 | | case 0x3e: /* DSRL32 */ |
| 3237 | | if (RDREG != 0) |
| 3238 | | { |
| 3239 | | if (RTREG != 0) |
| 3240 | | { |
| 3241 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi |
| 3242 | | if (SHIFT != 0) |
| 3243 | | emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT |
| 3244 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0 |
| 3245 | | emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EAX); // mov [rdreg].lo,eax |
| 3246 | | } |
| 3247 | | else |
| 3248 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3249 | | } |
| 3250 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3251 | | |
| 3252 | | case 0x3f: /* DSRA32 */ |
| 3253 | | if (RDREG != 0) |
| 3254 | | { |
| 3255 | | if (RTREG != 0) |
| 3256 | | { |
| 3257 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi |
| 3258 | | emit_cdq(DRCTOP); // cdq |
| 3259 | | if (SHIFT != 0) |
| 3260 | | emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT |
| 3261 | | emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax |
| 3262 | | } |
| 3263 | | else |
| 3264 | | emit_zero_m64(DRCTOP, REGADDR(RDREG)); |
| 3265 | | } |
| 3266 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3267 | | } |
| 3268 | | |
| 3269 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 3270 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 3271 | | } |
| 3272 | | |
| 3273 | | |
| 3274 | | static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op) |
| 3275 | | { |
| 3276 | | if (!(op & 32)) |
| 3277 | | return recompile_special1(drc, pc, op); |
| 3278 | | else |
| 3279 | | return recompile_special2(drc, pc, op); |
| 3280 | | } |
| 3281 | | |
| 3282 | | |
| 3283 | | /*------------------------------------------------------------------ |
| 3284 | | recompile_regimm |
| 3285 | | ------------------------------------------------------------------*/ |
| 3286 | | |
| 3287 | | static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op) |
| 3288 | | { |
| 3289 | | emit_link link1; |
| 3290 | | int cycles; |
| 3291 | | |
| 3292 | | switch (RTREG) |
| 3293 | | { |
| 3294 | | case 0x00: /* BLTZ */ |
| 3295 | | if (RSREG == 0) |
| 3296 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3297 | | else |
| 3298 | | { |
| 3299 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3300 | | emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip |
| 3301 | | } |
| 3302 | | |
| 3303 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3304 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3305 | | resolve_link(DRCTOP, &link1); // skip: |
| 3306 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3307 | | |
| 3308 | | case 0x01: /* BGEZ */ |
| 3309 | | if (RSREG == 0) |
| 3310 | | { |
| 3311 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3312 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3313 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 3314 | | } |
| 3315 | | else |
| 3316 | | { |
| 3317 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3318 | | emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip |
| 3319 | | } |
| 3320 | | |
| 3321 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3322 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3323 | | resolve_link(DRCTOP, &link1); // skip: |
| 3324 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3325 | | |
| 3326 | | case 0x02: /* BLTZL */ |
| 3327 | | if (RSREG == 0) |
| 3328 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3329 | | else |
| 3330 | | { |
| 3331 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3332 | | emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip |
| 3333 | | } |
| 3334 | | |
| 3335 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3336 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3337 | | resolve_link(DRCTOP, &link1); // skip: |
| 3338 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 3339 | | |
| 3340 | | case 0x03: /* BGEZL */ |
| 3341 | | if (RSREG == 0) |
| 3342 | | { |
| 3343 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3344 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3345 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 3346 | | } |
| 3347 | | else |
| 3348 | | { |
| 3349 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3350 | | emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip |
| 3351 | | } |
| 3352 | | |
| 3353 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3354 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3355 | | resolve_link(DRCTOP, &link1); // skip: |
| 3356 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 3357 | | |
| 3358 | | case 0x08: /* TGEI */ |
| 3359 | | if (RSREG != 0) |
| 3360 | | { |
| 3361 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3362 | | emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo |
| 3363 | | emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo |
| 3364 | | emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception |
| 3365 | | } |
| 3366 | | else |
| 3367 | | { |
| 3368 | | if (0 >= SIMMVAL) |
| 3369 | | emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception |
| 3370 | | } |
| 3371 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3372 | | |
| 3373 | | case 0x09: /* TGEIU */ |
| 3374 | | if (RSREG != 0) |
| 3375 | | { |
| 3376 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); |
| 3377 | | // cmp [rsreg].hi,upper |
| 3378 | | emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception |
| 3379 | | emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skip |
| 3380 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower |
| 3381 | | emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception |
| 3382 | | resolve_link(DRCTOP, &link1); // skip: |
| 3383 | | } |
| 3384 | | else |
| 3385 | | { |
| 3386 | | if (0 >= SIMMVAL) |
| 3387 | | emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception |
| 3388 | | } |
| 3389 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3390 | | |
| 3391 | | case 0x0a: /* TLTI */ |
| 3392 | | if (RSREG != 0) |
| 3393 | | { |
| 3394 | | emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] |
| 3395 | | emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo |
| 3396 | | emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo |
| 3397 | | emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception |
| 3398 | | } |
| 3399 | | else |
| 3400 | | { |
| 3401 | | if (0 < SIMMVAL) |
| 3402 | | emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception |
| 3403 | | } |
| 3404 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3405 | | |
| 3406 | | case 0x0b: /* TLTIU */ |
| 3407 | | if (RSREG != 0) |
| 3408 | | { |
| 3409 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); |
| 3410 | | // cmp [rsreg].hi,upper |
| 3411 | | emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception |
| 3412 | | emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skip |
| 3413 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower |
| 3414 | | emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception |
| 3415 | | resolve_link(DRCTOP, &link1); // skip: |
| 3416 | | } |
| 3417 | | else |
| 3418 | | { |
| 3419 | | emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const |
| 3420 | | emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) |
| 3421 | | } |
| 3422 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3423 | | |
| 3424 | | case 0x0c: /* TEQI */ |
| 3425 | | if (RSREG != 0) |
| 3426 | | { |
| 3427 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); |
| 3428 | | // cmp [rsreg].hi,upper |
| 3429 | | emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skip |
| 3430 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower |
| 3431 | | emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception |
| 3432 | | resolve_link(DRCTOP, &link1); // skip: |
| 3433 | | } |
| 3434 | | else |
| 3435 | | { |
| 3436 | | if (0 == SIMMVAL) |
| 3437 | | emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception |
| 3438 | | } |
| 3439 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3440 | | |
| 3441 | | case 0x0e: /* TNEI */ |
| 3442 | | if (RSREG != 0) |
| 3443 | | { |
| 3444 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); |
| 3445 | | // cmp [rsreg].hi,upper |
| 3446 | | emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip |
| 3447 | | emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower |
| 3448 | | emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception |
| 3449 | | resolve_link(DRCTOP, &link1); // skip: |
| 3450 | | } |
| 3451 | | else |
| 3452 | | { |
| 3453 | | if (0 != SIMMVAL) |
| 3454 | | emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception |
| 3455 | | } |
| 3456 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; |
| 3457 | | |
| 3458 | | case 0x10: /* BLTZAL */ |
| 3459 | | if (RSREG == 0) |
| 3460 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3461 | | else |
| 3462 | | { |
| 3463 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3464 | | emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip |
| 3465 | | } |
| 3466 | | emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 |
| 3467 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3468 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3469 | | resolve_link(DRCTOP, &link1); // skip: |
| 3470 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3471 | | |
| 3472 | | case 0x11: /* BGEZAL */ |
| 3473 | | if (RSREG == 0) |
| 3474 | | { |
| 3475 | | emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 |
| 3476 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3477 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3478 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 3479 | | } |
| 3480 | | else |
| 3481 | | { |
| 3482 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3483 | | emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip |
| 3484 | | } |
| 3485 | | |
| 3486 | | emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 |
| 3487 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3488 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3489 | | resolve_link(DRCTOP, &link1); // skip: |
| 3490 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3491 | | |
| 3492 | | case 0x12: /* BLTZALL */ |
| 3493 | | if (RSREG == 0) |
| 3494 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3495 | | else |
| 3496 | | { |
| 3497 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3498 | | emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip |
| 3499 | | } |
| 3500 | | |
| 3501 | | emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 |
| 3502 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3503 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3504 | | resolve_link(DRCTOP, &link1); // skip: |
| 3505 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 3506 | | |
| 3507 | | case 0x13: /* BGEZALL */ |
| 3508 | | if (RSREG == 0) |
| 3509 | | { |
| 3510 | | emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 |
| 3511 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3512 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3513 | | return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; |
| 3514 | | } |
| 3515 | | else |
| 3516 | | { |
| 3517 | | emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 |
| 3518 | | emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip |
| 3519 | | } |
| 3520 | | |
| 3521 | | emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 |
| 3522 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3523 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3524 | | resolve_link(DRCTOP, &link1); // skip: |
| 3525 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 3526 | | } |
| 3527 | | |
| 3528 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 3529 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 3530 | | } |
| 3531 | | |
| 3532 | | |
| 3533 | | |
| 3534 | | /*************************************************************************** |
| 3535 | | COP0 RECOMPILATION |
| 3536 | | ***************************************************************************/ |
| 3537 | | |
| 3538 | | /*------------------------------------------------------------------ |
| 3539 | | recompile_set_cop0_reg |
| 3540 | | ------------------------------------------------------------------*/ |
| 3541 | | |
| 3542 | | static UINT32 recompile_set_cop0_reg(drc_core *drc, UINT8 reg) |
| 3543 | | { |
| 3544 | | emit_link link1; |
| 3545 | | |
| 3546 | | switch (reg) |
| 3547 | | { |
| 3548 | | case COP0_Cause: |
| 3549 | | emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Cause)); // mov ebx,[COP0_Cause] |
| 3550 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00 |
| 3551 | | emit_and_r32_imm(DRCTOP, REG_EBX, 0xfc00); // and ebx,0xfc00 |
| 3552 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 3553 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax |
| 3554 | | emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status] |
| 3555 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_SW_INTERRUPTS; |
| 3556 | | |
| 3557 | | case COP0_Status: |
| 3558 | | emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Status)); // mov ebx,[COP0_Status] |
| 3559 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax |
| 3560 | | emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EAX); // xor ebx,eax |
| 3561 | | /* |
| 3562 | | #ifdef ENABLE_DEBUGGER |
| 3563 | | _test_r32_imm(REG_EAX, 0xe0); // test eax,0xe0 |
| 3564 | | _jcc_short_link(COND_Z, &link1); // jz skip |
| 3565 | | _sub_r32_imm(REG_ESP, 4); // sub esp,4 |
| 3566 | | _push_r32(REG_EAX); // push eax |
| 3567 | | _push_imm("System set 64-bit addressing mode, SR=%08X"); // push <string> |
| 3568 | | _call(mame_printf_debug); // call mame_printf_debug |
| 3569 | | _call(mame_debug_break); // call mame_debug_break |
| 3570 | | _add_r32_imm(REG_ESP, 12); // add esp,12 |
| 3571 | | _resolve_link(&link1); // skip: |
| 3572 | | #endif |
| 3573 | | */ |
| 3574 | | emit_test_r32_imm(DRCTOP, REG_EBX, 0x8000); // test ebx,0x8000 |
| 3575 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 3576 | | append_update_cycle_counting(drc); // update cycle counting |
| 3577 | | resolve_link(DRCTOP, &link1); // skip: |
| 3578 | | return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; |
| 3579 | | |
| 3580 | | case COP0_Count: |
| 3581 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [COP0_Count],eax |
| 3582 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 3583 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 3584 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 3585 | | emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles); // call activecpu_gettotalcycles |
| 3586 | | emit_pop_r32(DRCTOP, REG_EBX); // pop ebx |
| 3587 | | emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8 |
| 3588 | | emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx |
| 3589 | | emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0 |
| 3590 | | emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx |
| 3591 | | emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0 |
| 3592 | | emit_mov_m64_r64(DRCTOP, MABS(&mips3.core->count_zero_time), REG_EDX, REG_EAX); // mov [mips3.core->count_zero_time],edx:eax |
| 3593 | | append_update_cycle_counting(drc); // update cycle counting |
| 3594 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3595 | | |
| 3596 | | case COP0_Compare: |
| 3597 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [COP0_Compare],eax |
| 3598 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [COP0_Cause],~0x8000 |
| 3599 | | append_update_cycle_counting(drc); // update cycle counting |
| 3600 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3601 | | |
| 3602 | | case COP0_PRId: |
| 3603 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3604 | | |
| 3605 | | case COP0_Config: |
| 3606 | | emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Config)); // mov ebx,[COP0_Cause] |
| 3607 | | emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007 |
| 3608 | | emit_and_r32_imm(DRCTOP, REG_EBX, ~0x0007); // and ebx,~0x0007 |
| 3609 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 3610 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [COP0_Cause],eax |
| 3611 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3612 | | |
| 3613 | | default: |
| 3614 | | emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov [reg],eax |
| 3615 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3616 | | } |
| 3617 | | return RECOMPILE_UNIMPLEMENTED; |
| 3618 | | } |
| 3619 | | |
| 3620 | | |
| 3621 | | /*------------------------------------------------------------------ |
| 3622 | | recompile_get_cop0_reg |
| 3623 | | ------------------------------------------------------------------*/ |
| 3624 | | |
| 3625 | | static UINT32 recompile_get_cop0_reg(drc_core *drc, UINT8 reg) |
| 3626 | | { |
| 3627 | | emit_link link1; |
| 3628 | | |
| 3629 | | switch (reg) |
| 3630 | | { |
| 3631 | | case COP0_Count: |
| 3632 | | emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24 |
| 3633 | | emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg |
| 3634 | | emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp |
| 3635 | | resolve_link(DRCTOP, &link1); // notneg: |
| 3636 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 3637 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12 |
| 3638 | | emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles); // call activecpu_gettotalcycles |
| 3639 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 3640 | | emit_sub_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->count_zero_time))); // sub eax,[mips3.core->count_zero_time+0] |
| 3641 | | emit_sbb_r32_m32(DRCTOP, REG_EDX, MABS(HI(&mips3.core->count_zero_time))); // sbb edx,[mips3.core->count_zero_time+4] |
| 3642 | | emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, 1); // shrd eax,edx,1 |
| 3643 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3644 | | |
| 3645 | | case COP0_Cause: |
| 3646 | | emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24 |
| 3647 | | emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg |
| 3648 | | emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp |
| 3649 | | resolve_link(DRCTOP, &link1); // notneg: |
| 3650 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg] |
| 3651 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3652 | | |
| 3653 | | default: |
| 3654 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg] |
| 3655 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3656 | | } |
| 3657 | | return RECOMPILE_UNIMPLEMENTED; |
| 3658 | | } |
| 3659 | | |
| 3660 | | |
| 3661 | | /*------------------------------------------------------------------ |
| 3662 | | recompile_cop0 |
| 3663 | | ------------------------------------------------------------------*/ |
| 3664 | | |
| 3665 | | static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op) |
| 3666 | | { |
| 3667 | | emit_link checklink; |
| 3668 | | UINT32 result; |
| 3669 | | |
| 3670 | | if (mips3.drcoptions & MIPS3DRC_STRICT_COP0) |
| 3671 | | { |
| 3672 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [COP0_Status],SR_KSU_MASK |
| 3673 | | emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay |
| 3674 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [COP0_Status],SR_COP0 |
| 3675 | | emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception |
| 3676 | | resolve_link(DRCTOP, &checklink); // okay: |
| 3677 | | } |
| 3678 | | |
| 3679 | | switch (RSREG) |
| 3680 | | { |
| 3681 | | case 0x00: /* MFCz */ |
| 3682 | | result = RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3683 | | if (RTREG != 0) |
| 3684 | | { |
| 3685 | | result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg |
| 3686 | | emit_cdq(DRCTOP); // cdq |
| 3687 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 3688 | | } |
| 3689 | | return result; |
| 3690 | | |
| 3691 | | case 0x01: /* DMFCz */ |
| 3692 | | result = RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3693 | | if (RTREG != 0) |
| 3694 | | { |
| 3695 | | result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg |
| 3696 | | emit_cdq(DRCTOP); // cdq |
| 3697 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 3698 | | } |
| 3699 | | return result; |
| 3700 | | |
| 3701 | | case 0x02: /* CFCz */ |
| 3702 | | if (RTREG != 0) |
| 3703 | | { |
| 3704 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CCR0ADDR(RDREG)); // mov eax,[mips3.core->ccr[0][rdreg]] |
| 3705 | | emit_cdq(DRCTOP); // cdq |
| 3706 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax |
| 3707 | | } |
| 3708 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3709 | | |
| 3710 | | case 0x04: /* MTCz */ |
| 3711 | | if (RTREG != 0) |
| 3712 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] |
| 3713 | | else |
| 3714 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3715 | | result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg |
| 3716 | | return result; |
| 3717 | | |
| 3718 | | case 0x05: /* DMTCz */ |
| 3719 | | if (RTREG != 0) |
| 3720 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] |
| 3721 | | else |
| 3722 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3723 | | result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg |
| 3724 | | return result; |
| 3725 | | |
| 3726 | | case 0x06: /* CTCz */ |
| 3727 | | if (RTREG != 0) |
| 3728 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] |
| 3729 | | else |
| 3730 | | emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax |
| 3731 | | emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[0][RDREG]],eax |
| 3732 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3733 | | |
| 3734 | | // case 0x08: /* BC */ |
| 3735 | | // switch (RTREG) |
| 3736 | | // { |
| 3737 | | // case 0x00: /* BCzF */ if (!mips3.core->cf[0][0]) ADDPC(SIMMVAL); break; |
| 3738 | | // case 0x01: /* BCzF */ if (mips3.core->cf[0][0]) ADDPC(SIMMVAL); break; |
| 3739 | | // case 0x02: /* BCzFL */ invalid_instruction(op); break; |
| 3740 | | // case 0x03: /* BCzTL */ invalid_instruction(op); break; |
| 3741 | | // default: invalid_instruction(op); break; |
| 3742 | | // } |
| 3743 | | // break; |
| 3744 | | |
| 3745 | | case 0x10: |
| 3746 | | case 0x11: |
| 3747 | | case 0x12: |
| 3748 | | case 0x13: |
| 3749 | | case 0x14: |
| 3750 | | case 0x15: |
| 3751 | | case 0x16: |
| 3752 | | case 0x17: |
| 3753 | | case 0x18: |
| 3754 | | case 0x19: |
| 3755 | | case 0x1a: |
| 3756 | | case 0x1b: |
| 3757 | | case 0x1c: |
| 3758 | | case 0x1d: |
| 3759 | | case 0x1e: |
| 3760 | | case 0x1f: /* COP */ |
| 3761 | | switch (op & 0x01ffffff) |
| 3762 | | { |
| 3763 | | case 0x01: /* TLBR */ |
| 3764 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 3765 | | emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core |
| 3766 | | drc_append_save_call_restore(drc, (x86code *)mips3com_tlbr, 12); // call tlbr |
| 3767 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3768 | | |
| 3769 | | case 0x02: /* TLBWI */ |
| 3770 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 3771 | | emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core |
| 3772 | | drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwi, 12); // call tlbwi |
| 3773 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3774 | | |
| 3775 | | case 0x06: /* TLBWR */ |
| 3776 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 3777 | | emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core |
| 3778 | | drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwr, 12); // call tlbwr |
| 3779 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3780 | | |
| 3781 | | case 0x08: /* TLBP */ |
| 3782 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 3783 | | emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core |
| 3784 | | drc_append_save_call_restore(drc, (x86code *)mips3com_tlbp, 12); // call tlbp |
| 3785 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3786 | | |
| 3787 | | case 0x10: /* RFE */ |
| 3788 | | emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 3789 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 3790 | | |
| 3791 | | case 0x18: /* ERET */ |
| 3792 | | emit_mov_r32_m32(DRCTOP, REG_EDI, CPR0ADDR(COP0_EPC)); // mov edi,[COP0_EPC] |
| 3793 | | emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [COP0_Status],~SR_EXL |
| 3794 | | return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; |
| 3795 | | |
| 3796 | | default: |
| 3797 | | emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 3798 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 3799 | | } |
| 3800 | | break; |
| 3801 | | |
| 3802 | | // default: |
| 3803 | | // _jmp(mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 3804 | | // return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 3805 | | } |
| 3806 | | return RECOMPILE_UNIMPLEMENTED; |
| 3807 | | } |
| 3808 | | |
| 3809 | | |
| 3810 | | |
| 3811 | | /*************************************************************************** |
| 3812 | | COP1 RECOMPILATION |
| 3813 | | ***************************************************************************/ |
| 3814 | | |
| 3815 | | /*------------------------------------------------------------------ |
| 3816 | | recompile_cop1 |
| 3817 | | ------------------------------------------------------------------*/ |
| 3818 | | |
| 3819 | | static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op) |
| 3820 | | { |
| 3821 | | emit_link link1; |
| 3822 | | int cycles, i; |
| 3823 | | |
| 3824 | | if (mips3.drcoptions & MIPS3DRC_STRICT_COP1) |
| 3825 | | { |
| 3826 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1 |
| 3827 | | emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception |
| 3828 | | } |
| 3829 | | |
| 3830 | | switch (RSREG) |
| 3831 | | { |
| 3832 | | case 0x00: /* MFCz */ |
| 3833 | | if (RTREG != 0) |
| 3834 | | { |
| 3835 | | emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(RDREG)); // mov eax,[RDREG] |
| 3836 | | emit_cdq(DRCTOP); // cdq |
| 3837 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [RTREG],edx:eax |
| 3838 | | } |
| 3839 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3840 | | |
| 3841 | | case 0x01: /* DMFCz */ |
| 3842 | | if (RTREG != 0) |
| 3843 | | emit_mov_m64_m64(DRCTOP, REGADDR(RTREG), FPR64ADDR(RDREG)); |
| 3844 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3845 | | |
| 3846 | | case 0x02: /* CFCz */ |
| 3847 | | if (RTREG != 0) |
| 3848 | | { |
| 3849 | | emit_mov_r32_m32(DRCTOP, REG_EAX, CCR1ADDR(RDREG)); // mov eax,[mips3.core->ccr[1][RDREG]] |
| 3850 | | if (RDREG == 31) |
| 3851 | | { |
| 3852 | | emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfe800000); // and eax,~0xfe800000 |
| 3853 | | emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx |
| 3854 | | emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][0]), 0); // cmp [cf[0]],0 |
| 3855 | | emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl |
| 3856 | | emit_shl_r32_imm(DRCTOP, REG_EBX, 23); // shl ebx,23 |
| 3857 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 3858 | | if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) |
| 3859 | | for (i = 1; i <= 7; i++) |
| 3860 | | { |
| 3861 | | emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][i]), 0); // cmp [cf[i]],0 |
| 3862 | | emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl |
| 3863 | | emit_shl_r32_imm(DRCTOP, REG_EBX, 24+i); // shl ebx,24+i |
| 3864 | | emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx |
| 3865 | | } |
| 3866 | | } |
| 3867 | | emit_cdq(DRCTOP); // cdq |
| 3868 | | emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [mips3.core->r[RTREG]],edx:eax |
| 3869 | | } |
| 3870 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3871 | | |
| 3872 | | case 0x04: /* MTCz */ |
| 3873 | | if (RTREG != 0) |
| 3874 | | { |
| 3875 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] |
| 3876 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), REG_EAX); // mov [mips3.core->cpr[1][RDREG]],eax |
| 3877 | | } |
| 3878 | | else |
| 3879 | | emit_mov_m32_imm(DRCTOP, FPR32ADDR(RDREG), 0); // mov [mips3.core->cpr[1][RDREG]],0 |
| 3880 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3881 | | |
| 3882 | | case 0x05: /* DMTCz */ |
| 3883 | | if (RTREG != 0) |
| 3884 | | emit_mov_m64_m64(DRCTOP, FPR64ADDR(RDREG), REGADDR(RTREG)); |
| 3885 | | else |
| 3886 | | emit_zero_m64(DRCTOP, FPR64ADDR(RDREG)); // mov [mips3.core->cpr[1][RDREG]],0 |
| 3887 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3888 | | |
| 3889 | | case 0x06: /* CTCz */ |
| 3890 | | if (RTREG != 0) |
| 3891 | | { |
| 3892 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] |
| 3893 | | emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[1][RDREG]],eax |
| 3894 | | } |
| 3895 | | else |
| 3896 | | emit_mov_m32_imm(DRCTOP, CCR1ADDR(RDREG), 0); // mov [mips3.core->ccr[1][RDREG]],0 |
| 3897 | | if (RDREG == 31) |
| 3898 | | { |
| 3899 | | emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->ccr[1][RDREG]))); // mov eax,[mips3.core->ccr[1][RDREG]] |
| 3900 | | emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1<<23 |
| 3901 | | emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][0])); // setnz [cf[0]] |
| 3902 | | if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) |
| 3903 | | for (i = 1; i <= 7; i++) |
| 3904 | | { |
| 3905 | | emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24+i)); // test eax,1<<(24+i) |
| 3906 | | emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][i])); // setnz [cf[i]] |
| 3907 | | } |
| 3908 | | emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3 |
| 3909 | | emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1 |
| 3910 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip |
| 3911 | | emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2 |
| 3912 | | resolve_link(DRCTOP, &link1); // skip: |
| 3913 | | drc_append_set_fp_rounding(drc, REG_EAX); // set_rounding(EAX) |
| 3914 | | } |
| 3915 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3916 | | |
| 3917 | | case 0x08: /* BC */ |
| 3918 | | switch ((op >> 16) & 3) |
| 3919 | | { |
| 3920 | | case 0x00: /* BCzF */ |
| 3921 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 |
| 3922 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1 |
| 3923 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3924 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3925 | | resolve_link(DRCTOP, &link1); // skip: |
| 3926 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3927 | | |
| 3928 | | case 0x01: /* BCzT */ |
| 3929 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 |
| 3930 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1 |
| 3931 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3932 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3933 | | resolve_link(DRCTOP, &link1); // skip: |
| 3934 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3935 | | |
| 3936 | | case 0x02: /* BCzFL */ |
| 3937 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 |
| 3938 | | emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1 |
| 3939 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3940 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3941 | | resolve_link(DRCTOP, &link1); // skip: |
| 3942 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 3943 | | |
| 3944 | | case 0x03: /* BCzTL */ |
| 3945 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 |
| 3946 | | emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1 |
| 3947 | | cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> |
| 3948 | | append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> |
| 3949 | | resolve_link(DRCTOP, &link1); // skip: |
| 3950 | | return RECOMPILE_SUCCESSFUL_CP(1,8); |
| 3951 | | } |
| 3952 | | break; |
| 3953 | | |
| 3954 | | default: |
| 3955 | | switch (op & 0x3f) |
| 3956 | | { |
| 3957 | | case 0x00: |
| 3958 | | if (IS_SINGLE(op)) /* ADD.S */ |
| 3959 | | { |
| 3960 | | if (USE_SSE) |
| 3961 | | { |
| 3962 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3963 | | emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg] |
| 3964 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 3965 | | } |
| 3966 | | else |
| 3967 | | { |
| 3968 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 3969 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 3970 | | emit_faddp(DRCTOP); // faddp |
| 3971 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 3972 | | } |
| 3973 | | } |
| 3974 | | else /* ADD.D */ |
| 3975 | | { |
| 3976 | | if (USE_SSE) |
| 3977 | | { |
| 3978 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 3979 | | emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg] |
| 3980 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 3981 | | } |
| 3982 | | else |
| 3983 | | { |
| 3984 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 3985 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 3986 | | emit_faddp(DRCTOP); // faddp |
| 3987 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 3988 | | } |
| 3989 | | } |
| 3990 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 3991 | | |
| 3992 | | case 0x01: |
| 3993 | | if (IS_SINGLE(op)) /* SUB.S */ |
| 3994 | | { |
| 3995 | | if (USE_SSE) |
| 3996 | | { |
| 3997 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 3998 | | emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg] |
| 3999 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 4000 | | } |
| 4001 | | else |
| 4002 | | { |
| 4003 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4004 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4005 | | emit_fsubp(DRCTOP); // fsubp |
| 4006 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4007 | | } |
| 4008 | | } |
| 4009 | | else /* SUB.D */ |
| 4010 | | { |
| 4011 | | if (USE_SSE) |
| 4012 | | { |
| 4013 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4014 | | emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg] |
| 4015 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 4016 | | } |
| 4017 | | else |
| 4018 | | { |
| 4019 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4020 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4021 | | emit_fsubp(DRCTOP); // fsubp |
| 4022 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4023 | | } |
| 4024 | | } |
| 4025 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4026 | | |
| 4027 | | case 0x02: |
| 4028 | | if (IS_SINGLE(op)) /* MUL.S */ |
| 4029 | | { |
| 4030 | | if (USE_SSE) |
| 4031 | | { |
| 4032 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4033 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 4034 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 4035 | | } |
| 4036 | | else |
| 4037 | | { |
| 4038 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4039 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4040 | | emit_fmulp(DRCTOP); // fmulp |
| 4041 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4042 | | } |
| 4043 | | } |
| 4044 | | else /* MUL.D */ |
| 4045 | | { |
| 4046 | | if (USE_SSE) |
| 4047 | | { |
| 4048 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4049 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 4050 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 4051 | | } |
| 4052 | | else |
| 4053 | | { |
| 4054 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4055 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4056 | | emit_fmulp(DRCTOP); // fmulp |
| 4057 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4058 | | } |
| 4059 | | } |
| 4060 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4061 | | |
| 4062 | | case 0x03: |
| 4063 | | if (IS_SINGLE(op)) /* DIV.S */ |
| 4064 | | { |
| 4065 | | if (USE_SSE) |
| 4066 | | { |
| 4067 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4068 | | emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg] |
| 4069 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 4070 | | } |
| 4071 | | else |
| 4072 | | { |
| 4073 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4074 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4075 | | emit_fdivp(DRCTOP); // fdivp |
| 4076 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4077 | | } |
| 4078 | | } |
| 4079 | | else /* DIV.D */ |
| 4080 | | { |
| 4081 | | if (USE_SSE) |
| 4082 | | { |
| 4083 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4084 | | emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg] |
| 4085 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 4086 | | } |
| 4087 | | else |
| 4088 | | { |
| 4089 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4090 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4091 | | emit_fdivp(DRCTOP); // fdivp |
| 4092 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4093 | | } |
| 4094 | | } |
| 4095 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4096 | | |
| 4097 | | case 0x04: |
| 4098 | | if (IS_SINGLE(op)) /* SQRT.S */ |
| 4099 | | { |
| 4100 | | if (USE_SSE) |
| 4101 | | { |
| 4102 | | emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg] |
| 4103 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 4104 | | } |
| 4105 | | else |
| 4106 | | { |
| 4107 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4108 | | emit_fsqrt(DRCTOP); // fsqrt |
| 4109 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4110 | | } |
| 4111 | | } |
| 4112 | | else /* SQRT.D */ |
| 4113 | | { |
| 4114 | | if (USE_SSE) |
| 4115 | | { |
| 4116 | | emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg] |
| 4117 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 4118 | | } |
| 4119 | | else |
| 4120 | | { |
| 4121 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4122 | | emit_fsqrt(DRCTOP); // fsqrt |
| 4123 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4124 | | } |
| 4125 | | } |
| 4126 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4127 | | |
| 4128 | | case 0x05: |
| 4129 | | if (IS_SINGLE(op)) /* ABS.S */ |
| 4130 | | { |
| 4131 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4132 | | emit_fabs(DRCTOP); // fabs |
| 4133 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4134 | | } |
| 4135 | | else /* ABS.D */ |
| 4136 | | { |
| 4137 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4138 | | emit_fabs(DRCTOP); // fabs |
| 4139 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4140 | | } |
| 4141 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4142 | | |
| 4143 | | case 0x06: |
| 4144 | | if (IS_SINGLE(op)) /* MOV.S */ |
| 4145 | | { |
| 4146 | | emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] |
| 4147 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 4148 | | } |
| 4149 | | else /* MOV.D */ |
| 4150 | | emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); |
| 4151 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4152 | | |
| 4153 | | case 0x07: |
| 4154 | | if (IS_SINGLE(op)) /* NEG.S */ |
| 4155 | | { |
| 4156 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4157 | | emit_fchs(DRCTOP); // fchs |
| 4158 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4159 | | } |
| 4160 | | else /* NEG.D */ |
| 4161 | | { |
| 4162 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4163 | | emit_fchs(DRCTOP); // fchs |
| 4164 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4165 | | } |
| 4166 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4167 | | |
| 4168 | | case 0x08: |
| 4169 | | drc_append_set_temp_fp_rounding(drc, FPRND_NEAR); |
| 4170 | | if (IS_SINGLE(op)) /* ROUND.L.S */ |
| 4171 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4172 | | else /* ROUND.L.D */ |
| 4173 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4174 | | emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] |
| 4175 | | drc_append_restore_fp_rounding(drc); |
| 4176 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4177 | | |
| 4178 | | case 0x09: |
| 4179 | | drc_append_set_temp_fp_rounding(drc, FPRND_CHOP); |
| 4180 | | if (IS_SINGLE(op)) /* TRUNC.L.S */ |
| 4181 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4182 | | else /* TRUNC.L.D */ |
| 4183 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4184 | | emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] |
| 4185 | | drc_append_restore_fp_rounding(drc); |
| 4186 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4187 | | |
| 4188 | | case 0x0a: |
| 4189 | | drc_append_set_temp_fp_rounding(drc, FPRND_UP); |
| 4190 | | if (IS_SINGLE(op)) /* CEIL.L.S */ |
| 4191 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4192 | | else /* CEIL.L.D */ |
| 4193 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4194 | | emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] |
| 4195 | | drc_append_restore_fp_rounding(drc); |
| 4196 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4197 | | |
| 4198 | | case 0x0b: |
| 4199 | | drc_append_set_temp_fp_rounding(drc, FPRND_DOWN); |
| 4200 | | if (IS_SINGLE(op)) /* FLOOR.L.S */ |
| 4201 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4202 | | else /* FLOOR.L.D */ |
| 4203 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4204 | | emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] |
| 4205 | | drc_append_restore_fp_rounding(drc); |
| 4206 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4207 | | |
| 4208 | | case 0x0c: |
| 4209 | | drc_append_set_temp_fp_rounding(drc, FPRND_NEAR); |
| 4210 | | if (IS_SINGLE(op)) /* ROUND.W.S */ |
| 4211 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4212 | | else /* ROUND.W.D */ |
| 4213 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4214 | | emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] |
| 4215 | | drc_append_restore_fp_rounding(drc); |
| 4216 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4217 | | |
| 4218 | | case 0x0d: |
| 4219 | | drc_append_set_temp_fp_rounding(drc, FPRND_CHOP); |
| 4220 | | if (IS_SINGLE(op)) /* TRUNC.W.S */ |
| 4221 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4222 | | else /* TRUNC.W.D */ |
| 4223 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4224 | | emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] |
| 4225 | | drc_append_restore_fp_rounding(drc); |
| 4226 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4227 | | |
| 4228 | | case 0x0e: |
| 4229 | | drc_append_set_temp_fp_rounding(drc, FPRND_UP); |
| 4230 | | if (IS_SINGLE(op)) /* CEIL.W.S */ |
| 4231 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4232 | | else /* CEIL.W.D */ |
| 4233 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4234 | | emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] |
| 4235 | | drc_append_restore_fp_rounding(drc); |
| 4236 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4237 | | |
| 4238 | | case 0x0f: |
| 4239 | | drc_append_set_temp_fp_rounding(drc, FPRND_DOWN); |
| 4240 | | if (IS_SINGLE(op)) /* FLOOR.W.S */ |
| 4241 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4242 | | else /* FLOOR.W.D */ |
| 4243 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4244 | | emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] |
| 4245 | | drc_append_restore_fp_rounding(drc); |
| 4246 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4247 | | |
| 4248 | | case 0x11: /* R5000 */ |
| 4249 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 4250 | | { |
| 4251 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); |
| 4252 | | // jmp generate_invalidop_exception |
| 4253 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4254 | | } |
| 4255 | | emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 |
| 4256 | | emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); |
| 4257 | | // jz/nz skip |
| 4258 | | if (IS_SINGLE(op)) /* MOVT/F.S */ |
| 4259 | | { |
| 4260 | | emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] |
| 4261 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 4262 | | } |
| 4263 | | else /* MOVT/F.D */ |
| 4264 | | emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); |
| 4265 | | resolve_link(DRCTOP, &link1); // skip: |
| 4266 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4267 | | |
| 4268 | | case 0x12: /* R5000 */ |
| 4269 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 4270 | | { |
| 4271 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); |
| 4272 | | // jmp generate_invalidop_exception |
| 4273 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4274 | | } |
| 4275 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 4276 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 4277 | | emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip |
| 4278 | | if (IS_SINGLE(op)) /* MOVZ.S */ |
| 4279 | | { |
| 4280 | | emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] |
| 4281 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 4282 | | } |
| 4283 | | else /* MOVZ.D */ |
| 4284 | | emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); |
| 4285 | | resolve_link(DRCTOP, &link1); // skip: |
| 4286 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4287 | | |
| 4288 | | case 0x13: /* R5000 */ |
| 4289 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 4290 | | { |
| 4291 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); |
| 4292 | | // jmp generate_invalidop_exception |
| 4293 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4294 | | } |
| 4295 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo |
| 4296 | | emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi |
| 4297 | | emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip |
| 4298 | | if (IS_SINGLE(op)) /* MOVN.S */ |
| 4299 | | { |
| 4300 | | emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] |
| 4301 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 4302 | | } |
| 4303 | | else /* MOVN.D */ |
| 4304 | | emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); |
| 4305 | | resolve_link(DRCTOP, &link1); // skip: |
| 4306 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4307 | | |
| 4308 | | case 0x15: /* R5000 */ |
| 4309 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 4310 | | { |
| 4311 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); |
| 4312 | | // jmp generate_invalidop_exception |
| 4313 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4314 | | } |
| 4315 | | emit_fld1(DRCTOP); // fld1 |
| 4316 | | if (IS_SINGLE(op)) /* RECIP.S */ |
| 4317 | | { |
| 4318 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4319 | | emit_fdivp(DRCTOP); // fdivp |
| 4320 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4321 | | } |
| 4322 | | else /* RECIP.D */ |
| 4323 | | { |
| 4324 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4325 | | emit_fdivp(DRCTOP); // fdivp |
| 4326 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4327 | | } |
| 4328 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4329 | | |
| 4330 | | case 0x16: /* R5000 */ |
| 4331 | | if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) |
| 4332 | | { |
| 4333 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); |
| 4334 | | // jmp generate_invalidop_exception |
| 4335 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4336 | | } |
| 4337 | | emit_fld1(DRCTOP); // fld1 |
| 4338 | | if (IS_SINGLE(op)) /* RSQRT.S */ |
| 4339 | | { |
| 4340 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4341 | | emit_fsqrt(DRCTOP); // fsqrt |
| 4342 | | emit_fdivp(DRCTOP); // fdivp |
| 4343 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4344 | | } |
| 4345 | | else /* RSQRT.D */ |
| 4346 | | { |
| 4347 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4348 | | emit_fsqrt(DRCTOP); // fsqrt |
| 4349 | | emit_fdivp(DRCTOP); // fdivp |
| 4350 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4351 | | } |
| 4352 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4353 | | |
| 4354 | | case 0x20: |
| 4355 | | if (IS_INTEGRAL(op)) |
| 4356 | | { |
| 4357 | | if (IS_SINGLE(op)) /* CVT.S.W */ |
| 4358 | | emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg] |
| 4359 | | else /* CVT.S.L */ |
| 4360 | | emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg] |
| 4361 | | } |
| 4362 | | else /* CVT.S.D */ |
| 4363 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4364 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4365 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4366 | | |
| 4367 | | case 0x21: |
| 4368 | | if (IS_INTEGRAL(op)) |
| 4369 | | { |
| 4370 | | if (IS_SINGLE(op)) /* CVT.D.W */ |
| 4371 | | emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg] |
| 4372 | | else /* CVT.D.L */ |
| 4373 | | emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg] |
| 4374 | | } |
| 4375 | | else /* CVT.D.S */ |
| 4376 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4377 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4378 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4379 | | |
| 4380 | | case 0x24: |
| 4381 | | if (IS_SINGLE(op)) /* CVT.W.S */ |
| 4382 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4383 | | else /* CVT.W.D */ |
| 4384 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4385 | | emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] |
| 4386 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4387 | | |
| 4388 | | case 0x25: |
| 4389 | | if (IS_SINGLE(op)) /* CVT.L.S */ |
| 4390 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4391 | | else /* CVT.L.D */ |
| 4392 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4393 | | emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] |
| 4394 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4395 | | |
| 4396 | | case 0x30: |
| 4397 | | case 0x38: |
| 4398 | | emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */ |
| 4399 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4400 | | |
| 4401 | | case 0x31: |
| 4402 | | case 0x39: |
| 4403 | | emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.UN.S/D */ |
| 4404 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4405 | | |
| 4406 | | case 0x32: |
| 4407 | | case 0x3a: |
| 4408 | | if (USE_SSE) |
| 4409 | | { |
| 4410 | | if (IS_SINGLE(op)) /* C.EQ.S */ |
| 4411 | | { |
| 4412 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4413 | | emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] |
| 4414 | | } |
| 4415 | | else |
| 4416 | | { |
| 4417 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4418 | | emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] |
| 4419 | | } |
| 4420 | | emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] |
| 4421 | | } |
| 4422 | | else |
| 4423 | | { |
| 4424 | | if (IS_SINGLE(op)) /* C.EQ.S */ |
| 4425 | | { |
| 4426 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4427 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4428 | | } |
| 4429 | | else |
| 4430 | | { |
| 4431 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4432 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4433 | | } |
| 4434 | | emit_fcompp(DRCTOP); // fcompp |
| 4435 | | emit_fstsw_ax(DRCTOP); // fnstsw ax |
| 4436 | | emit_sahf(DRCTOP); // sahf |
| 4437 | | emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] |
| 4438 | | } |
| 4439 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4440 | | |
| 4441 | | case 0x33: |
| 4442 | | case 0x3b: |
| 4443 | | if (USE_SSE) |
| 4444 | | { |
| 4445 | | if (IS_SINGLE(op)) /* C.UEQ.S */ |
| 4446 | | { |
| 4447 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4448 | | emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] |
| 4449 | | } |
| 4450 | | else |
| 4451 | | { |
| 4452 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4453 | | emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] |
| 4454 | | } |
| 4455 | | emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] |
| 4456 | | } |
| 4457 | | else |
| 4458 | | { |
| 4459 | | if (IS_SINGLE(op)) /* C.UEQ.S */ |
| 4460 | | { |
| 4461 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4462 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4463 | | } |
| 4464 | | else |
| 4465 | | { |
| 4466 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4467 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4468 | | } |
| 4469 | | emit_fucompp(DRCTOP); // fucompp |
| 4470 | | emit_fstsw_ax(DRCTOP); // fnstsw ax |
| 4471 | | emit_sahf(DRCTOP); // sahf |
| 4472 | | emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] |
| 4473 | | } |
| 4474 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4475 | | |
| 4476 | | case 0x34: |
| 4477 | | case 0x3c: |
| 4478 | | if (USE_SSE) |
| 4479 | | { |
| 4480 | | if (IS_SINGLE(op)) /* C.OLT.S */ |
| 4481 | | { |
| 4482 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4483 | | emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] |
| 4484 | | } |
| 4485 | | else |
| 4486 | | { |
| 4487 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4488 | | emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] |
| 4489 | | } |
| 4490 | | emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] |
| 4491 | | } |
| 4492 | | else |
| 4493 | | { |
| 4494 | | if (IS_SINGLE(op)) /* C.OLT.S */ |
| 4495 | | { |
| 4496 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4497 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4498 | | } |
| 4499 | | else |
| 4500 | | { |
| 4501 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4502 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4503 | | } |
| 4504 | | emit_fcompp(DRCTOP); // fcompp |
| 4505 | | emit_fstsw_ax(DRCTOP); // fnstsw ax |
| 4506 | | emit_sahf(DRCTOP); // sahf |
| 4507 | | emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] |
| 4508 | | } |
| 4509 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4510 | | |
| 4511 | | case 0x35: |
| 4512 | | case 0x3d: |
| 4513 | | if (USE_SSE) |
| 4514 | | { |
| 4515 | | if (IS_SINGLE(op)) /* C.ULT.S */ |
| 4516 | | { |
| 4517 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4518 | | emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] |
| 4519 | | } |
| 4520 | | else |
| 4521 | | { |
| 4522 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4523 | | emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] |
| 4524 | | } |
| 4525 | | emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] |
| 4526 | | } |
| 4527 | | else |
| 4528 | | { |
| 4529 | | if (IS_SINGLE(op)) /* C.ULT.S */ |
| 4530 | | { |
| 4531 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4532 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4533 | | } |
| 4534 | | else |
| 4535 | | { |
| 4536 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4537 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4538 | | } |
| 4539 | | emit_fucompp(DRCTOP); // fucompp |
| 4540 | | emit_fstsw_ax(DRCTOP); // fnstsw ax |
| 4541 | | emit_sahf(DRCTOP); // sahf |
| 4542 | | emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] |
| 4543 | | } |
| 4544 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4545 | | |
| 4546 | | case 0x36: |
| 4547 | | case 0x3e: |
| 4548 | | if (USE_SSE) |
| 4549 | | { |
| 4550 | | if (IS_SINGLE(op)) /* C.OLE.S */ |
| 4551 | | { |
| 4552 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4553 | | emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] |
| 4554 | | } |
| 4555 | | else |
| 4556 | | { |
| 4557 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4558 | | emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] |
| 4559 | | } |
| 4560 | | emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setle [cf[x]] |
| 4561 | | } |
| 4562 | | else |
| 4563 | | { |
| 4564 | | if (IS_SINGLE(op)) /* C.OLE.S */ |
| 4565 | | { |
| 4566 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4567 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4568 | | } |
| 4569 | | else |
| 4570 | | { |
| 4571 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4572 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4573 | | } |
| 4574 | | emit_fcompp(DRCTOP); // fcompp |
| 4575 | | emit_fstsw_ax(DRCTOP); // fnstsw ax |
| 4576 | | emit_sahf(DRCTOP); // sahf |
| 4577 | | emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]] |
| 4578 | | } |
| 4579 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4580 | | |
| 4581 | | case 0x37: |
| 4582 | | case 0x3f: |
| 4583 | | if (USE_SSE) |
| 4584 | | { |
| 4585 | | if (IS_SINGLE(op)) /* C.ULE.S */ |
| 4586 | | { |
| 4587 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4588 | | emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] |
| 4589 | | } |
| 4590 | | else |
| 4591 | | { |
| 4592 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4593 | | emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] |
| 4594 | | } |
| 4595 | | emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setl [cf[x]] |
| 4596 | | } |
| 4597 | | else |
| 4598 | | { |
| 4599 | | if (IS_SINGLE(op)) /* C.ULE.S */ |
| 4600 | | { |
| 4601 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4602 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4603 | | } |
| 4604 | | else |
| 4605 | | { |
| 4606 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4607 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4608 | | } |
| 4609 | | emit_fucompp(DRCTOP); // fucompp |
| 4610 | | emit_fstsw_ax(DRCTOP); // fnstsw ax |
| 4611 | | emit_sahf(DRCTOP); // sahf |
| 4612 | | emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]] |
| 4613 | | } |
| 4614 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4615 | | } |
| 4616 | | break; |
| 4617 | | } |
| 4618 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 4619 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4620 | | } |
| 4621 | | |
| 4622 | | |
| 4623 | | |
| 4624 | | /*************************************************************************** |
| 4625 | | COP1X RECOMPILATION |
| 4626 | | ***************************************************************************/ |
| 4627 | | |
| 4628 | | /*------------------------------------------------------------------ |
| 4629 | | recompile_cop1x |
| 4630 | | ------------------------------------------------------------------*/ |
| 4631 | | |
| 4632 | | static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op) |
| 4633 | | { |
| 4634 | | if (mips3.drcoptions & MIPS3DRC_STRICT_COP1) |
| 4635 | | { |
| 4636 | | emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1 |
| 4637 | | emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception |
| 4638 | | } |
| 4639 | | |
| 4640 | | switch (op & 0x3f) |
| 4641 | | { |
| 4642 | | case 0x00: /* LWXC1 */ |
| 4643 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 4644 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 4645 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 4646 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] |
| 4647 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] |
| 4648 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 4649 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word |
| 4650 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 4651 | | emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax |
| 4652 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 4653 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4654 | | |
| 4655 | | case 0x01: /* LDXC1 */ |
| 4656 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 4657 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 4658 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 |
| 4659 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] |
| 4660 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] |
| 4661 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 4662 | | emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double |
| 4663 | | emit_mov_m32_r32(DRCTOP, FPR64ADDRLO(FDREG), REG_EAX); // mov [fdreg].lo,eax |
| 4664 | | emit_mov_m32_r32(DRCTOP, FPR64ADDRHI(FDREG), REG_EDX); // mov [fdreg].hi,edx |
| 4665 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 4666 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 4667 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4668 | | |
| 4669 | | case 0x08: /* SWXC1 */ |
| 4670 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 4671 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 4672 | | emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 |
| 4673 | | emit_push_m32(DRCTOP, FPR32ADDR(FSREG)); // push [fsreg] |
| 4674 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] |
| 4675 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] |
| 4676 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 4677 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word |
| 4678 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,8 |
| 4679 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 4680 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4681 | | |
| 4682 | | case 0x09: /* SDXC1 */ |
| 4683 | | emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp |
| 4684 | | emit_save_pc_before_call(DRCTOP); // save pc |
| 4685 | | emit_push_m32(DRCTOP, FPR64ADDRHI(FSREG)); // push [fsreg].hi |
| 4686 | | emit_push_m32(DRCTOP, FPR64ADDRLO(FSREG)); // push [fsreg].lo |
| 4687 | | emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] |
| 4688 | | emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] |
| 4689 | | emit_push_r32(DRCTOP, REG_EAX); // push eax |
| 4690 | | emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double |
| 4691 | | emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 |
| 4692 | | emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] |
| 4693 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4694 | | |
| 4695 | | case 0x0f: /* PREFX */ |
| 4696 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4697 | | |
| 4698 | | case 0x20: /* MADD.S */ |
| 4699 | | if (USE_SSE) |
| 4700 | | { |
| 4701 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4702 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 4703 | | emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg] |
| 4704 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 4705 | | } |
| 4706 | | else |
| 4707 | | { |
| 4708 | | emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] |
| 4709 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4710 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4711 | | emit_fmulp(DRCTOP); // fmulp |
| 4712 | | emit_faddp(DRCTOP); // faddp |
| 4713 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4714 | | } |
| 4715 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4716 | | |
| 4717 | | case 0x21: /* MADD.D */ |
| 4718 | | if (USE_SSE) |
| 4719 | | { |
| 4720 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4721 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 4722 | | emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg] |
| 4723 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 4724 | | } |
| 4725 | | else |
| 4726 | | { |
| 4727 | | emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] |
| 4728 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4729 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4730 | | emit_fmulp(DRCTOP); // fmulp |
| 4731 | | emit_faddp(DRCTOP); // faddp |
| 4732 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4733 | | } |
| 4734 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4735 | | |
| 4736 | | case 0x28: /* MSUB.S */ |
| 4737 | | if (USE_SSE) |
| 4738 | | { |
| 4739 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4740 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 4741 | | emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg] |
| 4742 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 |
| 4743 | | } |
| 4744 | | else |
| 4745 | | { |
| 4746 | | emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] |
| 4747 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4748 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4749 | | emit_fmulp(DRCTOP); // fmulp |
| 4750 | | emit_fsubrp(DRCTOP); // fsubrp |
| 4751 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4752 | | } |
| 4753 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4754 | | |
| 4755 | | case 0x29: /* MSUB.D */ |
| 4756 | | if (USE_SSE) |
| 4757 | | { |
| 4758 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4759 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 4760 | | emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg] |
| 4761 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 |
| 4762 | | } |
| 4763 | | else |
| 4764 | | { |
| 4765 | | emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] |
| 4766 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4767 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4768 | | emit_fmulp(DRCTOP); // fmulp |
| 4769 | | emit_fsubrp(DRCTOP); // fsubrp |
| 4770 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4771 | | } |
| 4772 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4773 | | |
| 4774 | | case 0x30: /* NMADD.S */ |
| 4775 | | if (USE_SSE) |
| 4776 | | { |
| 4777 | | emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1 |
| 4778 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4779 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 4780 | | emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg] |
| 4781 | | emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 |
| 4782 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1 |
| 4783 | | } |
| 4784 | | else |
| 4785 | | { |
| 4786 | | emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] |
| 4787 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4788 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4789 | | emit_fmulp(DRCTOP); // fmulp |
| 4790 | | emit_faddp(DRCTOP); // faddp |
| 4791 | | emit_fchs(DRCTOP); // fchs |
| 4792 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4793 | | } |
| 4794 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4795 | | |
| 4796 | | case 0x31: /* NMADD.D */ |
| 4797 | | if (USE_SSE) |
| 4798 | | { |
| 4799 | | emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1 |
| 4800 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4801 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 4802 | | emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg] |
| 4803 | | emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 |
| 4804 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1 |
| 4805 | | } |
| 4806 | | else |
| 4807 | | { |
| 4808 | | emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] |
| 4809 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4810 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4811 | | emit_fmulp(DRCTOP); // fmulp |
| 4812 | | emit_faddp(DRCTOP); // faddp |
| 4813 | | emit_fchs(DRCTOP); // fchs |
| 4814 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4815 | | } |
| 4816 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4817 | | |
| 4818 | | case 0x38: /* NMSUB.S */ |
| 4819 | | if (USE_SSE) |
| 4820 | | { |
| 4821 | | emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] |
| 4822 | | emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] |
| 4823 | | emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg] |
| 4824 | | emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 |
| 4825 | | emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1 |
| 4826 | | } |
| 4827 | | else |
| 4828 | | { |
| 4829 | | emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] |
| 4830 | | emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] |
| 4831 | | emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] |
| 4832 | | emit_fmulp(DRCTOP); // fmulp |
| 4833 | | emit_fsubp(DRCTOP); // fsubp |
| 4834 | | emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] |
| 4835 | | } |
| 4836 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4837 | | |
| 4838 | | case 0x39: /* NMSUB.D */ |
| 4839 | | if (USE_SSE) |
| 4840 | | { |
| 4841 | | emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] |
| 4842 | | emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] |
| 4843 | | emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg] |
| 4844 | | emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 |
| 4845 | | emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1 |
| 4846 | | } |
| 4847 | | else |
| 4848 | | { |
| 4849 | | emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] |
| 4850 | | emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] |
| 4851 | | emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] |
| 4852 | | emit_fmulp(DRCTOP); // fmulp |
| 4853 | | emit_fsubp(DRCTOP); // fsubrp |
| 4854 | | emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] |
| 4855 | | } |
| 4856 | | return RECOMPILE_SUCCESSFUL_CP(1,4); |
| 4857 | | |
| 4858 | | case 0x24: /* MADD.W */ |
| 4859 | | case 0x25: /* MADD.L */ |
| 4860 | | case 0x2c: /* MSUB.W */ |
| 4861 | | case 0x2d: /* MSUB.L */ |
| 4862 | | case 0x34: /* NMADD.W */ |
| 4863 | | case 0x35: /* NMADD.L */ |
| 4864 | | case 0x3c: /* NMSUB.W */ |
| 4865 | | case 0x3d: /* NMSUB.L */ |
| 4866 | | default: |
| 4867 | | fprintf(stderr, "cop1x %X\n", op); |
| 4868 | | break; |
| 4869 | | } |
| 4870 | | emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception |
| 4871 | | return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; |
| 4872 | | } |
src/emu/cpu/mips/mips3drc.c
| r2821 | r2822 | |
| 117 | 117 | #define CPR264(reg) MEM(&mips3->cpr[2][reg]) |
| 118 | 118 | #define CCR264(reg) MEM(&mips3->ccr[2][reg]) |
| 119 | 119 | |
| 120 | | #define FCCMASK(which) fcc_mask[(mips3->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)] |
| 120 | #define FCCMASK(which) ((UINT32)(1 << fcc_shift[(mips3->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)])) |
| 121 | #define FCCSHIFT(which) fcc_shift[(mips3->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)] |
| 121 | 122 | |
| 122 | 123 | |
| 123 | 124 | |
| r2821 | r2822 | |
| 177 | 178 | |
| 178 | 179 | /* tables */ |
| 179 | 180 | UINT8 fpmode[4]; /* FPU mode table */ |
| 180 | | UINT64 slt_table[32]; /* FLAGS table for slt */ |
| 181 | | UINT64 sltu_table[32]; /* FLAGS table for sltu */ |
| 182 | | UINT32 c_un_table[32]; /* FLAGS table for c_un */ |
| 183 | | UINT32 c_eq_table[32]; /* FLAGS table for c_eq */ |
| 184 | | UINT32 c_ueq_table[32]; /* FLAGS table for c_ueq */ |
| 185 | | UINT32 c_olt_table[32]; /* FLAGS table for c_olt */ |
| 186 | | UINT32 c_ult_table[32]; /* FLAGS table for c_ult */ |
| 187 | | UINT32 c_ole_table[32]; /* FLAGS table for c_ole */ |
| 188 | | UINT32 c_ule_table[32]; /* FLAGS table for c_ule */ |
| 189 | 181 | |
| 190 | 182 | /* register mappings */ |
| 191 | 183 | drcuml_parameter regmap[34]; /* parameter to register mappings for all 32 integer registers */ |
| r2821 | r2822 | |
| 270 | 262 | |
| 271 | 263 | |
| 272 | 264 | /* bit indexes for various FCCs */ |
| 273 | | static const UINT32 fcc_mask[8] = { 1 << 23, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29, 1 << 30, 1 << 31 }; |
| 265 | static const UINT8 fcc_shift[8] = { 23, 25, 26, 27, 28, 29, 30, 31 }; |
| 274 | 266 | |
| 275 | 267 | /* lookup table for FP modes */ |
| 276 | 268 | static const UINT8 fpmode_source[4] = |
| r2821 | r2822 | |
| 281 | 273 | DRCUML_FMOD_FLOOR |
| 282 | 274 | }; |
| 283 | 275 | |
| 284 | | /* flag lookup table for SLT */ |
| 285 | | static const UINT64 slt_table_source[32] = |
| 286 | | { |
| 287 | | /* ..... */ 0, |
| 288 | | /* ....C */ 0, |
| 289 | | /* ...V. */ 1, |
| 290 | | /* ...VC */ 1, |
| 291 | | /* ..Z.. */ 0, |
| 292 | | /* ..Z.C */ 0, |
| 293 | | /* ..ZV. */ 1, |
| 294 | | /* ..ZVC */ 1, |
| 295 | | /* .S... */ 1, |
| 296 | | /* .S..C */ 1, |
| 297 | | /* .S.V. */ 0, |
| 298 | | /* .S.VC */ 0, |
| 299 | | /* .SZ.. */ 1, |
| 300 | | /* .SZ.C */ 1, |
| 301 | | /* .SZV. */ 0, |
| 302 | | /* .SZVC */ 0, |
| 303 | | /* U.... */ 0, |
| 304 | | /* U...C */ 0, |
| 305 | | /* U..V. */ 1, |
| 306 | | /* U..VC */ 1, |
| 307 | | /* U.Z.. */ 0, |
| 308 | | /* U.Z.C */ 0, |
| 309 | | /* U.ZV. */ 1, |
| 310 | | /* U.ZVC */ 1, |
| 311 | | /* US... */ 1, |
| 312 | | /* US..C */ 1, |
| 313 | | /* US.V. */ 0, |
| 314 | | /* US.VC */ 0, |
| 315 | | /* USZ.. */ 1, |
| 316 | | /* USZ.C */ 1, |
| 317 | | /* USZV. */ 0, |
| 318 | | /* USZVC */ 0 |
| 319 | | }; |
| 320 | 276 | |
| 321 | | /* flag lookup table for SLTU */ |
| 322 | | static const UINT64 sltu_table_source[32] = |
| 323 | | { |
| 324 | | /* ..... */ 0, |
| 325 | | /* ....C */ 1, |
| 326 | | /* ...V. */ 0, |
| 327 | | /* ...VC */ 1, |
| 328 | | /* ..Z.. */ 0, |
| 329 | | /* ..Z.C */ 1, |
| 330 | | /* ..ZV. */ 0, |
| 331 | | /* ..ZVC */ 1, |
| 332 | | /* .S... */ 0, |
| 333 | | /* .S..C */ 1, |
| 334 | | /* .S.V. */ 0, |
| 335 | | /* .S.VC */ 1, |
| 336 | | /* .SZ.. */ 0, |
| 337 | | /* .SZ.C */ 1, |
| 338 | | /* .SZV. */ 0, |
| 339 | | /* .SZVC */ 1, |
| 340 | | /* U.... */ 0, |
| 341 | | /* U...C */ 1, |
| 342 | | /* U..V. */ 0, |
| 343 | | /* U..VC */ 1, |
| 344 | | /* U.Z.. */ 0, |
| 345 | | /* U.Z.C */ 1, |
| 346 | | /* U.ZV. */ 0, |
| 347 | | /* U.ZVC */ 1, |
| 348 | | /* US... */ 0, |
| 349 | | /* US..C */ 1, |
| 350 | | /* US.V. */ 0, |
| 351 | | /* US.VC */ 1, |
| 352 | | /* USZ.. */ 0, |
| 353 | | /* USZ.C */ 1, |
| 354 | | /* USZV. */ 0, |
| 355 | | /* USZVC */ 1 |
| 356 | | }; |
| 357 | 277 | |
| 358 | | /* flag lookup table for C.UN */ |
| 359 | | static const UINT32 c_un_table_source[32] = |
| 360 | | { |
| 361 | | /* ..... */ 0, |
| 362 | | /* ....C */ 0, |
| 363 | | /* ...V. */ 0, |
| 364 | | /* ...VC */ 0, |
| 365 | | /* ..Z.. */ 0, |
| 366 | | /* ..Z.C */ 0, |
| 367 | | /* ..ZV. */ 0, |
| 368 | | /* ..ZVC */ 0, |
| 369 | | /* .S... */ 0, |
| 370 | | /* .S..C */ 0, |
| 371 | | /* .S.V. */ 0, |
| 372 | | /* .S.VC */ 0, |
| 373 | | /* .SZ.. */ 0, |
| 374 | | /* .SZ.C */ 0, |
| 375 | | /* .SZV. */ 0, |
| 376 | | /* .SZVC */ 0, |
| 377 | | /* U.... */ ~0, |
| 378 | | /* U...C */ ~0, |
| 379 | | /* U..V. */ ~0, |
| 380 | | /* U..VC */ ~0, |
| 381 | | /* U.Z.. */ ~0, |
| 382 | | /* U.Z.C */ ~0, |
| 383 | | /* U.ZV. */ ~0, |
| 384 | | /* U.ZVC */ ~0, |
| 385 | | /* US... */ ~0, |
| 386 | | /* US..C */ ~0, |
| 387 | | /* US.V. */ ~0, |
| 388 | | /* US.VC */ ~0, |
| 389 | | /* USZ.. */ ~0, |
| 390 | | /* USZ.C */ ~0, |
| 391 | | /* USZV. */ ~0, |
| 392 | | /* USZVC */ ~0 |
| 393 | | }; |
| 394 | | |
| 395 | | /* flag lookup table for C.EQ */ |
| 396 | | static const UINT32 c_eq_table_source[32] = |
| 397 | | { |
| 398 | | /* ..... */ 0, |
| 399 | | /* ....C */ 0, |
| 400 | | /* ...V. */ 0, |
| 401 | | /* ...VC */ 0, |
| 402 | | /* ..Z.. */ ~0, |
| 403 | | /* ..Z.C */ ~0, |
| 404 | | /* ..ZV. */ ~0, |
| 405 | | /* ..ZVC */ ~0, |
| 406 | | /* .S... */ 0, |
| 407 | | /* .S..C */ 0, |
| 408 | | /* .S.V. */ 0, |
| 409 | | /* .S.VC */ 0, |
| 410 | | /* .SZ.. */ ~0, |
| 411 | | /* .SZ.C */ ~0, |
| 412 | | /* .SZV. */ ~0, |
| 413 | | /* .SZVC */ ~0, |
| 414 | | /* U.... */ 0, |
| 415 | | /* U...C */ 0, |
| 416 | | /* U..V. */ 0, |
| 417 | | /* U..VC */ 0, |
| 418 | | /* U.Z.. */ 0, |
| 419 | | /* U.Z.C */ 0, |
| 420 | | /* U.ZV. */ 0, |
| 421 | | /* U.ZVC */ 0, |
| 422 | | /* US... */ 0, |
| 423 | | /* US..C */ 0, |
| 424 | | /* US.V. */ 0, |
| 425 | | /* US.VC */ 0, |
| 426 | | /* USZ.. */ 0, |
| 427 | | /* USZ.C */ 0, |
| 428 | | /* USZV. */ 0, |
| 429 | | /* USZVC */ 0 |
| 430 | | }; |
| 431 | | |
| 432 | | /* flag lookup table for C.UEQ */ |
| 433 | | static const UINT32 c_ueq_table_source[32] = |
| 434 | | { |
| 435 | | /* ..... */ 0, |
| 436 | | /* ....C */ 0, |
| 437 | | /* ...V. */ 0, |
| 438 | | /* ...VC */ 0, |
| 439 | | /* ..Z.. */ ~0, |
| 440 | | /* ..Z.C */ ~0, |
| 441 | | /* ..ZV. */ ~0, |
| 442 | | /* ..ZVC */ ~0, |
| 443 | | /* .S... */ 0, |
| 444 | | /* .S..C */ 0, |
| 445 | | /* .S.V. */ 0, |
| 446 | | /* .S.VC */ 0, |
| 447 | | /* .SZ.. */ ~0, |
| 448 | | /* .SZ.C */ ~0, |
| 449 | | /* .SZV. */ ~0, |
| 450 | | /* .SZVC */ ~0, |
| 451 | | /* U.... */ ~0, |
| 452 | | /* U...C */ ~0, |
| 453 | | /* U..V. */ ~0, |
| 454 | | /* U..VC */ ~0, |
| 455 | | /* U.Z.. */ ~0, |
| 456 | | /* U.Z.C */ ~0, |
| 457 | | /* U.ZV. */ ~0, |
| 458 | | /* U.ZVC */ ~0, |
| 459 | | /* US... */ ~0, |
| 460 | | /* US..C */ ~0, |
| 461 | | /* US.V. */ ~0, |
| 462 | | /* US.VC */ ~0, |
| 463 | | /* USZ.. */ ~0, |
| 464 | | /* USZ.C */ ~0, |
| 465 | | /* USZV. */ ~0, |
| 466 | | /* USZVC */ ~0 |
| 467 | | }; |
| 468 | | |
| 469 | | /* flag lookup table for C.OLT */ |
| 470 | | static const UINT32 c_olt_table_source[32] = |
| 471 | | { |
| 472 | | /* ..... */ 0, |
| 473 | | /* ....C */ ~0, |
| 474 | | /* ...V. */ 0, |
| 475 | | /* ...VC */ ~0, |
| 476 | | /* ..Z.. */ 0, |
| 477 | | /* ..Z.C */ ~0, |
| 478 | | /* ..ZV. */ 0, |
| 479 | | /* ..ZVC */ ~0, |
| 480 | | /* .S... */ 0, |
| 481 | | /* .S..C */ ~0, |
| 482 | | /* .S.V. */ 0, |
| 483 | | /* .S.VC */ ~0, |
| 484 | | /* .SZ.. */ 0, |
| 485 | | /* .SZ.C */ ~0, |
| 486 | | /* .SZV. */ 0, |
| 487 | | /* .SZVC */ ~0, |
| 488 | | /* U.... */ 0, |
| 489 | | /* U...C */ 0, |
| 490 | | /* U..V. */ 0, |
| 491 | | /* U..VC */ 0, |
| 492 | | /* U.Z.. */ 0, |
| 493 | | /* U.Z.C */ 0, |
| 494 | | /* U.ZV. */ 0, |
| 495 | | /* U.ZVC */ 0, |
| 496 | | /* US... */ 0, |
| 497 | | /* US..C */ 0, |
| 498 | | /* US.V. */ 0, |
| 499 | | /* US.VC */ 0, |
| 500 | | /* USZ.. */ 0, |
| 501 | | /* USZ.C */ 0, |
| 502 | | /* USZV. */ 0, |
| 503 | | /* USZVC */ 0 |
| 504 | | }; |
| 505 | | |
| 506 | | /* flag lookup table for C.ULT */ |
| 507 | | static const UINT32 c_ult_table_source[32] = |
| 508 | | { |
| 509 | | /* ..... */ 0, |
| 510 | | /* ....C */ ~0, |
| 511 | | /* ...V. */ 0, |
| 512 | | /* ...VC */ ~0, |
| 513 | | /* ..Z.. */ 0, |
| 514 | | /* ..Z.C */ ~0, |
| 515 | | /* ..ZV. */ 0, |
| 516 | | /* ..ZVC */ ~0, |
| 517 | | /* .S... */ 0, |
| 518 | | /* .S..C */ ~0, |
| 519 | | /* .S.V. */ 0, |
| 520 | | /* .S.VC */ ~0, |
| 521 | | /* .SZ.. */ 0, |
| 522 | | /* .SZ.C */ ~0, |
| 523 | | /* .SZV. */ 0, |
| 524 | | /* .SZVC */ ~0, |
| 525 | | /* U.... */ ~0, |
| 526 | | /* U...C */ ~0, |
| 527 | | /* U..V. */ ~0, |
| 528 | | /* U..VC */ ~0, |
| 529 | | /* U.Z.. */ ~0, |
| 530 | | /* U.Z.C */ ~0, |
| 531 | | /* U.ZV. */ ~0, |
| 532 | | /* U.ZVC */ ~0, |
| 533 | | /* US... */ ~0, |
| 534 | | /* US..C */ ~0, |
| 535 | | /* US.V. */ ~0, |
| 536 | | /* US.VC */ ~0, |
| 537 | | /* USZ.. */ ~0, |
| 538 | | /* USZ.C */ ~0, |
| 539 | | /* USZV. */ ~0, |
| 540 | | /* USZVC */ ~0 |
| 541 | | }; |
| 542 | | |
| 543 | | /* flag lookup table for C.OLE */ |
| 544 | | static const UINT32 c_ole_table_source[32] = |
| 545 | | { |
| 546 | | /* ..... */ 0, |
| 547 | | /* ....C */ ~0, |
| 548 | | /* ...V. */ 0, |
| 549 | | /* ...VC */ ~0, |
| 550 | | /* ..Z.. */ ~0, |
| 551 | | /* ..Z.C */ ~0, |
| 552 | | /* ..ZV. */ ~0, |
| 553 | | /* ..ZVC */ ~0, |
| 554 | | /* .S... */ 0, |
| 555 | | /* .S..C */ ~0, |
| 556 | | /* .S.V. */ 0, |
| 557 | | /* .S.VC */ ~0, |
| 558 | | /* .SZ.. */ ~0, |
| 559 | | /* .SZ.C */ ~0, |
| 560 | | /* .SZV. */ ~0, |
| 561 | | /* .SZVC */ ~0, |
| 562 | | /* U.... */ 0, |
| 563 | | /* U...C */ 0, |
| 564 | | /* U..V. */ 0, |
| 565 | | /* U..VC */ 0, |
| 566 | | /* U.Z.. */ 0, |
| 567 | | /* U.Z.C */ 0, |
| 568 | | /* U.ZV. */ 0, |
| 569 | | /* U.ZVC */ 0, |
| 570 | | /* US... */ 0, |
| 571 | | /* US..C */ 0, |
| 572 | | /* US.V. */ 0, |
| 573 | | /* US.VC */ 0, |
| 574 | | /* USZ.. */ 0, |
| 575 | | /* USZ.C */ 0, |
| 576 | | /* USZV. */ 0, |
| 577 | | /* USZVC */ 0 |
| 578 | | }; |
| 579 | | |
| 580 | | /* flag lookup table for C.ULE */ |
| 581 | | static const UINT32 c_ule_table_source[32] = |
| 582 | | { |
| 583 | | /* ..... */ 0, |
| 584 | | /* ....C */ ~0, |
| 585 | | /* ...V. */ 0, |
| 586 | | /* ...VC */ ~0, |
| 587 | | /* ..Z.. */ ~0, |
| 588 | | /* ..Z.C */ ~0, |
| 589 | | /* ..ZV. */ ~0, |
| 590 | | /* ..ZVC */ ~0, |
| 591 | | /* .S... */ 0, |
| 592 | | /* .S..C */ ~0, |
| 593 | | /* .S.V. */ 0, |
| 594 | | /* .S.VC */ ~0, |
| 595 | | /* .SZ.. */ ~0, |
| 596 | | /* .SZ.C */ ~0, |
| 597 | | /* .SZV. */ ~0, |
| 598 | | /* .SZVC */ ~0, |
| 599 | | /* U.... */ ~0, |
| 600 | | /* U...C */ ~0, |
| 601 | | /* U..V. */ ~0, |
| 602 | | /* U..VC */ ~0, |
| 603 | | /* U.Z.. */ ~0, |
| 604 | | /* U.Z.C */ ~0, |
| 605 | | /* U.ZV. */ ~0, |
| 606 | | /* U.ZVC */ ~0, |
| 607 | | /* US... */ ~0, |
| 608 | | /* US..C */ ~0, |
| 609 | | /* US.V. */ ~0, |
| 610 | | /* US.VC */ ~0, |
| 611 | | /* USZ.. */ ~0, |
| 612 | | /* USZ.C */ ~0, |
| 613 | | /* USZV. */ ~0, |
| 614 | | /* USZVC */ ~0 |
| 615 | | }; |
| 616 | | |
| 617 | | |
| 618 | | |
| 619 | 278 | /*************************************************************************** |
| 620 | 279 | INLINE FUNCTIONS |
| 621 | 280 | ***************************************************************************/ |
| r2821 | r2822 | |
| 738 | 397 | |
| 739 | 398 | /* allocate memory for cache-local state and initialize it */ |
| 740 | 399 | memcpy(mips3->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); |
| 741 | | memcpy(mips3->impstate->slt_table, slt_table_source, sizeof(slt_table_source)); |
| 742 | | memcpy(mips3->impstate->sltu_table, sltu_table_source, sizeof(sltu_table_source)); |
| 743 | | memcpy(mips3->impstate->c_un_table, c_un_table_source, sizeof(c_un_table_source)); |
| 744 | | memcpy(mips3->impstate->c_eq_table, c_eq_table_source, sizeof(c_eq_table_source)); |
| 745 | | memcpy(mips3->impstate->c_ueq_table, c_ueq_table_source, sizeof(c_ueq_table_source)); |
| 746 | | memcpy(mips3->impstate->c_olt_table, c_olt_table_source, sizeof(c_olt_table_source)); |
| 747 | | memcpy(mips3->impstate->c_ult_table, c_ult_table_source, sizeof(c_ult_table_source)); |
| 748 | | memcpy(mips3->impstate->c_ole_table, c_ole_table_source, sizeof(c_ole_table_source)); |
| 749 | | memcpy(mips3->impstate->c_ule_table, c_ule_table_source, sizeof(c_ule_table_source)); |
| 750 | 400 | |
| 751 | 401 | /* compute the register parameters */ |
| 752 | 402 | for (regnum = 0; regnum < 34; regnum++) |
| r2821 | r2822 | |
| 1259 | 909 | |
| 1260 | 910 | /* reset the FPU mode */ |
| 1261 | 911 | UML_AND(block, IREG(0), CCR132(31), IMM(3)); // and i0,ccr1[31],3 |
| 1262 | | UML_LOAD1U(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0)); // load1u i0,fpmode,i0 |
| 912 | UML_LOAD(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0), BYTE); // load i0,fpmode,i0,byte |
| 1263 | 913 | UML_SETFMOD(block, IREG(0)); // setfmod i0 |
| 1264 | 914 | |
| 1265 | 915 | /* load fast integer registers */ |
| r2821 | r2822 | |
| 1370 | 1020 | UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC |
| 1371 | 1021 | UML_MOV(block, MEM(&mips3->pc), IREG(0)); // mov <pc>,i0 |
| 1372 | 1022 | UML_SHR(block, IREG(1), IREG(0), IMM(12)); // shr i1,i0,12 |
| 1373 | | UML_LOAD4(block, IREG(1), mips3->tlb_table, IREG(1)); // load4 i1,[tlb_table],i1 |
| 1023 | UML_LOAD(block, IREG(1), mips3->tlb_table, IREG(1), DWORD); // load i1,[tlb_table],i1,dword |
| 1374 | 1024 | if (PRINTF_MMU) |
| 1375 | 1025 | { |
| 1376 | 1026 | UML_MOV(block, MEM(&mips3->impstate->arg0), IREG(0)); // mov [arg0],i0 |
| r2821 | r2822 | |
| 1433 | 1083 | if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) |
| 1434 | 1084 | { |
| 1435 | 1085 | /* set the upper bits of EntryHi and the lower bits of Context to the fault page */ |
| 1436 | | UML_INSERT(block, CPR032(COP0_EntryHi), IREG(0), IMM(0), IMM(0xffffe000)); // insert [EntryHi],i0,0,0xffffe000 |
| 1437 | | UML_INSERT(block, CPR032(COP0_Context), IREG(0), IMM(32-9), IMM(0x7fffff)); // insert [Context],i0,32-9,0x7fffff |
| 1086 | UML_ROLINS(block, CPR032(COP0_EntryHi), IREG(0), IMM(0), IMM(0xffffe000)); // rolins [EntryHi],i0,0,0xffffe000 |
| 1087 | UML_ROLINS(block, CPR032(COP0_Context), IREG(0), IMM(32-9), IMM(0x7fffff)); // rolins [Context],i0,32-9,0x7fffff |
| 1438 | 1088 | } |
| 1439 | 1089 | |
| 1440 | 1090 | /* set the EPC and Cause registers */ |
| r2821 | r2822 | |
| 1454 | 1104 | UML_MOVc(block, IF_Z, CPR032(COP0_EPC), IREG(0)); // mov [EPC],i0,Z |
| 1455 | 1105 | UML_OR(block, CPR032(COP0_Cause), IREG(2), IMM(exception << 2)); // or [Cause],i2,exception << 2 |
| 1456 | 1106 | |
| 1107 | /* for BADCOP exceptions, we use the exception parameter to know which COP */ |
| 1108 | if (exception == EXCEPTION_BADCOP) |
| 1109 | { |
| 1110 | UML_GETEXP(block, IREG(0)); // getexp i0 |
| 1111 | UML_ROLINS(block, CPR032(COP0_Cause), IREG(0), IMM(28), IMM(0x30000000)); // rolins [Cause],i0,28,0x30000000 |
| 1112 | } |
| 1113 | |
| 1457 | 1114 | /* set EXL in the SR */ |
| 1458 | 1115 | UML_OR(block, IREG(0), CPR032(COP0_Status), IMM(SR_EXL)); // or i0,[Status],SR_EXL |
| 1459 | 1116 | UML_MOV(block, CPR032(COP0_Status), IREG(0)); // mov [Status],i0 |
| r2821 | r2822 | |
| 1529 | 1186 | |
| 1530 | 1187 | /* general case: assume paging and perform a translation */ |
| 1531 | 1188 | UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12 |
| 1532 | | UML_LOAD4(block, IREG(3), mips3->tlb_table, IREG(3)); // load4 i3,[tlb_table],i3 |
| 1189 | UML_LOAD(block, IREG(3), mips3->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword |
| 1533 | 1190 | UML_TEST(block, IREG(3), IMM(iswrite ? TLB_DIRTY : TLB_VALID)); // test i3,iswrite ? TLB_DIRTY : TLB_VALID |
| 1534 | 1191 | UML_JMPc(block, IF_Z, tlbmiss = label++); // jmp tlbmiss,z |
| 1535 | | UML_INSERT(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // insert i0,i3,0,0xfffff000 |
| 1192 | UML_ROLINS(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // rolins i0,i3,0,0xfffff000 |
| 1536 | 1193 | |
| 1537 | 1194 | for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) |
| 1538 | 1195 | if (!Machine->debug_mode && mips3->impstate->fastram[ramnum].base != NULL && (!iswrite || !mips3->impstate->fastram[ramnum].readonly)) |
| r2821 | r2822 | |
| 1556 | 1213 | { |
| 1557 | 1214 | UML_XOR(block, IREG(0), IREG(0), IMM(mips3->bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0))); |
| 1558 | 1215 | // xor i0,i0,bytexor |
| 1559 | | UML_LOAD1U(block, IREG(0), fastbase, IREG(0)); // load1u i0,fastbase,i0 |
| 1216 | UML_LOAD(block, IREG(0), fastbase, IREG(0), BYTE); // load i0,fastbase,i0,byte |
| 1560 | 1217 | } |
| 1561 | 1218 | else if (size == 2) |
| 1562 | 1219 | { |
| 1563 | 1220 | UML_SHR(block, IREG(0), IREG(0), IMM(1)); // shr i0,i0,1 |
| 1564 | 1221 | UML_XOR(block, IREG(0), IREG(0), IMM(mips3->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))); |
| 1565 | 1222 | // xor i0,i0,bytexor |
| 1566 | | UML_LOAD2U(block, IREG(0), fastbase, IREG(0)); // load2u i0,fastbase,i0 |
| 1223 | UML_LOAD(block, IREG(0), fastbase, IREG(0), WORD); // load i0,fastbase,i0,word |
| 1567 | 1224 | } |
| 1568 | 1225 | else if (size == 4) |
| 1569 | 1226 | { |
| 1570 | 1227 | UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2 |
| 1571 | | UML_LOAD4(block, IREG(0), fastbase, IREG(0)); // load4 i0,fastbase,i0 |
| 1228 | UML_LOAD(block, IREG(0), fastbase, IREG(0), DWORD); // load i0,fastbase,i0,dword |
| 1572 | 1229 | } |
| 1573 | 1230 | else if (size == 8) |
| 1574 | 1231 | { |
| 1575 | 1232 | UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3 |
| 1576 | | UML_DLOAD8(block, IREG(0), fastbase, IREG(0)); // dload8 i0,fastbase,i0 |
| 1233 | UML_DLOAD(block, IREG(0), fastbase, IREG(0), QWORD); // dload i0,fastbase,i0,qword |
| 1577 | 1234 | UML_DROR(block, IREG(0), IREG(0), IMM(32 * (mips3->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)))); |
| 1578 | 1235 | // dror i0,i0,32*bytexor |
| 1579 | 1236 | } |
| r2821 | r2822 | |
| 1585 | 1242 | { |
| 1586 | 1243 | UML_XOR(block, IREG(0), IREG(0), IMM(mips3->bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0))); |
| 1587 | 1244 | // xor i0,i0,bytexor |
| 1588 | | UML_STORE1(block, fastbase, IREG(0), IREG(1)); // store1 fastbase,i0,i1 |
| 1245 | UML_STORE(block, fastbase, IREG(0), IREG(1), BYTE); // store fastbase,i0,i1,byte |
| 1589 | 1246 | } |
| 1590 | 1247 | else if (size == 2) |
| 1591 | 1248 | { |
| 1592 | 1249 | UML_SHR(block, IREG(0), IREG(0), IMM(1)); // shr i0,i0,1 |
| 1593 | 1250 | UML_XOR(block, IREG(0), IREG(0), IMM(mips3->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))); |
| 1594 | 1251 | // xor i0,i0,bytexor |
| 1595 | | UML_STORE2(block, fastbase, IREG(0), IREG(1)); // store2 fastbase,i0,i1 |
| 1252 | UML_STORE(block, fastbase, IREG(0), IREG(1), WORD); // store fastbase,i0,i1,word |
| 1596 | 1253 | } |
| 1597 | 1254 | else if (size == 4) |
| 1598 | 1255 | { |
| 1599 | 1256 | UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2 |
| 1600 | 1257 | if (ismasked) |
| 1601 | 1258 | { |
| 1602 | | UML_LOAD4(block, IREG(3), fastbase, IREG(0)); // load4 i3,fastbase,i0 |
| 1603 | | UML_INSERT(block, IREG(3), IREG(1), IMM(0), IREG(2)); // insert i3,i1,0,i2 |
| 1604 | | UML_STORE4(block, fastbase, IREG(0), IREG(3)); // store4 fastbase,i0,i3 |
| 1259 | UML_LOAD(block, IREG(3), fastbase, IREG(0), DWORD); // load i3,fastbase,i0,dword |
| 1260 | UML_ROLINS(block, IREG(3), IREG(1), IMM(0), IREG(2)); // rolins i3,i1,0,i2 |
| 1261 | UML_STORE(block, fastbase, IREG(0), IREG(3), DWORD); // store fastbase,i0,i3,dword |
| 1605 | 1262 | } |
| 1606 | 1263 | else |
| 1607 | | UML_STORE4(block, fastbase, IREG(0), IREG(1)); // store4 fastbase,i0,i1 |
| 1264 | UML_STORE(block, fastbase, IREG(0), IREG(1), DWORD); // store fastbase,i0,i1,dword |
| 1608 | 1265 | } |
| 1609 | 1266 | else if (size == 8) |
| 1610 | 1267 | { |
| r2821 | r2822 | |
| 1615 | 1272 | { |
| 1616 | 1273 | UML_DROR(block, IREG(2), IREG(2), IMM(32 * (mips3->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)))); |
| 1617 | 1274 | // dror i2,i2,32*bytexor |
| 1618 | | UML_DLOAD8(block, IREG(3), fastbase, IREG(0)); // dload8 i3,fastbase,i0 |
| 1619 | | UML_DINSERT(block, IREG(3), IREG(1), IMM(0), IREG(2)); // dinsert i3,i1,0,i2 |
| 1620 | | UML_DSTORE8(block, fastbase, IREG(0), IREG(3)); // dstore8 fastbase,i0,i3 |
| 1275 | UML_DLOAD(block, IREG(3), fastbase, IREG(0), QWORD); // dload i3,fastbase,i0,qword |
| 1276 | UML_DROLINS(block, IREG(3), IREG(1), IMM(0), IREG(2)); // drolins i3,i1,0,i2 |
| 1277 | UML_DSTORE(block, fastbase, IREG(0), IREG(3), QWORD); // dstore fastbase,i0,i3,qword |
| 1621 | 1278 | } |
| 1622 | 1279 | else |
| 1623 | | UML_DSTORE8(block, fastbase, IREG(0), IREG(1)); // dstore8 fastbase,i0,i1 |
| 1280 | UML_DSTORE(block, fastbase, IREG(0), IREG(1), QWORD); // dstore fastbase,i0,i1,qword |
| 1624 | 1281 | } |
| 1625 | 1282 | UML_RET(block); // ret |
| 1626 | 1283 | } |
| r2821 | r2822 | |
| 1632 | 1289 | { |
| 1633 | 1290 | case 1: |
| 1634 | 1291 | if (iswrite) |
| 1635 | | UML_WRITE1(block, PROGRAM, IREG(0), IREG(1)); // write1 i0,i1 |
| 1292 | UML_WRITE(block, IREG(0), IREG(1), PROGRAM_BYTE); // write i0,i1,program_byte |
| 1636 | 1293 | else |
| 1637 | | UML_READ1U(block, IREG(0), PROGRAM, IREG(0)); // read1u i0,i0 |
| 1294 | UML_READ(block, IREG(0), IREG(0), PROGRAM_BYTE); // read i0,i0,program_byte |
| 1638 | 1295 | break; |
| 1639 | 1296 | |
| 1640 | 1297 | case 2: |
| 1641 | 1298 | if (iswrite) |
| 1642 | | UML_WRITE2(block, PROGRAM, IREG(0), IREG(1)); // write2 i0,i1 |
| 1299 | UML_WRITE(block, IREG(0), IREG(1), PROGRAM_WORD); // write i0,i1,program_word |
| 1643 | 1300 | else |
| 1644 | | UML_READ2U(block, IREG(0), PROGRAM, IREG(0)); // read2u i0,i0 |
| 1301 | UML_READ(block, IREG(0), IREG(0), PROGRAM_WORD); // read i0,i0,program_word |
| 1645 | 1302 | break; |
| 1646 | 1303 | |
| 1647 | 1304 | case 4: |
| 1648 | 1305 | if (iswrite) |
| 1649 | 1306 | { |
| 1650 | 1307 | if (!ismasked) |
| 1651 | | UML_WRITE4(block, PROGRAM, IREG(0), IREG(1)); // write4 PROGRAM,i0,i1 |
| 1308 | UML_WRITE(block, IREG(0), IREG(1), PROGRAM_DWORD); // write i0,i1,program_dword |
| 1652 | 1309 | else |
| 1653 | | UML_WRIT4M(block, PROGRAM, IREG(0), IREG(2), IREG(1)); // writ4m PROGRAM,i0,i2,i1 |
| 1310 | UML_WRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_DWORD); // writem i0,i2,i1,program_dword |
| 1654 | 1311 | } |
| 1655 | 1312 | else |
| 1656 | 1313 | { |
| 1657 | 1314 | if (!ismasked) |
| 1658 | | UML_READ4(block, IREG(0), PROGRAM, IREG(0)); // read4 i0,PROGRAM,i0 |
| 1315 | UML_READ(block, IREG(0), IREG(0), PROGRAM_DWORD); // read i0,i0,program_dword |
| 1659 | 1316 | else |
| 1660 | | UML_READ4M(block, IREG(0), PROGRAM, IREG(0), IREG(2)); // read4m i0,PROGRAM,i0,i2 |
| 1317 | UML_READM(block, IREG(0), IREG(0), IREG(2), PROGRAM_DWORD); // readm i0,i0,i2,program_dword |
| 1661 | 1318 | } |
| 1662 | 1319 | break; |
| 1663 | 1320 | |
| r2821 | r2822 | |
| 1665 | 1322 | if (iswrite) |
| 1666 | 1323 | { |
| 1667 | 1324 | if (!ismasked) |
| 1668 | | UML_DWRITE8(block, PROGRAM, IREG(0), IREG(1)); // dwrite8 PROGRAM,i0,i1 |
| 1325 | UML_DWRITE(block, IREG(0), IREG(1), PROGRAM_QWORD); // dwrite i0,i1,program_qword |
| 1669 | 1326 | else |
| 1670 | | UML_DWRIT8M(block, PROGRAM, IREG(0), IREG(2), IREG(1)); // dwrit8m PROGRAM,i0,i2,i1 |
| 1327 | UML_DWRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_QWORD); // dwritem i0,i2,i1,program_qword |
| 1671 | 1328 | } |
| 1672 | 1329 | else |
| 1673 | 1330 | { |
| 1674 | 1331 | if (!ismasked) |
| 1675 | | UML_DREAD8(block, IREG(0), PROGRAM, IREG(0)); // dread8 i0,PROGRAM,i0 |
| 1332 | UML_DREAD(block, IREG(0), IREG(0), PROGRAM_QWORD); // dread i0,i0,program_qword |
| 1676 | 1333 | else |
| 1677 | | UML_DREAD8M(block, IREG(0), PROGRAM, IREG(0), IREG(2)); // dread8m i0,PROGRAM,i0,i2 |
| 1334 | UML_DREADM(block, IREG(0), IREG(0), IREG(2), PROGRAM_QWORD); // dreadm i0,i0,i2,program_qword |
| 1678 | 1335 | } |
| 1679 | 1336 | break; |
| 1680 | 1337 | } |
| r2821 | r2822 | |
| 1710 | 1367 | |
| 1711 | 1368 | static void generate_update_mode(drcuml_block *block) |
| 1712 | 1369 | { |
| 1713 | | UML_XTRACT(block, IREG(2), IREG(0), IMM(32-2), IMM(0x06)); // xtract i2,i0,32-2,0x06 |
| 1370 | UML_ROLAND(block, IREG(2), IREG(0), IMM(32-2), IMM(0x06)); // roland i2,i0,32-2,0x06 |
| 1714 | 1371 | UML_TEST(block, IREG(0), IMM(SR_EXL | SR_ERL)); // test i0,SR_EXL | SR_ERL |
| 1715 | 1372 | UML_MOVc(block, IF_NZ, IREG(2), IMM(0)); // mov i2,0,nz |
| 1716 | | UML_INSERT(block, IREG(2), IREG(0), IMM(32-26), IMM(0x01)); // insert i2,i0,32-26,0x01 |
| 1373 | UML_ROLINS(block, IREG(2), IREG(0), IMM(32-26), IMM(0x01)); // rolins i2,i0,32-26,0x01 |
| 1717 | 1374 | UML_MOV(block, MEM(&mips3->impstate->mode), IREG(2)); // mov [mode],i2 |
| 1718 | 1375 | } |
| 1719 | 1376 | |
| r2821 | r2822 | |
| 1790 | 1447 | { |
| 1791 | 1448 | if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1792 | 1449 | { |
| 1793 | | UML_LOAD4(block, IREG(0), seqhead->opptr.l, IMM(0)); // load4 i0,*opptr |
| 1450 | UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,0,dword |
| 1794 | 1451 | UML_CMP(block, IREG(0), IMM(*seqhead->opptr.l)); // cmp i0,*opptr |
| 1795 | 1452 | UML_EXHc(block, IF_NE, mips3->impstate->nocode, IMM(epc(seqhead))); // exne nocode,seqhead->pc |
| 1796 | 1453 | } |
| r2821 | r2822 | |
| 1803 | 1460 | for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) |
| 1804 | 1461 | if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1805 | 1462 | { |
| 1806 | | UML_LOAD4(block, IREG(0), curdesc->opptr.l, IMM(0)); // load4 i0,*opptr |
| 1463 | UML_LOAD(block, IREG(0), curdesc->opptr.l, IMM(0), DWORD); // load i0,*opptr,0,dword |
| 1807 | 1464 | UML_CMP(block, IREG(0), IMM(*curdesc->opptr.l)); // cmp i0,*opptr |
| 1808 | 1465 | UML_EXHc(block, IF_NE, mips3->impstate->nocode, IMM(epc(seqhead))); // exne nocode,seqhead->pc |
| 1809 | 1466 | } |
| 1810 | 1467 | #else |
| 1811 | 1468 | UINT32 sum = 0; |
| 1812 | | UML_LOAD4(block, IREG(0), seqhead->opptr.l, IMM(0)); // load4 i0,*opptr |
| 1469 | UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,0,dword |
| 1813 | 1470 | sum += *seqhead->opptr.l; |
| 1814 | 1471 | for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) |
| 1815 | 1472 | if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) |
| 1816 | 1473 | { |
| 1817 | | UML_LOAD4(block, IREG(1), curdesc->opptr.l, IMM(0)); // load4 i1,*opptr |
| 1474 | UML_LOAD(block, IREG(1), curdesc->opptr.l, IMM(0), DWORD); // load i1,*opptr,dword |
| 1818 | 1475 | UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1 |
| 1819 | 1476 | sum += *curdesc->opptr.l; |
| 1820 | 1477 | } |
| r2821 | r2822 | |
| 1899 | 1556 | UML_MOV(block, MEM(&mips3->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc |
| 1900 | 1557 | UML_CALLC(block, cfunc_printf_debug, "Checking TLB at @ %08X\n"); // callc printf_debug |
| 1901 | 1558 | } |
| 1902 | | UML_LOAD4(block, IREG(0), &mips3->tlb_table[desc->pc >> 12], IMM(0)); // load4 i0,tlb_table[desc->pc >> 12] |
| 1559 | UML_LOAD(block, IREG(0), &mips3->tlb_table[desc->pc >> 12], IMM(0), DWORD);// load i0,tlb_table[desc->pc >> 12],0,dword |
| 1903 | 1560 | UML_CMP(block, IREG(0), IMM(mips3->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry |
| 1904 | 1561 | UML_EXHc(block, IF_NE, mips3->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE |
| 1905 | 1562 | } |
| r2821 | r2822 | |
| 1944 | 1601 | |
| 1945 | 1602 | /* set the link if needed */ |
| 1946 | 1603 | if (linkreg != 0) |
| 1947 | | UML_DSEXT4(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dsext4 <linkreg>,desc->pc + 8 |
| 1604 | UML_DMOV(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dmov <linkreg>,desc->pc + 8 |
| 1948 | 1605 | |
| 1949 | 1606 | /* compile the delay slot using temporary compiler state */ |
| 1950 | 1607 | assert(desc->delay != NULL); |
| r2821 | r2822 | |
| 2054 | 1711 | |
| 2055 | 1712 | case 0x0f: /* LUI - MIPS I */ |
| 2056 | 1713 | if (RTREG != 0) |
| 2057 | | UML_DSEXT4(block, R64(RTREG), IMM(SIMMVAL << 16)); // dsext4 <rtreg>,SIMMVAL << 16 |
| 1714 | UML_DMOV(block, R64(RTREG), IMM(SIMMVAL << 16)); // dmov <rtreg>,SIMMVAL << 16 |
| 2058 | 1715 | return TRUE; |
| 2059 | 1716 | |
| 2060 | 1717 | case 0x08: /* ADDI - MIPS I */ |
| r2821 | r2822 | |
| 2067 | 1724 | else |
| 2068 | 1725 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2069 | 1726 | if (RTREG != 0) |
| 2070 | | UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0 |
| 1727 | UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0,dword |
| 2071 | 1728 | return TRUE; |
| 2072 | 1729 | |
| 2073 | 1730 | case 0x09: /* ADDIU - MIPS I */ |
| 2074 | 1731 | if (RTREG != 0) |
| 2075 | 1732 | { |
| 2076 | 1733 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL,V |
| 2077 | | UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0 |
| 1734 | UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0,dword |
| 2078 | 1735 | } |
| 2079 | 1736 | return TRUE; |
| 2080 | 1737 | |
| r2821 | r2822 | |
| 2115 | 1772 | if (RTREG != 0) |
| 2116 | 1773 | { |
| 2117 | 1774 | UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL |
| 2118 | | UML_DFLAGS(block, R64(RTREG), (UINT64)~0, mips3->impstate->slt_table); |
| 2119 | | // dflags <rtreg>,~0,slt_table |
| 1775 | UML_DSETc(block, IF_L, R64(RTREG)); // dset <rtreg>,l |
| 2120 | 1776 | } |
| 2121 | 1777 | return TRUE; |
| 2122 | 1778 | |
| r2821 | r2822 | |
| 2124 | 1780 | if (RTREG != 0) |
| 2125 | 1781 | { |
| 2126 | 1782 | UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL |
| 2127 | | UML_DFLAGS(block, R64(RTREG), (UINT64)~0, mips3->impstate->sltu_table); |
| 2128 | | // dflags <rtreg>,~0,sltu_table |
| 1783 | UML_DSETc(block, IF_B, R64(RTREG)); // dset <rtreg>,b |
| 2129 | 1784 | } |
| 2130 | 1785 | return TRUE; |
| 2131 | 1786 | |
| r2821 | r2822 | |
| 2136 | 1791 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2137 | 1792 | UML_CALLH(block, mips3->impstate->read8[mips3->impstate->mode >> 1]); // callh read8 |
| 2138 | 1793 | if (RTREG != 0) |
| 2139 | | UML_DSEXT1(block, R64(RTREG), IREG(0)); // dsext1 <rtreg>,i0 |
| 1794 | UML_DSEXT(block, R64(RTREG), IREG(0), BYTE); // dsext <rtreg>,i0,byte |
| 2140 | 1795 | if (!in_delay_slot) |
| 2141 | 1796 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2142 | 1797 | return TRUE; |
| r2821 | r2822 | |
| 2145 | 1800 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2146 | 1801 | UML_CALLH(block, mips3->impstate->read16[mips3->impstate->mode >> 1]); // callh read16 |
| 2147 | 1802 | if (RTREG != 0) |
| 2148 | | UML_DSEXT2(block, R64(RTREG), IREG(0)); // dsext2 <rtreg>,i0 |
| 1803 | UML_DSEXT(block, R64(RTREG), IREG(0), WORD); // dsext <rtreg>,i0,word |
| 2149 | 1804 | if (!in_delay_slot) |
| 2150 | 1805 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2151 | 1806 | return TRUE; |
| r2821 | r2822 | |
| 2154 | 1809 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2155 | 1810 | UML_CALLH(block, mips3->impstate->read32[mips3->impstate->mode >> 1]); // callh read32 |
| 2156 | 1811 | if (RTREG != 0) |
| 2157 | | UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0 |
| 1812 | UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0 |
| 2158 | 1813 | if (!in_delay_slot) |
| 2159 | 1814 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2160 | 1815 | return TRUE; |
| r2821 | r2822 | |
| 2163 | 1818 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2164 | 1819 | UML_CALLH(block, mips3->impstate->read8[mips3->impstate->mode >> 1]); // callh read8 |
| 2165 | 1820 | if (RTREG != 0) |
| 2166 | | UML_DZEXT1(block, R64(RTREG), IREG(0)); // dzext1 <rtreg>,i0 |
| 1821 | UML_DAND(block, R64(RTREG), IREG(0), IMM(0xff)); // dand <rtreg>,i0,0xff |
| 2167 | 1822 | if (!in_delay_slot) |
| 2168 | 1823 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2169 | 1824 | return TRUE; |
| r2821 | r2822 | |
| 2172 | 1827 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2173 | 1828 | UML_CALLH(block, mips3->impstate->read16[mips3->impstate->mode >> 1]); // callh read16 |
| 2174 | 1829 | if (RTREG != 0) |
| 2175 | | UML_DZEXT2(block, R64(RTREG), IREG(0)); // dzext2 <rtreg>,i0 |
| 1830 | UML_DAND(block, R64(RTREG), IREG(0), IMM(0xffff)); // dand <rtreg>,i0,0xffff |
| 2176 | 1831 | if (!in_delay_slot) |
| 2177 | 1832 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2178 | 1833 | return TRUE; |
| r2821 | r2822 | |
| 2181 | 1836 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2182 | 1837 | UML_CALLH(block, mips3->impstate->read32[mips3->impstate->mode >> 1]); // callh read32 |
| 2183 | 1838 | if (RTREG != 0) |
| 2184 | | UML_DZEXT4(block, R64(RTREG), IREG(0)); // dzext4 <rtreg>,i0 |
| 1839 | UML_DAND(block, R64(RTREG), IREG(0), IMM(0xffffffff)); // dand <rtreg>,i0,0xffffffff |
| 2185 | 1840 | if (!in_delay_slot) |
| 2186 | 1841 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2187 | 1842 | return TRUE; |
| r2821 | r2822 | |
| 2207 | 1862 | { |
| 2208 | 1863 | UML_SHL(block, IREG(2), IMM(~0), IREG(1)); // shl i2,~0,i1 |
| 2209 | 1864 | UML_MOV(block, IREG(3), R32(RTREG)); // mov i3,<rtreg> |
| 2210 | | UML_INSERT(block, IREG(3), IREG(0), IREG(1), IREG(2)); // insert i3,i0,i1,i2 |
| 2211 | | UML_DSEXT4(block, R64(RTREG), IREG(3)); // dsext4 <rtreg>,i3 |
| 1865 | UML_ROLINS(block, IREG(3), IREG(0), IREG(1), IREG(2)); // rolins i3,i0,i1,i2 |
| 1866 | UML_DSEXT(block, R64(RTREG), IREG(3), DWORD); // dsext <rtreg>,i3,dword |
| 2212 | 1867 | } |
| 2213 | 1868 | if (!in_delay_slot) |
| 2214 | 1869 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| r2821 | r2822 | |
| 2227 | 1882 | UML_SHR(block, IREG(2), IMM(~0), IREG(1)); // shr i2,~0,i1 |
| 2228 | 1883 | UML_SUB(block, IREG(1), IMM(32), IREG(1)); // sub i1,32,i1 |
| 2229 | 1884 | UML_MOV(block, IREG(3), R32(RTREG)); // mov i3,<rtreg> |
| 2230 | | UML_INSERT(block, IREG(3), IREG(0), IREG(1), IREG(2)); // insert i3,i0,i1,i2 |
| 2231 | | UML_DSEXT4(block, R64(RTREG), IREG(3)); // dsext4 <rtreg>,i3 |
| 1885 | UML_ROLINS(block, IREG(3), IREG(0), IREG(1), IREG(2)); // rolins i3,i0,i1,i2 |
| 1886 | UML_DSEXT(block, R64(RTREG), IREG(3), DWORD); // dsext <rtreg>,i3,dword |
| 2232 | 1887 | } |
| 2233 | 1888 | if (!in_delay_slot) |
| 2234 | 1889 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| r2821 | r2822 | |
| 2245 | 1900 | if (RTREG != 0) |
| 2246 | 1901 | { |
| 2247 | 1902 | UML_DSHL(block, IREG(2), IMM((UINT64)~0), IREG(1)); // dshl i2,~0,i1 |
| 2248 | | UML_DINSERT(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // dinsert <rtreg>,i0,i1,i2 |
| 1903 | UML_DROLINS(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // drolins <rtreg>,i0,i1,i2 |
| 2249 | 1904 | } |
| 2250 | 1905 | if (!in_delay_slot) |
| 2251 | 1906 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| r2821 | r2822 | |
| 2263 | 1918 | { |
| 2264 | 1919 | UML_DSHR(block, IREG(2), IMM((UINT64)~0), IREG(1)); // dshr i2,~0,i1 |
| 2265 | 1920 | UML_SUB(block, IREG(1), IMM(64), IREG(1)); // sub i1,64,i1 |
| 2266 | | UML_DINSERT(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // dinsert <rtreg>,i0,i1,i2 |
| 1921 | UML_DROLINS(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // drolins <rtreg>,i0,i1,i2 |
| 2267 | 1922 | } |
| 2268 | 1923 | if (!in_delay_slot) |
| 2269 | 1924 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| r2821 | r2822 | |
| 2288 | 1943 | case 0x32: /* LWC2 - MIPS I */ |
| 2289 | 1944 | UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL |
| 2290 | 1945 | UML_CALLH(block, mips3->impstate->read32[mips3->impstate->mode >> 1]); // callh read32 |
| 2291 | | UML_DZEXT4(block, CPR264(RTREG), IREG(0)); // dzext4 <cpr2_rt>,i0 |
| 1946 | UML_DAND(block, CPR264(RTREG), IREG(0), IMM(0xffffffff)); // dand <cpr2_rt>,i0,0xffffffff |
| 2292 | 1947 | if (!in_delay_slot) |
| 2293 | 1948 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| 2294 | 1949 | return TRUE; |
| r2821 | r2822 | |
| 2479 | 2134 | if (RDREG != 0) |
| 2480 | 2135 | { |
| 2481 | 2136 | UML_SHL(block, IREG(0), R32(RTREG), IMM(SHIFT)); // shl i0,<rtreg>,<shift> |
| 2482 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2137 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2483 | 2138 | } |
| 2484 | 2139 | return TRUE; |
| 2485 | 2140 | |
| r2821 | r2822 | |
| 2487 | 2142 | if (RDREG != 0) |
| 2488 | 2143 | { |
| 2489 | 2144 | UML_SHR(block, IREG(0), R32(RTREG), IMM(SHIFT)); // shr i0,<rtreg>,<shift> |
| 2490 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2145 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2491 | 2146 | } |
| 2492 | 2147 | return TRUE; |
| 2493 | 2148 | |
| r2821 | r2822 | |
| 2495 | 2150 | if (RDREG != 0) |
| 2496 | 2151 | { |
| 2497 | 2152 | UML_SAR(block, IREG(0), R32(RTREG), IMM(SHIFT)); // sar i0,<rtreg>,<shift> |
| 2498 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2153 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2499 | 2154 | } |
| 2500 | 2155 | return TRUE; |
| 2501 | 2156 | |
| r2821 | r2822 | |
| 2503 | 2158 | if (RDREG != 0) |
| 2504 | 2159 | { |
| 2505 | 2160 | UML_SHL(block, IREG(0), R32(RTREG), R32(RSREG)); // shl i0,<rtreg>,<rsreg> |
| 2506 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2161 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2507 | 2162 | } |
| 2508 | 2163 | return TRUE; |
| 2509 | 2164 | |
| r2821 | r2822 | |
| 2511 | 2166 | if (RDREG != 0) |
| 2512 | 2167 | { |
| 2513 | 2168 | UML_SHR(block, IREG(0), R32(RTREG), R32(RSREG)); // shr i0,<rtreg>,<rsreg> |
| 2514 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2169 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2515 | 2170 | } |
| 2516 | 2171 | return TRUE; |
| 2517 | 2172 | |
| r2821 | r2822 | |
| 2519 | 2174 | if (RDREG != 0) |
| 2520 | 2175 | { |
| 2521 | 2176 | UML_SAR(block, IREG(0), R32(RTREG), R32(RSREG)); // sar i0,<rtreg>,<rsreg> |
| 2522 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2177 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2523 | 2178 | } |
| 2524 | 2179 | return TRUE; |
| 2525 | 2180 | |
| r2821 | r2822 | |
| 2578 | 2233 | UML_EXHc(block, IF_V, mips3->impstate->exception[EXCEPTION_OVERFLOW], IMM(0)); |
| 2579 | 2234 | // exh overflow,0,V |
| 2580 | 2235 | if (RDREG != 0) |
| 2581 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2236 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2582 | 2237 | } |
| 2583 | 2238 | else if (RDREG != 0) |
| 2584 | 2239 | { |
| 2585 | 2240 | UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg> |
| 2586 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2241 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2587 | 2242 | } |
| 2588 | 2243 | return TRUE; |
| 2589 | 2244 | |
| r2821 | r2822 | |
| 2591 | 2246 | if (RDREG != 0) |
| 2592 | 2247 | { |
| 2593 | 2248 | UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg> |
| 2594 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2249 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2595 | 2250 | } |
| 2596 | 2251 | return TRUE; |
| 2597 | 2252 | |
| r2821 | r2822 | |
| 2620 | 2275 | UML_EXHc(block, IF_V, mips3->impstate->exception[EXCEPTION_OVERFLOW], IMM(0)); |
| 2621 | 2276 | // exh overflow,0,V |
| 2622 | 2277 | if (RDREG != 0) |
| 2623 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2278 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2624 | 2279 | } |
| 2625 | 2280 | else if (RDREG != 0) |
| 2626 | 2281 | { |
| 2627 | 2282 | UML_SUB(block, IREG(0), R32(RSREG), R32(RTREG)); // sub i0,<rsreg>,<rtreg> |
| 2628 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2283 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2629 | 2284 | } |
| 2630 | 2285 | return TRUE; |
| 2631 | 2286 | |
| r2821 | r2822 | |
| 2633 | 2288 | if (RDREG != 0) |
| 2634 | 2289 | { |
| 2635 | 2290 | UML_SUB(block, IREG(0), R32(RSREG), R32(RTREG)); // sub i0,<rsreg>,<rtreg> |
| 2636 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 |
| 2291 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword |
| 2637 | 2292 | } |
| 2638 | 2293 | return TRUE; |
| 2639 | 2294 | |
| r2821 | r2822 | |
| 2657 | 2312 | |
| 2658 | 2313 | case 0x18: /* MULT - MIPS I */ |
| 2659 | 2314 | UML_MULS(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // muls i0,i1,<rsreg>,<rtreg> |
| 2660 | | UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 |
| 2661 | | UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1 |
| 2315 | UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword |
| 2316 | UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword |
| 2662 | 2317 | return TRUE; |
| 2663 | 2318 | |
| 2664 | 2319 | case 0x19: /* MULTU - MIPS I */ |
| 2665 | 2320 | UML_MULU(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // mulu i0,i1,<rsreg>,<rtreg> |
| 2666 | | UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 |
| 2667 | | UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1 |
| 2321 | UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword |
| 2322 | UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword |
| 2668 | 2323 | return TRUE; |
| 2669 | 2324 | |
| 2670 | 2325 | case 0x1c: /* DMULT - MIPS III */ |
| r2821 | r2822 | |
| 2677 | 2332 | |
| 2678 | 2333 | case 0x1a: /* DIV - MIPS I */ |
| 2679 | 2334 | UML_DIVS(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // divs i0,i1,<rsreg>,<rtreg> |
| 2680 | | UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 |
| 2681 | | UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1 |
| 2335 | UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword |
| 2336 | UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword |
| 2682 | 2337 | return TRUE; |
| 2683 | 2338 | |
| 2684 | 2339 | case 0x1b: /* DIVU - MIPS I */ |
| 2685 | 2340 | UML_DIVU(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // divu i0,i1,<rsreg>,<rtreg> |
| 2686 | | UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 |
| 2687 | | UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1 |
| 2341 | UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword |
| 2342 | UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword |
| 2688 | 2343 | return TRUE; |
| 2689 | 2344 | |
| 2690 | 2345 | case 0x1e: /* DDIV - MIPS III */ |
| r2821 | r2822 | |
| 2728 | 2383 | if (RDREG != 0) |
| 2729 | 2384 | { |
| 2730 | 2385 | UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg> |
| 2731 | | UML_DFLAGS(block, R64(RDREG), (UINT64)~0, mips3->impstate->slt_table);// dflags <rdreg>,~0,slt_table |
| 2386 | UML_DSETc(block, IF_L, R64(RDREG)); // dset <rdreg>,l |
| 2732 | 2387 | } |
| 2733 | 2388 | return TRUE; |
| 2734 | 2389 | |
| r2821 | r2822 | |
| 2736 | 2391 | if (RDREG != 0) |
| 2737 | 2392 | { |
| 2738 | 2393 | UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg> |
| 2739 | | UML_DFLAGS(block, R64(RDREG), (UINT64)~0, mips3->impstate->sltu_table);// dflags <rdreg>,~0,sltu_table |
| 2394 | UML_DSETc(block, IF_B, R64(RDREG)); // dset <rdreg>,b |
| 2740 | 2395 | } |
| 2741 | 2396 | return TRUE; |
| 2742 | 2397 | |
| r2821 | r2822 | |
| 2795 | 2450 | case 0x01: /* MOVF/MOVT - MIPS IV */ |
| 2796 | 2451 | if (RDREG != 0) |
| 2797 | 2452 | { |
| 2798 | | UML_TEST(block, CCR132(31), IMM(fcc_mask[(op >> 18) & 7])); // test ccr31,fcc_mask[x] |
| 2453 | UML_TEST(block, CCR132(31), IMM(FCCMASK(op >> 18))); // test ccr31,fcc_mask[x] |
| 2799 | 2454 | UML_DMOVc(block, ((op >> 16) & 1) ? IF_NZ : IF_Z, R64(RDREG), R64(RSREG)); |
| 2800 | 2455 | // mov <rdreg>,<rsreg>,NZ/Z |
| 2801 | 2456 | } |
| r2821 | r2822 | |
| 2954 | 2609 | UML_MULS(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // muls i0,i1,rsreg,rtreg |
| 2955 | 2610 | UML_ADDf(block, FLAGS_C, IREG(0), IREG(0), LO32); // add i0,i0,lo |
| 2956 | 2611 | UML_ADDC(block, IREG(1), IREG(1), HI32); // addc i1,i1,hi |
| 2957 | | UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 |
| 2958 | | UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i0 |
| 2612 | UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword |
| 2613 | UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword |
| 2959 | 2614 | } |
| 2960 | 2615 | return TRUE; |
| 2961 | 2616 | |
| r2821 | r2822 | |
| 2965 | 2620 | UML_MULU(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // mulu i0,i1,rsreg,rtreg |
| 2966 | 2621 | UML_ADDf(block, FLAGS_C, IREG(0), IREG(0), LO32); // add i0,i0,lo |
| 2967 | 2622 | UML_ADDC(block, IREG(1), IREG(1), HI32); // addc i1,i1,hi |
| 2968 | | UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 |
| 2969 | | UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i0 |
| 2623 | UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword |
| 2624 | UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword |
| 2970 | 2625 | } |
| 2971 | 2626 | return TRUE; |
| 2972 | 2627 | |
| r2821 | r2822 | |
| 2974 | 2629 | if (RDREG != 0) |
| 2975 | 2630 | { |
| 2976 | 2631 | UML_MULS(block, IREG(0), IREG(0), R32(RSREG), R32(RTREG)); // muls i0,i0,rsreg,rtreg |
| 2977 | | UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 rdreg,i0 |
| 2632 | UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext rdreg,i0,dword |
| 2978 | 2633 | } |
| 2979 | 2634 | return TRUE; |
| 2980 | 2635 | } |
| r2821 | r2822 | |
| 2995 | 2650 | switch (reg) |
| 2996 | 2651 | { |
| 2997 | 2652 | case COP0_Cause: |
| 2998 | | UML_INSERT(block, CPR032(COP0_Cause), IREG(0), IMM(0), IMM(~0xfc00)); // insert [Cause],i0,0,~0xfc00 |
| 2653 | UML_ROLINS(block, CPR032(COP0_Cause), IREG(0), IMM(0), IMM(~0xfc00)); // rolins [Cause],i0,0,~0xfc00 |
| 2999 | 2654 | compiler->checksoftints = TRUE; |
| 3000 | 2655 | if (!in_delay_slot) |
| 3001 | 2656 | generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); |
| r2821 | r2822 | |
| 3018 | 2673 | generate_update_cycles(block, compiler, IMM(desc->pc), !in_delay_slot); // <subtract cycles> |
| 3019 | 2674 | UML_MOV(block, CPR032(COP0_Count), IREG(0)); // mov [Count],i0 |
| 3020 | 2675 | UML_CALLC(block, cfunc_get_cycles, &mips3->impstate->numcycles); // callc cfunc_get_cycles,&mips3->impstate->numcycles |
| 3021 | | UML_DZEXT4(block, IREG(0), IREG(0)); // dzext4 i0,i0 |
| 2676 | UML_DAND(block, IREG(0), IREG(0), IMM(0xffffffff)); // and i0,i0,0xffffffff |
| 3022 | 2677 | UML_DADD(block, IREG(0), IREG(0), IREG(0)); // dadd i0,i0,i0 |
| 3023 | 2678 | UML_DSUB(block, MEM(&mips3->count_zero_time), MEM(&mips3->impstate->numcycles), IREG(0)); |
| 3024 | 2679 | // dsub [count_zero_time],[mips3->impstate->numcycles],i0 |
| r2821 | r2822 | |
| 3036 | 2691 | return TRUE; |
| 3037 | 2692 | |
| 3038 | 2693 | case COP0_Config: |
| 3039 | | UML_INSERT(block, CPR032(COP0_Config), IREG(0), IMM(0), IMM(0x0007)); // insert [Config],i0,0,0x0007 |
| 2694 | UML_ROLINS(block, CPR032(COP0_Config), IREG(0), IMM(0), IMM(0x0007)); // rolins [Config],i0,0,0x0007 |
| 3040 | 2695 | return TRUE; |
| 3041 | 2696 | |
| 3042 | 2697 | case COP0_EntryHi: |
| r2821 | r2822 | |
| 3073 | 2728 | UML_DSUB(block, IREG(0), MEM(&mips3->impstate->numcycles), MEM(&mips3->count_zero_time)); |
| 3074 | 2729 | // dsub i0,[numcycles],[count_zero_time] |
| 3075 | 2730 | UML_DSHR(block, IREG(0), IREG(0), IMM(1)); // dshr i0,i0,1 |
| 3076 | | UML_DSEXT4(block, IREG(0), IREG(0)); // dsext4 i0,i0 |
| 2731 | UML_DSEXT(block, IREG(0), IREG(0), DWORD); // dsext i0,i0,dword |
| 3077 | 2732 | return TRUE; |
| 3078 | 2733 | |
| 3079 | 2734 | case COP0_Random: |
| r2821 | r2822 | |
| 3084 | 2739 | UML_AND(block, IREG(1), CPR032(COP0_Wired), IMM(0x3f)); // and i1,[Wired],0x3f |
| 3085 | 2740 | UML_SUBf(block, IREG(2), IMM(48), IREG(1), FLAGS_BE); // sub i2,48,i1,ALL |
| 3086 | 2741 | UML_JMPc(block, IF_BE, link1 = compiler->labelnum++); // jmp link1,BE |
| 3087 | | UML_DZEXT4(block, IREG(2), IREG(2)); // dzext4 i2,i2 |
| 2742 | UML_DAND(block, IREG(2), IREG(2), IMM(0xffffffff)); // dand i2,i2,0xffffffff |
| 3088 | 2743 | UML_DDIVU(block, IREG(0), IREG(2), IREG(0), IREG(2)); // ddivu i0,i2,i0,i2 |
| 3089 | 2744 | UML_ADD(block, IREG(0), IREG(2), IREG(1)); // add i0,i2,i1 |
| 3090 | 2745 | UML_DAND(block, IREG(0), IREG(0), IMM(0x3f)); // dand i0,i0,0x3f |
| 3091 | 2746 | UML_JMP(block, link2 = compiler->labelnum++); // jmp link2 |
| 3092 | 2747 | UML_LABEL(block, link1); // link1: |
| 3093 | | UML_DSEXT4(block, IREG(0), IMM(47)); // dsext4 i0,47 |
| 2748 | UML_DMOV(block, IREG(0), IMM(47)); // dmov i0,47 |
| 3094 | 2749 | UML_LABEL(block, link2); // link2: |
| 3095 | 2750 | return TRUE; |
| 3096 | 2751 | |
| 3097 | 2752 | default: |
| 3098 | | UML_DSEXT4(block, IREG(0), CPR032(reg)); // dsext4 i0,cpr0[reg] |
| 2753 | UML_DSEXT(block, IREG(0), CPR032(reg), DWORD); // dsext i0,cpr0[reg],dword |
| 3099 | 2754 | return TRUE; |
| 3100 | 2755 | } |
| 3101 | 2756 | } |
| r2821 | r2822 | |
| 3124 | 2779 | if (RTREG != 0) |
| 3125 | 2780 | { |
| 3126 | 2781 | generate_get_cop0_reg(block, compiler, desc, RDREG); // <get cop0 reg> |
| 3127 | | UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0 |
| 2782 | UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0,dword |
| 3128 | 2783 | } |
| 3129 | 2784 | return TRUE; |
| 3130 | 2785 | |
| r2821 | r2822 | |
| 3138 | 2793 | |
| 3139 | 2794 | case 0x02: /* CFCz */ |
| 3140 | 2795 | if (RTREG != 0) |
| 3141 | | UML_DSEXT4(block, R64(RTREG), CCR032(RDREG)); // dsext4 <rtreg>,ccr0[rdreg] |
| 2796 | UML_DSEXT(block, R64(RTREG), CCR032(RDREG), DWORD); // dsext <rtreg>,ccr0[rdreg],dword |
| 3142 | 2797 | return TRUE; |
| 3143 | 2798 | |
| 3144 | 2799 | case 0x04: /* MTCz */ |
| 3145 | | UML_DSEXT4(block, IREG(0), R32(RTREG)); // dsext4 i0,<rtreg> |
| 2800 | UML_DSEXT(block, IREG(0), R32(RTREG), DWORD); // dsext i0,<rtreg>,dword |
| 3146 | 2801 | generate_set_cop0_reg(block, compiler, desc, RDREG); // <set cop0 reg> |
| 3147 | 2802 | return TRUE; |
| 3148 | 2803 | |
| r2821 | r2822 | |
| 3152 | 2807 | return TRUE; |
| 3153 | 2808 | |
| 3154 | 2809 | case 0x06: /* CTCz */ |
| 3155 | | UML_DSEXT4(block, CCR064(RDREG), R32(RTREG)); // dsext4 ccr0[rdreg],<rtreg> |
| 2810 | UML_DSEXT(block, CCR064(RDREG), R32(RTREG), DWORD); // dsext ccr0[rdreg],<rtreg>,dword |
| 3156 | 2811 | return TRUE; |
| 3157 | 2812 | |
| 3158 | 2813 | case 0x10: |
| r2821 | r2822 | |
| 3240 | 2895 | if (mips3->impstate->drcoptions & MIPS3DRC_STRICT_COP1) |
| 3241 | 2896 | { |
| 3242 | 2897 | UML_TEST(block, CPR032(COP0_Status), IMM(SR_COP1)); // test [Status],SR_COP1 |
| 3243 | | UML_EXHc(block, IF_Z, mips3->impstate->exception[EXCEPTION_BADCOP], IMM(0));// exh cop,0,Z |
| 2898 | UML_EXHc(block, IF_Z, mips3->impstate->exception[EXCEPTION_BADCOP], IMM(1));// exh cop,1,Z |
| 3244 | 2899 | } |
| 3245 | 2900 | |
| 3246 | 2901 | switch (RSREG) |
| 3247 | 2902 | { |
| 3248 | 2903 | case 0x00: /* MFCz - MIPS I */ |
| 3249 | 2904 | if (RTREG != 0) |
| 3250 | | UML_DSEXT4(block, R64(RTREG), FPR32(RDREG)); // dsext4 <rtreg>,fpr[rdreg] |
| 2905 | UML_DSEXT(block, R64(RTREG), FPR32(RDREG), DWORD); // dsext <rtreg>,fpr[rdreg],dword |
| 3251 | 2906 | return TRUE; |
| 3252 | 2907 | |
| 3253 | 2908 | case 0x01: /* DMFCz - MIPS III */ |
| r2821 | r2822 | |
| 3257 | 2912 | |
| 3258 | 2913 | case 0x02: /* CFCz - MIPS I */ |
| 3259 | 2914 | if (RTREG != 0) |
| 3260 | | UML_DSEXT4(block, R64(RTREG), CCR132(RDREG)); // dsext4 <rtreg>,ccr132[rdreg] |
| 2915 | UML_DSEXT(block, R64(RTREG), CCR132(RDREG), DWORD); // dsext <rtreg>,ccr132[rdreg],dword |
| 3261 | 2916 | return TRUE; |
| 3262 | 2917 | |
| 3263 | 2918 | case 0x04: /* MTCz - MIPS I */ |
| r2821 | r2822 | |
| 3270 | 2925 | |
| 3271 | 2926 | case 0x06: /* CTCz - MIPS I */ |
| 3272 | 2927 | if (RDREG != 31) |
| 3273 | | UML_DSEXT4(block, CCR164(RDREG), R32(RTREG)); // dsext4 ccr1[rdreg],<rtreg> |
| 2928 | UML_DSEXT(block, CCR164(RDREG), R32(RTREG), DWORD); // dsext ccr1[rdreg],<rtreg>,dword |
| 3274 | 2929 | else |
| 3275 | 2930 | { |
| 3276 | 2931 | UML_XOR(block, IREG(0), CCR132(31), R32(RTREG)); // xor i0,ccr1[31],<rtreg> |
| 3277 | | UML_DSEXT4(block, CCR164(31), R32(RTREG)); // dsext4 ccr1[31],<rtreg> |
| 2932 | UML_DSEXT(block, CCR164(31), R32(RTREG), DWORD); // dsext ccr1[31],<rtreg>,dword |
| 3278 | 2933 | UML_TEST(block, IREG(0), IMM(3)); // test i0,3 |
| 3279 | 2934 | UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z |
| 3280 | 2935 | UML_AND(block, IREG(0), CCR132(31), IMM(3)); // and i0,ccr1[31],3 |
| 3281 | | UML_LOAD1U(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0)); // load1u i0,fpmode,i0 |
| 2936 | UML_LOAD(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0), BYTE);// load i0,fpmode,i0,byte |
| 3282 | 2937 | UML_SETFMOD(block, IREG(0)); // setfmod i0 |
| 3283 | 2938 | UML_LABEL(block, skip); // skip: |
| 3284 | 2939 | } |
| r2821 | r2822 | |
| 3366 | 3021 | |
| 3367 | 3022 | case 0x08: |
| 3368 | 3023 | if (IS_SINGLE(op)) /* ROUND.L.S - MIPS III */ |
| 3369 | | UML_FSTOI8R(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8r <fdreg>,<fsreg> |
| 3024 | UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, ROUND);// fstoint <fdreg>,<fsreg>,qword,round |
| 3370 | 3025 | else /* ROUND.L.D - MIPS III */ |
| 3371 | | UML_FDTOI8R(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8r <fdreg>,<fsreg> |
| 3026 | UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, ROUND);// fdtoint <fdreg>,<fsreg>,qword,round |
| 3372 | 3027 | return TRUE; |
| 3373 | 3028 | |
| 3374 | 3029 | case 0x09: |
| 3375 | 3030 | if (IS_SINGLE(op)) /* TRUNC.L.S - MIPS III */ |
| 3376 | | UML_FSTOI8T(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8t <fdreg>,<fsreg> |
| 3031 | UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, TRUNC);// fstoint <fdreg>,<fsreg>,qword,trunc |
| 3377 | 3032 | else /* TRUNC.L.D - MIPS III */ |
| 3378 | | UML_FDTOI8T(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8t <fdreg>,<fsreg> |
| 3033 | UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, TRUNC);// fdtoint <fdreg>,<fsreg>,qword,trunc |
| 3379 | 3034 | return TRUE; |
| 3380 | 3035 | |
| 3381 | 3036 | case 0x0a: |
| 3382 | 3037 | if (IS_SINGLE(op)) /* CEIL.L.S - MIPS III */ |
| 3383 | | UML_FSTOI8C(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8c <fdreg>,<fsreg> |
| 3038 | UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, CEIL);// fstoint <fdreg>,<fsreg>,qword,ceil |
| 3384 | 3039 | else /* CEIL.L.D - MIPS III */ |
| 3385 | | UML_FDTOI8C(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8c <fdreg>,<fsreg> |
| 3040 | UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, CEIL);// fdtoint <fdreg>,<fsreg>,qword,ceil |
| 3386 | 3041 | return TRUE; |
| 3387 | 3042 | |
| 3388 | 3043 | case 0x0b: |
| 3389 | 3044 | if (IS_SINGLE(op)) /* FLOOR.L.S - MIPS III */ |
| 3390 | | UML_FSTOI8F(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8f <fdreg>,<fsreg> |
| 3045 | UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, FLOOR);// fstoint <fdreg>,<fsreg>,qword,floor |
| 3391 | 3046 | else /* FLOOR.L.D - MIPS III */ |
| 3392 | | UML_FDTOI8F(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8f <fdreg>,<fsreg> |
| 3047 | UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, FLOOR);// fdtoint <fdreg>,<fsreg>,qword,floor |
| 3393 | 3048 | return TRUE; |
| 3394 | 3049 | |
| 3395 | 3050 | case 0x0c: |
| 3396 | 3051 | if (IS_SINGLE(op)) /* ROUND.W.S - MIPS II */ |
| 3397 | | UML_FSTOI4R(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4r <fdreg>,<fsreg> |
| 3052 | UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, ROUND);// fstoint <fdreg>,<fsreg>,dword,round |
| 3398 | 3053 | else /* ROUND.W.D - MIPS II */ |
| 3399 | | UML_FDTOI4R(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4r <fdreg>,<fsreg> |
| 3054 | UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, ROUND);// fdtoint <fdreg>,<fsreg>,dword,round |
| 3400 | 3055 | return TRUE; |
| 3401 | 3056 | |
| 3402 | 3057 | case 0x0d: |
| 3403 | 3058 | if (IS_SINGLE(op)) /* TRUNC.W.S - MIPS II */ |
| 3404 | | UML_FSTOI4T(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4t <fdreg>,<fsreg> |
| 3059 | UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, TRUNC);// fstoint <fdreg>,<fsreg>,dword,trunc |
| 3405 | 3060 | else /* TRUNC.W.D - MIPS II */ |
| 3406 | | UML_FDTOI4T(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4t <fdreg>,<fsreg> |
| 3061 | UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, TRUNC);// fdtoint <fdreg>,<fsreg>,dword,trunc |
| 3407 | 3062 | return TRUE; |
| 3408 | 3063 | |
| 3409 | 3064 | case 0x0e: |
| 3410 | 3065 | if (IS_SINGLE(op)) /* CEIL.W.S - MIPS II */ |
| 3411 | | UML_FSTOI4C(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4c <fdreg>,<fsreg> |
| 3066 | UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, CEIL);// fstoint <fdreg>,<fsreg>,dword,ceil |
| 3412 | 3067 | else /* CEIL.W.D - MIPS II */ |
| 3413 | | UML_FDTOI4C(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4c <fdreg>,<fsreg> |
| 3068 | UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, CEIL);// fdtoint <fdreg>,<fsreg>,dword,ceil |
| 3414 | 3069 | return TRUE; |
| 3415 | 3070 | |
| 3416 | 3071 | case 0x0f: |
| 3417 | 3072 | if (IS_SINGLE(op)) /* FLOOR.W.S - MIPS II */ |
| 3418 | | UML_FSTOI4F(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4f <fdreg>,<fsreg> |
| 3073 | UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, FLOOR);// fstoint <fdreg>,<fsreg>,dword,floor |
| 3419 | 3074 | else /* FLOOR.W.D - MIPS II */ |
| 3420 | | UML_FDTOI4F(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4f <fdreg>,<fsreg> |
| 3075 | UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, FLOOR);// fdtoint <fdreg>,<fsreg>,dword,floor |
| 3421 | 3076 | return TRUE; |
| 3422 | 3077 | |
| 3423 | 3078 | case 0x11: |
| r2821 | r2822 | |
| 3463 | 3118 | if (IS_INTEGRAL(op)) |
| 3464 | 3119 | { |
| 3465 | 3120 | if (IS_SINGLE(op)) /* CVT.S.W - MIPS I */ |
| 3466 | | UML_FSFRI4(block, FPR32(FDREG), FPR32(FSREG)); // fsfri4 <fdreg>,<fsreg> |
| 3121 | UML_FSFRINT(block, FPR32(FDREG), FPR32(FSREG), DWORD); // fsfrint <fdreg>,<fsreg>,dword |
| 3467 | 3122 | else /* CVT.S.L - MIPS I */ |
| 3468 | | UML_FSFRI8(block, FPR32(FDREG), FPR64(FSREG)); // fsfri8 <fdreg>,<fsreg> |
| 3123 | UML_FSFRINT(block, FPR32(FDREG), FPR64(FSREG), QWORD); // fsfrint <fdreg>,<fsreg>,qword |
| 3469 | 3124 | } |
| 3470 | 3125 | else /* CVT.S.D - MIPS I */ |
| 3471 | | UML_FSFRFD(block, FPR32(FDREG), FPR64(FSREG)); // fsfrfd <fdreg>,<fsreg> |
| 3126 | UML_FSFRFLT(block, FPR32(FDREG), FPR64(FSREG), QWORD); // fsfrflt <fdreg>,<fsreg>,qword |
| 3472 | 3127 | return TRUE; |
| 3473 | 3128 | |
| 3474 | 3129 | case 0x21: |
| 3475 | 3130 | if (IS_INTEGRAL(op)) |
| 3476 | 3131 | { |
| 3477 | 3132 | if (IS_SINGLE(op)) /* CVT.D.W - MIPS I */ |
| 3478 | | UML_FDFRI4(block, FPR64(FDREG), FPR32(FSREG)); // fdfri4 <fdreg>,<fsreg> |
| 3133 | UML_FDFRINT(block, FPR64(FDREG), FPR32(FSREG), DWORD); // fdfrint <fdreg>,<fsreg>,dword |
| 3479 | 3134 | else /* CVT.D.L - MIPS I */ |
| 3480 | | UML_FDFRI8(block, FPR64(FDREG), FPR64(FSREG)); // fdfri8 <fdreg>,<fsreg> |
| 3135 | UML_FDFRINT(block, FPR64(FDREG), FPR64(FSREG), QWORD); // fdfrint <fdreg>,<fsreg>,qword |
| 3481 | 3136 | } |
| 3482 | 3137 | else /* CVT.D.S - MIPS I */ |
| 3483 | | UML_FDFRFS(block, FPR64(FDREG), FPR32(FSREG)); // fdfrfs <fdreg>,<fsreg> |
| 3138 | UML_FDFRFLT(block, FPR64(FDREG), FPR32(FSREG), DWORD); // fdfrflt <fdreg>,<fsreg>,dword |
| 3484 | 3139 | return TRUE; |
| 3485 | 3140 | |
| 3486 | 3141 | case 0x24: |
| 3487 | 3142 | if (IS_SINGLE(op)) /* CVT.W.S - MIPS I */ |
| 3488 | | UML_FSTOI4(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4 <fdreg>,<fsreg> |
| 3143 | UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, DEFAULT);// fstoint <fdreg>,<fsreg>,dword,default |
| 3489 | 3144 | else /* CVT.W.D - MIPS I */ |
| 3490 | | UML_FDTOI4(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4 <fdreg>,<fsreg> |
| 3145 | UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, DEFAULT);// fdtoint <fdreg>,<fsreg>,dword,default |
| 3491 | 3146 | return TRUE; |
| 3492 | 3147 | |
| 3493 | 3148 | case 0x25: |
| 3494 | 3149 | if (IS_SINGLE(op)) /* CVT.L.S - MIPS I */ |
| 3495 | | UML_FSTOI8(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8 <fdreg>,<fsreg> |
| 3150 | UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, DEFAULT);// fstoint <fdreg>,<fsreg>,qword,default |
| 3496 | 3151 | else /* CVT.L.D - MIPS I */ |
| 3497 | | UML_FDTOI8(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8 <fdreg>,<fsreg> |
| 3152 | UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, DEFAULT);// fdtoint <fdreg>,<fsreg>,qword,default |
| 3498 | 3153 | return TRUE; |
| 3499 | 3154 | |
| 3500 | 3155 | case 0x30: |
| r2821 | r2822 | |
| 3508 | 3163 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3509 | 3164 | else /* C.UN.D - MIPS I */ |
| 3510 | 3165 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3511 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_un_table); |
| 3512 | | // flags ccr31,fccmask[op],c_eq_table |
| 3166 | UML_SETc(block, IF_U, IREG(0)); // set i0,u |
| 3167 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3168 | // rolins ccr31,i0,fccshift,fcc |
| 3513 | 3169 | return TRUE; |
| 3514 | 3170 | |
| 3515 | 3171 | case 0x32: |
| r2821 | r2822 | |
| 3518 | 3174 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3519 | 3175 | else /* C.EQ.D - MIPS I */ |
| 3520 | 3176 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3521 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_eq_table); |
| 3522 | | // flags ccr31,fccmask[op],c_eq_table |
| 3177 | UML_SETc(block, IF_E, IREG(0)); // set i0,e |
| 3178 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3179 | // rolins ccr31,i0,fccshift,fcc |
| 3523 | 3180 | return TRUE; |
| 3524 | 3181 | |
| 3525 | 3182 | case 0x33: |
| r2821 | r2822 | |
| 3528 | 3185 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3529 | 3186 | else /* C.UEQ.D - MIPS I */ |
| 3530 | 3187 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3531 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_ueq_table); |
| 3532 | | // flags ccr31,fccmask[op],c_eq_table |
| 3188 | UML_SETc(block, IF_U, IREG(0)); // set i0,u |
| 3189 | UML_SETc(block, IF_E, IREG(1)); // set i1,e |
| 3190 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 |
| 3191 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3192 | // rolins ccr31,i0,fccshift,fcc |
| 3533 | 3193 | return TRUE; |
| 3534 | 3194 | |
| 3535 | 3195 | case 0x34: |
| r2821 | r2822 | |
| 3538 | 3198 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3539 | 3199 | else /* C.OLT.D - MIPS I */ |
| 3540 | 3200 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3541 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_olt_table); |
| 3542 | | // flags ccr31,fccmask[op],c_lt_table |
| 3201 | UML_SETc(block, IF_B, IREG(0)); // set i0,b |
| 3202 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3203 | // rolins ccr31,i0,fccshift,fcc |
| 3543 | 3204 | return TRUE; |
| 3544 | 3205 | |
| 3545 | 3206 | case 0x35: |
| r2821 | r2822 | |
| 3548 | 3209 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3549 | 3210 | else /* C.ULT.D - MIPS I */ |
| 3550 | 3211 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3551 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_ult_table); |
| 3552 | | // flags ccr31,fccmask[op],c_lt_table |
| 3212 | UML_SETc(block, IF_U, IREG(0)); // set i0,u |
| 3213 | UML_SETc(block, IF_B, IREG(1)); // set i1,b |
| 3214 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 |
| 3215 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3216 | // rolins ccr31,i0,fccshift,fcc |
| 3553 | 3217 | return TRUE; |
| 3554 | 3218 | |
| 3555 | 3219 | case 0x36: |
| r2821 | r2822 | |
| 3558 | 3222 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3559 | 3223 | else /* C.OLE.D - MIPS I */ |
| 3560 | 3224 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3561 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_ole_table); |
| 3562 | | // flags ccr31,fccmask[op],c_le_table |
| 3225 | UML_SETc(block, IF_BE, IREG(0)); // set i0,be |
| 3226 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3227 | // rolins ccr31,i0,fccshift,fcc |
| 3563 | 3228 | return TRUE; |
| 3564 | 3229 | |
| 3565 | 3230 | case 0x37: |
| r2821 | r2822 | |
| 3568 | 3233 | UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg> |
| 3569 | 3234 | else /* C.ULE.D - MIPS I */ |
| 3570 | 3235 | UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg> |
| 3571 | | UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3->impstate->c_ule_table); |
| 3572 | | // flags ccr31,fccmask[op],c_le_table |
| 3236 | UML_SETc(block, IF_U, IREG(0)); // set i0,u |
| 3237 | UML_SETc(block, IF_BE, IREG(1)); // set i1,be |
| 3238 | UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 |
| 3239 | UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); |
| 3240 | // rolins ccr31,i0,fccshift,fcc |
| 3573 | 3241 | return TRUE; |
| 3574 | 3242 | } |
| 3575 | 3243 | break; |
| r2821 | r2822 | |
| 3595 | 3263 | if (mips3->impstate->drcoptions & MIPS3DRC_STRICT_COP1) |
| 3596 | 3264 | { |
| 3597 | 3265 | UML_TEST(block, CPR032(COP0_Status), IMM(SR_COP1)); // test [Status],SR_COP1 |
| 3598 | | UML_EXHc(block, IF_Z, mips3->impstate->exception[EXCEPTION_BADCOP], IMM(0));// exh cop,0,Z |
| 3266 | UML_EXHc(block, IF_Z, mips3->impstate->exception[EXCEPTION_BADCOP], IMM(1));// exh cop,1,Z |
| 3599 | 3267 | } |
| 3600 | 3268 | |
| 3601 | 3269 | switch (op & 0x3f) |
src/emu/cpu/drcbex86.c
| r2821 | r2822 | |
| 18 | 18 | |
| 19 | 19 | * Identify common pairs and optimize output |
| 20 | 20 | |
| 21 | * Convert AND 0xff/0xffff to movzx |
| 22 | |
| 21 | 23 | **************************************************************************** |
| 22 | 24 | |
| 23 | 25 | --------------- |
| r2821 | r2822 | |
| 282 | 284 | static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 283 | 285 | static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 284 | 286 | static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 287 | static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 285 | 288 | static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 286 | 289 | static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 287 | 290 | |
| 288 | | static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 289 | | static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 290 | | static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 291 | | static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 292 | | static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 293 | | static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 294 | | static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 295 | | static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 296 | | static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 297 | | static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 298 | | static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 299 | | static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 300 | | static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 301 | | static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 302 | | static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 303 | | static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 304 | | static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 305 | | static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 306 | | static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 307 | | static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 308 | | static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 309 | | static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 310 | | static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 311 | | static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 312 | | static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 313 | | static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 314 | | static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 315 | | static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 316 | | static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 317 | | static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 291 | static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 292 | static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 293 | static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 294 | static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 295 | static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 296 | static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 297 | static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 298 | static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 299 | static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 318 | 300 | static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 319 | | static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 320 | | static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 321 | | static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 322 | | static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 323 | | static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 324 | | static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 325 | | static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 326 | | static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 301 | static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 302 | static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 303 | static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 327 | 304 | static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 328 | 305 | static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 329 | 306 | static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| r2821 | r2822 | |
| 352 | 329 | static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 353 | 330 | static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 354 | 331 | static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 355 | | static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 356 | | static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 357 | | static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 358 | | static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 359 | | static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 360 | | static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 361 | | static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 362 | | static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 363 | | static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 364 | | static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 365 | | static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 366 | | static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 367 | | static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 368 | | static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 332 | static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 333 | static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 334 | static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 335 | static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 369 | 336 | static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 370 | 337 | static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| 371 | 338 | static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); |
| r2821 | r2822 | |
| 400 | 367 | /* Internal Register Operations */ |
| 401 | 368 | { DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */ |
| 402 | 369 | { DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */ |
| 403 | | { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */ |
| 404 | | { DRCUML_OP_SAVE, op_save }, /* SAVE dst,index */ |
| 405 | | { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst,index */ |
| 370 | { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst */ |
| 371 | { DRCUML_OP_GETFLGS, op_getflgs }, /* GETFLGS dst[,f] */ |
| 372 | { DRCUML_OP_SAVE, op_save }, /* SAVE dst */ |
| 373 | { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst */ |
| 406 | 374 | |
| 407 | 375 | /* Integer Operations */ |
| 408 | | { DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */ |
| 409 | | { DRCUML_OP_LOAD1S, op_load1s }, /* LOAD1S dst,base,index */ |
| 410 | | { DRCUML_OP_LOAD2U, op_load2u }, /* LOAD2U dst,base,index */ |
| 411 | | { DRCUML_OP_LOAD2S, op_load2s }, /* LOAD2S dst,base,index */ |
| 412 | | { DRCUML_OP_LOAD4U, op_load4u }, /* LOAD4U dst,base,index */ |
| 413 | | { DRCUML_OP_LOAD4S, op_load4s }, /* LOAD4S dst,base,index */ |
| 414 | | { DRCUML_OP_LOAD8U, op_load8u }, /* LOAD8U dst,base,index */ |
| 415 | | { DRCUML_OP_STORE1, op_store1 }, /* STORE1 base,index,src */ |
| 416 | | { DRCUML_OP_STORE2, op_store2 }, /* STORE2 base,index,src */ |
| 417 | | { DRCUML_OP_STORE4, op_store4 }, /* STORE4 base,index,src */ |
| 418 | | { DRCUML_OP_STORE8, op_store8 }, /* STORE8 base,index,src */ |
| 419 | | { DRCUML_OP_READ1U, op_read1u }, /* READ1U dst,space,src1 */ |
| 420 | | { DRCUML_OP_READ1S, op_read1s }, /* READ1S dst,space,src1 */ |
| 421 | | { DRCUML_OP_READ2U, op_read2u }, /* READ2U dst,space,src1 */ |
| 422 | | { DRCUML_OP_READ2S, op_read2s }, /* READ2S dst,space,src1 */ |
| 423 | | { DRCUML_OP_READ2M, op_read2m }, /* READ2M dst,space,src1,mask */ |
| 424 | | { DRCUML_OP_READ4U, op_read4u }, /* READ4U dst,space,src1 */ |
| 425 | | { DRCUML_OP_READ4S, op_read4s }, /* READ4S dst,space,src1 */ |
| 426 | | { DRCUML_OP_READ4M, op_read4m }, /* READ4M dst,space,src1,mask */ |
| 427 | | { DRCUML_OP_READ8U, op_read8u }, /* READ8U dst,space,src1 */ |
| 428 | | { DRCUML_OP_READ8M, op_read8m }, /* READ8M dst,space,src1,mask */ |
| 429 | | { DRCUML_OP_WRITE1, op_write1 }, /* WRITE1 space,dst,src1 */ |
| 430 | | { DRCUML_OP_WRITE2, op_write2 }, /* WRITE2 space,dst,src1 */ |
| 431 | | { DRCUML_OP_WRIT2M, op_writ2m }, /* WRIT2M space,dst,src1 */ |
| 432 | | { DRCUML_OP_WRITE4, op_write4 }, /* WRITE4 space,dst,src1 */ |
| 433 | | { DRCUML_OP_WRIT4M, op_writ4m }, /* WRIT4M space,dst,mask,src1 */ |
| 434 | | { DRCUML_OP_WRITE8, op_write8 }, /* WRITE8 space,dst,src1 */ |
| 435 | | { DRCUML_OP_WRIT8M, op_writ8m }, /* WRIT8M space,dst,mask,src1 */ |
| 436 | | { DRCUML_OP_FLAGS, op_flags }, /* FLAGS dst,mask,table */ |
| 437 | | { DRCUML_OP_SETC, op_setc }, /* FLAGS src,bitnum */ |
| 376 | { DRCUML_OP_LOAD, op_load }, /* LOAD dst,base,index,size */ |
| 377 | { DRCUML_OP_LOADS, op_loads }, /* LOADS dst,base,index,size */ |
| 378 | { DRCUML_OP_STORE, op_store }, /* STORE base,index,src,size */ |
| 379 | { DRCUML_OP_READ, op_read }, /* READ dst,src1,spacesize */ |
| 380 | { DRCUML_OP_READM, op_readm }, /* READM dst,src1,mask,spacesize */ |
| 381 | { DRCUML_OP_WRITE, op_write }, /* WRITE dst,src1,spacesize */ |
| 382 | { DRCUML_OP_WRITEM, op_writem }, /* WRITEM dst,src1,spacesize */ |
| 383 | { DRCUML_OP_CARRY, op_carry }, /* CARRY src,bitnum */ |
| 384 | { DRCUML_OP_SET, op_set }, /* SET dst,c */ |
| 438 | 385 | { DRCUML_OP_MOV, op_mov }, /* MOV dst,src[,c] */ |
| 439 | | { DRCUML_OP_ZEXT1, op_zext1 }, /* ZEXT1 dst,src */ |
| 440 | | { DRCUML_OP_ZEXT2, op_zext2 }, /* ZEXT2 dst,src */ |
| 441 | | { DRCUML_OP_ZEXT4, op_zext4 }, /* ZEXT4 dst,src */ |
| 442 | | { DRCUML_OP_SEXT1, op_sext1 }, /* SEXT1 dst,src */ |
| 443 | | { DRCUML_OP_SEXT2, op_sext2 }, /* SEXT2 dst,src */ |
| 444 | | { DRCUML_OP_SEXT4, op_sext4 }, /* SEXT4 dst,src */ |
| 445 | | { DRCUML_OP_XTRACT, op_xtract }, /* XTRACT dst,src1,src2,src3 */ |
| 446 | | { DRCUML_OP_INSERT, op_insert }, /* INSERT dst,src1,src2,src3 */ |
| 386 | { DRCUML_OP_SEXT, op_sext }, /* SEXT dst,src */ |
| 387 | { DRCUML_OP_ROLAND, op_roland }, /* ROLAND dst,src1,src2,src3 */ |
| 388 | { DRCUML_OP_ROLINS, op_rolins }, /* ROLINS dst,src1,src2,src3 */ |
| 447 | 389 | { DRCUML_OP_ADD, op_add }, /* ADD dst,src1,src2[,f] */ |
| 448 | 390 | { DRCUML_OP_ADDC, op_addc }, /* ADDC dst,src1,src2[,f] */ |
| 449 | 391 | { DRCUML_OP_SUB, op_sub }, /* SUB dst,src1,src2[,f] */ |
| r2821 | r2822 | |
| 470 | 412 | /* Floating Point Operations */ |
| 471 | 413 | { DRCUML_OP_FLOAD, op_fload }, /* FLOAD dst,base,index */ |
| 472 | 414 | { DRCUML_OP_FSTORE, op_fstore }, /* FSTORE base,index,src */ |
| 473 | | { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,space,src1 */ |
| 474 | | { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE space,dst,src1 */ |
| 415 | { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,src1,space */ |
| 416 | { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE dst,src1,space */ |
| 475 | 417 | { DRCUML_OP_FMOV, op_fmov }, /* FMOV dst,src1[,c] */ |
| 476 | | { DRCUML_OP_FTOI4, op_ftoi4 }, /* FTOI4 dst,src1 */ |
| 477 | | { DRCUML_OP_FTOI4T, op_ftoi4t }, /* FTOI4T dst,src1 */ |
| 478 | | { DRCUML_OP_FTOI4R, op_ftoi4r }, /* FTOI4R dst,src1 */ |
| 479 | | { DRCUML_OP_FTOI4F, op_ftoi4f }, /* FTOI4F dst,src1 */ |
| 480 | | { DRCUML_OP_FTOI4C, op_ftoi4c }, /* FTOI4C dst,src1 */ |
| 481 | | { DRCUML_OP_FTOI8, op_ftoi8 }, /* FTOI8 dst,src1 */ |
| 482 | | { DRCUML_OP_FTOI8T, op_ftoi8t }, /* FTOI8T dst,src1 */ |
| 483 | | { DRCUML_OP_FTOI8R, op_ftoi8r }, /* FTOI8R dst,src1 */ |
| 484 | | { DRCUML_OP_FTOI8F, op_ftoi8f }, /* FTOI8F dst,src1 */ |
| 485 | | { DRCUML_OP_FTOI8C, op_ftoi8c }, /* FTOI8C dst,src1 */ |
| 486 | | { DRCUML_OP_FFRFS, op_ffrfs }, /* FFRFS dst,src1 */ |
| 487 | | { DRCUML_OP_FFRFD, op_ffrfd }, /* FFRFD dst,src1 */ |
| 488 | | { DRCUML_OP_FFRI4, op_ffri4 }, /* FFRI4 dst,src1 */ |
| 489 | | { DRCUML_OP_FFRI8, op_ffri8 }, /* FFRI8 dst,src1 */ |
| 418 | { DRCUML_OP_FTOINT, op_ftoint }, /* FTOINT dst,src1,size,round */ |
| 419 | { DRCUML_OP_FFRINT, op_ffrint }, /* FFRINT dst,src1,size */ |
| 420 | { DRCUML_OP_FFRFLT, op_ffrflt }, /* FFRFLT dst,src1,size */ |
| 421 | { DRCUML_OP_FRNDS, op_frnds }, /* FRNDS dst,src1 */ |
| 490 | 422 | { DRCUML_OP_FADD, op_fadd }, /* FADD dst,src1,src2 */ |
| 491 | 423 | { DRCUML_OP_FSUB, op_fsub }, /* FSUB dst,src1,src2 */ |
| 492 | 424 | { DRCUML_OP_FCMP, op_fcmp }, /* FCMP src1,src2 */ |
| r2821 | r2822 | |
| 3603 | 3535 | |
| 3604 | 3536 | |
| 3605 | 3537 | /*------------------------------------------------- |
| 3538 | op_getflgs - process a GETFLGS opcode |
| 3539 | -------------------------------------------------*/ |
| 3540 | |
| 3541 | static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3542 | { |
| 3543 | drcuml_parameter dstp; |
| 3544 | int dstreg; |
| 3545 | |
| 3546 | /* validate instruction */ |
| 3547 | assert(inst->size == 4); |
| 3548 | assert(inst->condflags != DRCUML_COND_ALWAYS); |
| 3549 | |
| 3550 | /* normalize parameters */ |
| 3551 | param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); |
| 3552 | |
| 3553 | /* pick a target register for the general case */ |
| 3554 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3555 | |
| 3556 | switch (inst->condflags) |
| 3557 | { |
| 3558 | /* single flags only */ |
| 3559 | case DRCUML_FLAG_C: |
| 3560 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3561 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3562 | break; |
| 3563 | |
| 3564 | case DRCUML_FLAG_V: |
| 3565 | emit_setcc_r8(&dst, COND_O, REG_AL); // seto al |
| 3566 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3567 | emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 |
| 3568 | break; |
| 3569 | |
| 3570 | case DRCUML_FLAG_Z: |
| 3571 | emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al |
| 3572 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3573 | emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 |
| 3574 | break; |
| 3575 | |
| 3576 | case DRCUML_FLAG_S: |
| 3577 | emit_setcc_r8(&dst, COND_S, REG_AL); // sets al |
| 3578 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3579 | emit_shl_r32_imm(&dst, dstreg, 3); // shl dstreg,3 |
| 3580 | break; |
| 3581 | |
| 3582 | case DRCUML_FLAG_U: |
| 3583 | emit_setcc_r8(&dst, COND_P, REG_AL); // setp al |
| 3584 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 3585 | emit_shl_r32_imm(&dst, dstreg, 4); // shl dstreg,4 |
| 3586 | break; |
| 3587 | |
| 3588 | /* carry plus another flag */ |
| 3589 | case DRCUML_FLAG_C | DRCUML_FLAG_V: |
| 3590 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3591 | emit_setcc_r8(&dst, COND_O, REG_CL); // seto cl |
| 3592 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3593 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3594 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] |
| 3595 | break; |
| 3596 | |
| 3597 | case DRCUML_FLAG_C | DRCUML_FLAG_Z: |
| 3598 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3599 | emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl |
| 3600 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3601 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3602 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] |
| 3603 | break; |
| 3604 | |
| 3605 | case DRCUML_FLAG_C | DRCUML_FLAG_S: |
| 3606 | emit_setcc_r8(&dst, COND_C, REG_AL); // setc al |
| 3607 | emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl |
| 3608 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3609 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3610 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 8, 0)); // lea dstreg,[eax+ecx*8] |
| 3611 | break; |
| 3612 | |
| 3613 | /* overflow plus another flag */ |
| 3614 | case DRCUML_FLAG_V | DRCUML_FLAG_Z: |
| 3615 | emit_setcc_r8(&dst, COND_O, REG_AL); // seto al |
| 3616 | emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl |
| 3617 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3618 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3619 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] |
| 3620 | emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 |
| 3621 | break; |
| 3622 | |
| 3623 | case DRCUML_FLAG_V | DRCUML_FLAG_S: |
| 3624 | emit_setcc_r8(&dst, COND_O, REG_AL); // seto al |
| 3625 | emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl |
| 3626 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3627 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3628 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] |
| 3629 | emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 |
| 3630 | break; |
| 3631 | |
| 3632 | /* zero plus another flag */ |
| 3633 | case DRCUML_FLAG_Z | DRCUML_FLAG_S: |
| 3634 | emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al |
| 3635 | emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl |
| 3636 | emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al |
| 3637 | emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al |
| 3638 | emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] |
| 3639 | emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 |
| 3640 | break; |
| 3641 | |
| 3642 | /* default cases */ |
| 3643 | default: |
| 3644 | emit_pushf(&dst); // pushf |
| 3645 | emit_pop_r32(&dst, REG_EAX); // pop eax |
| 3646 | emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 |
| 3647 | emit_movzx_r32_m8(&dst, dstreg, MBD(REG_EAX, flags_map)); // movzx dstreg,[flags_map] |
| 3648 | break; |
| 3649 | } |
| 3650 | |
| 3651 | /* store low 32 bits */ |
| 3652 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3653 | |
| 3654 | /* 64-bit form stores upper 32 bits */ |
| 3655 | if (inst->size == 8) |
| 3656 | { |
| 3657 | /* general case */ |
| 3658 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 3659 | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 3660 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 3661 | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 3662 | } |
| 3663 | return dst; |
| 3664 | } |
| 3665 | |
| 3666 | |
| 3667 | /*------------------------------------------------- |
| 3606 | 3668 | op_save - process a SAVE opcode |
| 3607 | 3669 | -------------------------------------------------*/ |
| 3608 | 3670 | |
| r2821 | r2822 | |
| 3726 | 3788 | ***************************************************************************/ |
| 3727 | 3789 | |
| 3728 | 3790 | /*------------------------------------------------- |
| 3729 | | op_load1u - process a LOAD1U opcode |
| 3791 | op_load - process a LOAD opcode |
| 3730 | 3792 | -------------------------------------------------*/ |
| 3731 | 3793 | |
| 3732 | | static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3794 | static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3733 | 3795 | { |
| 3734 | | drcuml_parameter dstp, basep, indp; |
| 3796 | drcuml_parameter dstp, basep, indp, sizep; |
| 3735 | 3797 | int dstreg; |
| 3736 | 3798 | |
| 3737 | 3799 | /* validate instruction */ |
| r2821 | r2822 | |
| 3739 | 3801 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3740 | 3802 | |
| 3741 | 3803 | /* normalize parameters */ |
| 3742 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3804 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); |
| 3743 | 3805 | |
| 3744 | 3806 | /* pick a target register for the general case */ |
| 3745 | 3807 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3746 | 3808 | |
| 3747 | 3809 | /* immediate index */ |
| 3748 | 3810 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3749 | | emit_movzx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movzx dstreg,[basep + 1*indp] |
| 3811 | { |
| 3812 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3813 | emit_movzx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movzx dstreg,[basep + 1*indp] |
| 3814 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3815 | emit_movzx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movzx dstreg,[basep + 2*indp] |
| 3816 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3817 | emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3818 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3819 | { |
| 3820 | emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4] |
| 3821 | emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp] |
| 3822 | } |
| 3823 | } |
| 3750 | 3824 | |
| 3751 | 3825 | /* other index */ |
| 3752 | 3826 | else |
| 3753 | 3827 | { |
| 3754 | 3828 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3755 | 3829 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3756 | | emit_movzx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movzx dstreg,[basep + 1*indp] |
| 3830 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3831 | emit_movzx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movzx dstreg,[basep + 1*indp] |
| 3832 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3833 | emit_movzx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movzx dstreg,[basep + 2*indp] |
| 3834 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3835 | emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp] |
| 3836 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3837 | { |
| 3838 | emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4] |
| 3839 | emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp] |
| 3840 | } |
| 3757 | 3841 | } |
| 3758 | 3842 | |
| 3759 | 3843 | /* store low 32 bits */ |
| r2821 | r2822 | |
| 3762 | 3846 | /* 64-bit form stores upper 32 bits */ |
| 3763 | 3847 | if (inst->size == 8) |
| 3764 | 3848 | { |
| 3765 | | /* general case */ |
| 3766 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 3767 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 3768 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 3769 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 3770 | | } |
| 3771 | | return dst; |
| 3772 | | } |
| 3849 | /* 1, 2, or 4-byte case */ |
| 3850 | if (sizep.value != DRCUML_SIZE_QWORD) |
| 3851 | { |
| 3852 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 3853 | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 3854 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 3855 | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 3856 | } |
| 3773 | 3857 | |
| 3774 | | |
| 3775 | | /*------------------------------------------------- |
| 3776 | | op_load1s - process a LOAD1S opcode |
| 3777 | | -------------------------------------------------*/ |
| 3778 | | |
| 3779 | | static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3780 | | { |
| 3781 | | drcuml_parameter dstp, basep, indp; |
| 3782 | | int dstreg; |
| 3783 | | |
| 3784 | | /* validate instruction */ |
| 3785 | | assert(inst->size == 4 || inst->size == 8); |
| 3786 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3787 | | |
| 3788 | | /* normalize parameters */ |
| 3789 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3790 | | |
| 3791 | | /* pick a target register for the general case */ |
| 3792 | | dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL); |
| 3793 | | |
| 3794 | | /* immediate index */ |
| 3795 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3796 | | emit_movsx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movsx eax,[basep + 1*indp] |
| 3797 | | |
| 3798 | | /* other index */ |
| 3799 | | else |
| 3800 | | { |
| 3801 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3802 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3803 | | emit_movsx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movsx eax,[basep + 1*indp] |
| 3858 | /* 8-byte case */ |
| 3859 | else |
| 3860 | { |
| 3861 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 3862 | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx |
| 3863 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 3864 | emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx |
| 3865 | } |
| 3804 | 3866 | } |
| 3805 | | |
| 3806 | | /* 32-bit form */ |
| 3807 | | if (inst->size == 4) |
| 3808 | | { |
| 3809 | | /* general case */ |
| 3810 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3811 | | } |
| 3812 | | |
| 3813 | | /* 64-bit form */ |
| 3814 | | else |
| 3815 | | { |
| 3816 | | /* general case */ |
| 3817 | | emit_cdq(&dst); // cdq |
| 3818 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 3819 | | } |
| 3820 | 3867 | return dst; |
| 3821 | 3868 | } |
| 3822 | 3869 | |
| 3823 | 3870 | |
| 3824 | 3871 | /*------------------------------------------------- |
| 3825 | | op_load2u - process a LOAD2U opcode |
| 3872 | op_loads - process a LOADS opcode |
| 3826 | 3873 | -------------------------------------------------*/ |
| 3827 | 3874 | |
| 3828 | | static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3875 | static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3829 | 3876 | { |
| 3830 | | drcuml_parameter dstp, basep, indp; |
| 3877 | drcuml_parameter dstp, basep, indp, sizep; |
| 3831 | 3878 | int dstreg; |
| 3832 | 3879 | |
| 3833 | 3880 | /* validate instruction */ |
| r2821 | r2822 | |
| 3835 | 3882 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3836 | 3883 | |
| 3837 | 3884 | /* normalize parameters */ |
| 3838 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3885 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); |
| 3839 | 3886 | |
| 3840 | 3887 | /* pick a target register for the general case */ |
| 3841 | 3888 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3842 | 3889 | |
| 3843 | 3890 | /* immediate index */ |
| 3844 | 3891 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3845 | | emit_movzx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movzx dstreg,[basep + 2*indp] |
| 3846 | | |
| 3847 | | /* other index */ |
| 3848 | | else |
| 3849 | 3892 | { |
| 3850 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3851 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3852 | | emit_movzx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movzx dstreg,[basep + 2*indp] |
| 3893 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3894 | emit_movsx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movsx dstreg,[basep + 1*indp] |
| 3895 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3896 | emit_movsx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movsx dstreg,[basep + 2*indp] |
| 3897 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3898 | emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3899 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3900 | { |
| 3901 | emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4] |
| 3902 | emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp] |
| 3903 | } |
| 3853 | 3904 | } |
| 3854 | 3905 | |
| 3855 | | /* store low 32 bits */ |
| 3856 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3857 | | |
| 3858 | | /* 64-bit form stores upper 32 bits */ |
| 3859 | | if (inst->size == 8) |
| 3860 | | { |
| 3861 | | /* general case */ |
| 3862 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 3863 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 3864 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 3865 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 3866 | | } |
| 3867 | | return dst; |
| 3868 | | } |
| 3869 | | |
| 3870 | | |
| 3871 | | /*------------------------------------------------- |
| 3872 | | op_load2s - process a LOAD2S opcode |
| 3873 | | -------------------------------------------------*/ |
| 3874 | | |
| 3875 | | static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3876 | | { |
| 3877 | | drcuml_parameter dstp, basep, indp; |
| 3878 | | int dstreg; |
| 3879 | | |
| 3880 | | /* validate instruction */ |
| 3881 | | assert(inst->size == 4 || inst->size == 8); |
| 3882 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3883 | | |
| 3884 | | /* normalize parameters */ |
| 3885 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3886 | | |
| 3887 | | /* pick a target register for the general case */ |
| 3888 | | dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL); |
| 3889 | | |
| 3890 | | /* immediate index */ |
| 3891 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3892 | | emit_movsx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movsx eax,[basep + 2*indp] |
| 3893 | | |
| 3894 | 3906 | /* other index */ |
| 3895 | 3907 | else |
| 3896 | 3908 | { |
| 3897 | 3909 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3898 | 3910 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3899 | | emit_movsx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movsx eax,[basep + 2*indp] |
| 3911 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3912 | emit_movsx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movsx dstreg,[basep + 1*indp] |
| 3913 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3914 | emit_movsx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movsx dstreg,[basep + 2*indp] |
| 3915 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3916 | emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp] |
| 3917 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3918 | { |
| 3919 | emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4] |
| 3920 | emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp] |
| 3921 | } |
| 3900 | 3922 | } |
| 3901 | 3923 | |
| 3902 | | /* 32-bit form */ |
| 3903 | | if (inst->size == 4) |
| 3904 | | { |
| 3905 | | /* general case */ |
| 3906 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3907 | | } |
| 3908 | | |
| 3909 | | /* 64-bit form */ |
| 3910 | | else |
| 3911 | | { |
| 3912 | | /* general case */ |
| 3913 | | emit_cdq(&dst); // cdq |
| 3914 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 3915 | | } |
| 3916 | | return dst; |
| 3917 | | } |
| 3918 | | |
| 3919 | | |
| 3920 | | /*------------------------------------------------- |
| 3921 | | op_load4u - process a LOAD4U opcode |
| 3922 | | -------------------------------------------------*/ |
| 3923 | | |
| 3924 | | static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3925 | | { |
| 3926 | | drcuml_parameter dstp, basep, indp; |
| 3927 | | int dstreg; |
| 3928 | | |
| 3929 | | /* validate instruction */ |
| 3930 | | assert(inst->size == 4 || inst->size == 8); |
| 3931 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3932 | | |
| 3933 | | /* normalize parameters */ |
| 3934 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3935 | | |
| 3936 | | /* pick a target register for the general case */ |
| 3937 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 3938 | | |
| 3939 | | /* immediate index */ |
| 3940 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3941 | | emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp] |
| 3942 | | |
| 3943 | | /* other index */ |
| 3944 | | else |
| 3945 | | { |
| 3946 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3947 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3948 | | emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp] |
| 3949 | | } |
| 3950 | | |
| 3951 | 3924 | /* store low 32 bits */ |
| 3952 | 3925 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 3953 | 3926 | |
| 3954 | 3927 | /* 64-bit form stores upper 32 bits */ |
| 3955 | 3928 | if (inst->size == 8) |
| 3956 | 3929 | { |
| 3957 | | /* general case */ |
| 3930 | emit_cdq(&dst); // cdq |
| 3958 | 3931 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 3959 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 3932 | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx |
| 3960 | 3933 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 3961 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 3934 | emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx |
| 3962 | 3935 | } |
| 3963 | 3936 | return dst; |
| 3964 | 3937 | } |
| 3965 | 3938 | |
| 3966 | 3939 | |
| 3967 | 3940 | /*------------------------------------------------- |
| 3968 | | op_load4s - process a LOAD4S opcode |
| 3941 | op_store - process a STORE opcode |
| 3969 | 3942 | -------------------------------------------------*/ |
| 3970 | 3943 | |
| 3971 | | static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3944 | static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 3972 | 3945 | { |
| 3973 | | drcuml_parameter dstp, basep, indp; |
| 3974 | | |
| 3975 | | /* validate instruction */ |
| 3976 | | assert(inst->size == 8); |
| 3977 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 3978 | | |
| 3979 | | /* normalize parameters */ |
| 3980 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 3981 | | |
| 3982 | | /* immediate index */ |
| 3983 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 3984 | | emit_mov_r32_m32(&dst, REG_EAX, MABS(basep.value + 4*indp.value)); // mov eax,[basep + 4*indp] |
| 3985 | | |
| 3986 | | /* other index */ |
| 3987 | | else |
| 3988 | | { |
| 3989 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 3990 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 3991 | | emit_mov_r32_m32(&dst, REG_EAX, MISD(indreg, 4, basep.value)); // movsx eax,[basep + 4*indp] |
| 3992 | | } |
| 3993 | | |
| 3994 | | /* general case */ |
| 3995 | | emit_cdq(&dst); // cdq |
| 3996 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 3997 | | |
| 3998 | | return dst; |
| 3999 | | } |
| 4000 | | |
| 4001 | | |
| 4002 | | /*------------------------------------------------- |
| 4003 | | op_load8u - process a LOAD8U opcode |
| 4004 | | -------------------------------------------------*/ |
| 4005 | | |
| 4006 | | static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4007 | | { |
| 4008 | | drcuml_parameter dstp, basep, indp; |
| 4009 | | int dstreg; |
| 4010 | | |
| 4011 | | /* validate instruction */ |
| 4012 | | assert(inst->size == 8); |
| 4013 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4014 | | |
| 4015 | | /* normalize parameters */ |
| 4016 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); |
| 4017 | | |
| 4018 | | /* pick a target register for the general case */ |
| 4019 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4020 | | |
| 4021 | | /* immediate index */ |
| 4022 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4023 | | { |
| 4024 | | emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4] |
| 4025 | | emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp] |
| 4026 | | } |
| 4027 | | |
| 4028 | | /* other index */ |
| 4029 | | else |
| 4030 | | { |
| 4031 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4032 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 4033 | | emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4] |
| 4034 | | emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp] |
| 4035 | | } |
| 4036 | | |
| 4037 | | /* general case */ |
| 4038 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg |
| 4039 | | |
| 4040 | | return dst; |
| 4041 | | } |
| 4042 | | |
| 4043 | | |
| 4044 | | /*------------------------------------------------- |
| 4045 | | op_store1 - process a STORE1 opcode |
| 4046 | | -------------------------------------------------*/ |
| 4047 | | |
| 4048 | | static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4049 | | { |
| 4050 | | drcuml_parameter srcp, basep, indp; |
| 3946 | drcuml_parameter srcp, basep, indp, sizep; |
| 4051 | 3947 | int srcreg; |
| 4052 | 3948 | |
| 4053 | 3949 | /* validate instruction */ |
| r2821 | r2822 | |
| 4055 | 3951 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4056 | 3952 | |
| 4057 | 3953 | /* normalize parameters */ |
| 4058 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 3954 | param_normalize_4(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI, &sizep, PTYPE_I); |
| 4059 | 3955 | |
| 4060 | 3956 | /* pick a source register for the general case */ |
| 4061 | 3957 | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4062 | | if (srcreg & 4) |
| 3958 | if (sizep.value == DRCUML_SIZE_BYTE && (srcreg & 4)) |
| 4063 | 3959 | srcreg = REG_EAX; |
| 4064 | 3960 | |
| 4065 | 3961 | /* degenerate case: constant index */ |
| 4066 | 3962 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4067 | 3963 | { |
| 3964 | /* immediate source */ |
| 4068 | 3965 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4069 | | emit_mov_m8_imm(&dst, MABS(basep.value + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp |
| 4070 | | else |
| 4071 | 3966 | { |
| 4072 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4073 | | emit_mov_m8_r8(&dst, MABS(basep.value + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg |
| 3967 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3968 | emit_mov_m8_imm(&dst, MABS(basep.value + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp |
| 3969 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3970 | emit_mov_m16_imm(&dst, MABS(basep.value + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp |
| 3971 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3972 | emit_mov_m32_imm(&dst, MABS(basep.value + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp |
| 3973 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3974 | { |
| 3975 | emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp |
| 3976 | emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value + 4), srcp.value >> 32); |
| 3977 | // mov [basep + 8*indp + 4],srcp >> 32 |
| 3978 | } |
| 4074 | 3979 | } |
| 4075 | | } |
| 4076 | 3980 | |
| 4077 | | /* normal case: variable index */ |
| 4078 | | else |
| 4079 | | { |
| 4080 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4081 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4082 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4083 | | emit_mov_m8_imm(&dst, MISD(indreg, 1, basep.value), srcp.value); // mov [basep + 1*ecx],srcp |
| 3981 | /* variable source */ |
| 4084 | 3982 | else |
| 4085 | 3983 | { |
| 4086 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4087 | | emit_mov_m8_r8(&dst, MISD(indreg, 1, basep.value), srcreg); // mov [basep + 1*ecx],srcreg |
| 3984 | if (sizep.value != DRCUML_SIZE_QWORD) |
| 3985 | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 3986 | else |
| 3987 | emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp |
| 3988 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 3989 | emit_mov_m8_r8(&dst, MABS(basep.value + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg |
| 3990 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 3991 | emit_mov_m16_r16(&dst, MABS(basep.value + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg |
| 3992 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 3993 | emit_mov_m32_r32(&dst, MABS(basep.value + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg |
| 3994 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 3995 | { |
| 3996 | emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg |
| 3997 | emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value + 4), REG_EDX); // mov [basep + 8*indp + 4],edx |
| 3998 | } |
| 4088 | 3999 | } |
| 4089 | 4000 | } |
| 4090 | | return dst; |
| 4091 | | } |
| 4092 | 4001 | |
| 4093 | | |
| 4094 | | /*------------------------------------------------- |
| 4095 | | op_store2 - process a STORE2 opcode |
| 4096 | | -------------------------------------------------*/ |
| 4097 | | |
| 4098 | | static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4099 | | { |
| 4100 | | drcuml_parameter srcp, basep, indp; |
| 4101 | | int srcreg; |
| 4102 | | |
| 4103 | | /* validate instruction */ |
| 4104 | | assert(inst->size == 4 || inst->size == 8); |
| 4105 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4106 | | |
| 4107 | | /* normalize parameters */ |
| 4108 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4109 | | |
| 4110 | | /* pick a source register for the general case */ |
| 4111 | | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4112 | | |
| 4113 | | /* degenerate case: constant index */ |
| 4114 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4115 | | { |
| 4116 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4117 | | emit_mov_m16_imm(&dst, MABS(basep.value + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp |
| 4118 | | else |
| 4119 | | { |
| 4120 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4121 | | emit_mov_m16_r16(&dst, MABS(basep.value + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg |
| 4122 | | } |
| 4123 | | } |
| 4124 | | |
| 4125 | 4002 | /* normal case: variable index */ |
| 4126 | 4003 | else |
| 4127 | 4004 | { |
| 4128 | 4005 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4129 | 4006 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4130 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4131 | | emit_mov_m16_imm(&dst, MISD(indreg, 2, basep.value), srcp.value); // mov [basep + 2*ecx],srcp |
| 4132 | | else |
| 4133 | | { |
| 4134 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4135 | | emit_mov_m16_r16(&dst, MISD(indreg, 2, basep.value), srcreg); // mov [basep + 2*ecx],srcreg |
| 4136 | | } |
| 4137 | | } |
| 4138 | | return dst; |
| 4139 | | } |
| 4140 | 4007 | |
| 4141 | | |
| 4142 | | /*------------------------------------------------- |
| 4143 | | op_store4 - process a STORE4 opcode |
| 4144 | | -------------------------------------------------*/ |
| 4145 | | |
| 4146 | | static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4147 | | { |
| 4148 | | drcuml_parameter srcp, basep, indp; |
| 4149 | | int srcreg; |
| 4150 | | |
| 4151 | | /* validate instruction */ |
| 4152 | | assert(inst->size == 4 || inst->size == 8); |
| 4153 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4154 | | |
| 4155 | | /* normalize parameters */ |
| 4156 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4157 | | |
| 4158 | | /* pick a source register for the general case */ |
| 4159 | | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4160 | | |
| 4161 | | /* degenerate case: constant index */ |
| 4162 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4163 | | { |
| 4008 | /* immediate source */ |
| 4164 | 4009 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4165 | | emit_mov_m32_imm(&dst, MABS(basep.value + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp |
| 4166 | | else |
| 4167 | 4010 | { |
| 4168 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4169 | | emit_mov_m32_r32(&dst, MABS(basep.value + indp.value), srcreg); // mov [basep + 4*indp],srcreg |
| 4011 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4012 | emit_mov_m8_imm(&dst, MISD(indreg, 1, basep.value), srcp.value); // mov [basep + 1*ecx],srcp |
| 4013 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4014 | emit_mov_m16_imm(&dst, MISD(indreg, 2, basep.value), srcp.value); // mov [basep + 2*ecx],srcp |
| 4015 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4016 | emit_mov_m32_imm(&dst, MISD(indreg, 4, basep.value), srcp.value); // mov [basep + 4*ecx],srcp |
| 4017 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 4018 | { |
| 4019 | emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value), srcp.value); // mov [basep + 8*ecx],srcp |
| 4020 | emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value + 4), srcp.value >> 32); |
| 4021 | // mov [basep + 8*ecx + 4],srcp >> 32 |
| 4022 | } |
| 4170 | 4023 | } |
| 4171 | | } |
| 4172 | 4024 | |
| 4173 | | /* normal case: variable index */ |
| 4174 | | else |
| 4175 | | { |
| 4176 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4177 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4178 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4179 | | emit_mov_m32_imm(&dst, MISD(indreg, 4, basep.value), srcp.value); // mov [basep + 4*ecx],srcp |
| 4025 | /* variable source */ |
| 4180 | 4026 | else |
| 4181 | 4027 | { |
| 4182 | | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4183 | | emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), srcreg); // mov [basep + 4*ecx],srcreg |
| 4028 | if (sizep.value != DRCUML_SIZE_QWORD) |
| 4029 | emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp |
| 4030 | else |
| 4031 | emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp |
| 4032 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4033 | emit_mov_m8_r8(&dst, MISD(indreg, 1, basep.value), srcreg); // mov [basep + 1*ecx],srcreg |
| 4034 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4035 | emit_mov_m16_r16(&dst, MISD(indreg, 2, basep.value), srcreg); // mov [basep + 2*ecx],srcreg |
| 4036 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4037 | emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), srcreg); // mov [basep + 4*ecx],srcreg |
| 4038 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 4039 | { |
| 4040 | emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value), srcreg); // mov [basep + 8*ecx],srcreg |
| 4041 | emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value + 4), REG_EDX); // mov [basep + 8*ecx],edx |
| 4042 | } |
| 4184 | 4043 | } |
| 4185 | 4044 | } |
| 4186 | 4045 | return dst; |
| r2821 | r2822 | |
| 4188 | 4047 | |
| 4189 | 4048 | |
| 4190 | 4049 | /*------------------------------------------------- |
| 4191 | | op_store8 - process a STORE8 opcode |
| 4050 | op_read - process a READ opcode |
| 4192 | 4051 | -------------------------------------------------*/ |
| 4193 | 4052 | |
| 4194 | | static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4053 | static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4195 | 4054 | { |
| 4196 | | drcuml_parameter srcp, basep, indp; |
| 4197 | | int srcreg; |
| 4198 | | |
| 4199 | | /* validate instruction */ |
| 4200 | | assert(inst->size == 8); |
| 4201 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4202 | | |
| 4203 | | /* normalize parameters */ |
| 4204 | | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4205 | | |
| 4206 | | /* pick a source register for the general case */ |
| 4207 | | srcreg = param_select_register(REG_EAX, &srcp, NULL); |
| 4208 | | |
| 4209 | | /* degenerate case: constant index */ |
| 4210 | | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4211 | | { |
| 4212 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4213 | | { |
| 4214 | | emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp |
| 4215 | | emit_mov_m32_imm(&dst, MABS(basep.value + 4 + 8*indp.value), srcp.value >> 32); |
| 4216 | | // mov [basep + 4 + 8*indp],srcp >> 32 |
| 4217 | | } |
| 4218 | | else |
| 4219 | | { |
| 4220 | | emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp |
| 4221 | | emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg |
| 4222 | | emit_mov_m32_r32(&dst, MABS(basep.value + 4 + 8*indp.value), REG_EDX); // mov [basep + 8*indp + 4],edx |
| 4223 | | } |
| 4224 | | } |
| 4225 | | |
| 4226 | | /* normal case: variable index */ |
| 4227 | | else |
| 4228 | | { |
| 4229 | | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 4230 | | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp |
| 4231 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 4232 | | { |
| 4233 | | emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value), srcp.value); // mov [basep + 8*ecx],srcp |
| 4234 | | emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value + 4), srcp.value >> 32); // mov [basep + 8*ecx + 4],srcp >> 32 |
| 4235 | | } |
| 4236 | | else |
| 4237 | | { |
| 4238 | | emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp |
| 4239 | | emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value), srcreg); // mov [basep + 8*ecx],srcreg |
| 4240 | | emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value + 4), REG_EDX); // mov [basep + 4 + 8*ecx],edx |
| 4241 | | } |
| 4242 | | } |
| 4243 | | return dst; |
| 4244 | | } |
| 4245 | | |
| 4246 | | |
| 4247 | | /*------------------------------------------------- |
| 4248 | | op_read1u - process a READ1U opcode |
| 4249 | | -------------------------------------------------*/ |
| 4250 | | |
| 4251 | | static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4252 | | { |
| 4253 | | drcuml_parameter dstp, spacep, addrp; |
| 4055 | drcuml_parameter dstp, addrp, spacesizep; |
| 4254 | 4056 | int dstreg; |
| 4255 | 4057 | |
| 4256 | 4058 | /* validate instruction */ |
| r2821 | r2822 | |
| 4258 | 4060 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4259 | 4061 | |
| 4260 | 4062 | /* normalize parameters */ |
| 4261 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4063 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4262 | 4064 | |
| 4263 | 4065 | /* pick a target register for the general case */ |
| 4264 | 4066 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4265 | 4067 | |
| 4266 | 4068 | /* set up a call to the read byte handler */ |
| 4267 | 4069 | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4268 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_byte);// call read_byte |
| 4269 | | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4270 | | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 4271 | | |
| 4272 | | /* store low 32 bits */ |
| 4273 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4274 | | |
| 4275 | | /* 64-bit form stores upper 32 bits */ |
| 4276 | | if (inst->size == 8) |
| 4070 | if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) |
| 4277 | 4071 | { |
| 4278 | | /* general case */ |
| 4279 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4280 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4281 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4282 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4072 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_byte); |
| 4073 | // call read_byte |
| 4074 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 4283 | 4075 | } |
| 4284 | | return dst; |
| 4285 | | } |
| 4286 | | |
| 4287 | | |
| 4288 | | /*------------------------------------------------- |
| 4289 | | op_read1s - process a READ1S opcode |
| 4290 | | -------------------------------------------------*/ |
| 4291 | | |
| 4292 | | static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4293 | | { |
| 4294 | | drcuml_parameter dstp, spacep, addrp; |
| 4295 | | int dstreg; |
| 4296 | | |
| 4297 | | /* validate instruction */ |
| 4298 | | assert(inst->size == 4 || inst->size == 8); |
| 4299 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4300 | | |
| 4301 | | /* normalize parameters */ |
| 4302 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4303 | | |
| 4304 | | /* pick a target register for the general case */ |
| 4305 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4306 | | |
| 4307 | | /* set up a call to the read byte handler */ |
| 4308 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4309 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_byte);// call read_byte |
| 4310 | | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4311 | | emit_movsx_r32_r8(&dst, dstreg, REG_AL); // movsx dstreg,al |
| 4312 | | |
| 4313 | | /* 32-bit form */ |
| 4314 | | if (inst->size == 4) |
| 4076 | else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4315 | 4077 | { |
| 4316 | | /* general case */ |
| 4317 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4078 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_word); |
| 4079 | // call read_word |
| 4080 | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4318 | 4081 | } |
| 4319 | | |
| 4320 | | /* 64-bit form */ |
| 4321 | | else |
| 4082 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4322 | 4083 | { |
| 4323 | | /* general case */ |
| 4324 | | emit_cdq(&dst); // cdq |
| 4325 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 4084 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_dword); |
| 4085 | // call read_dword |
| 4086 | emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax |
| 4326 | 4087 | } |
| 4327 | | return dst; |
| 4328 | | } |
| 4329 | | |
| 4330 | | |
| 4331 | | /*------------------------------------------------- |
| 4332 | | op_read2u - process a READ2U opcode |
| 4333 | | -------------------------------------------------*/ |
| 4334 | | |
| 4335 | | static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4336 | | { |
| 4337 | | drcuml_parameter dstp, spacep, addrp; |
| 4338 | | int dstreg; |
| 4339 | | |
| 4340 | | /* validate instruction */ |
| 4341 | | assert(inst->size == 4 || inst->size == 8); |
| 4342 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4343 | | |
| 4344 | | /* normalize parameters */ |
| 4345 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4346 | | |
| 4347 | | /* pick a target register for the general case */ |
| 4348 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4349 | | |
| 4350 | | /* set up a call to the read word handler */ |
| 4351 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4352 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word);// call read_word |
| 4088 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4089 | { |
| 4090 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_qword); |
| 4091 | // call read_qword |
| 4092 | emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax |
| 4093 | } |
| 4353 | 4094 | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4354 | | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4355 | 4095 | |
| 4356 | 4096 | /* store low 32 bits */ |
| 4357 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4097 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4358 | 4098 | |
| 4359 | 4099 | /* 64-bit form stores upper 32 bits */ |
| 4360 | 4100 | if (inst->size == 8) |
| 4361 | 4101 | { |
| 4362 | | /* general case */ |
| 4363 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4364 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4365 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4366 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4102 | /* 1, 2, or 4-byte case */ |
| 4103 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4104 | { |
| 4105 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4106 | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4107 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4108 | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4109 | } |
| 4110 | |
| 4111 | /* 8-byte case */ |
| 4112 | else |
| 4113 | { |
| 4114 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4115 | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx |
| 4116 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4117 | emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx |
| 4118 | } |
| 4367 | 4119 | } |
| 4368 | 4120 | return dst; |
| 4369 | 4121 | } |
| 4370 | 4122 | |
| 4371 | 4123 | |
| 4372 | 4124 | /*------------------------------------------------- |
| 4373 | | op_read2s - process a READ2S opcode |
| 4125 | op_readm - process a READM opcode |
| 4374 | 4126 | -------------------------------------------------*/ |
| 4375 | 4127 | |
| 4376 | | static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4128 | static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4377 | 4129 | { |
| 4378 | | drcuml_parameter dstp, spacep, addrp; |
| 4130 | drcuml_parameter dstp, addrp, maskp, spacesizep; |
| 4379 | 4131 | int dstreg; |
| 4380 | 4132 | |
| 4381 | 4133 | /* validate instruction */ |
| r2821 | r2822 | |
| 4383 | 4135 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4384 | 4136 | |
| 4385 | 4137 | /* normalize parameters */ |
| 4386 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4138 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4387 | 4139 | |
| 4388 | 4140 | /* pick a target register for the general case */ |
| 4389 | 4141 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4390 | 4142 | |
| 4391 | | /* set up a call to the read word handler */ |
| 4143 | /* set up a call to the read byte handler */ |
| 4144 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4145 | emit_push_p32(drcbe, &dst, &maskp); // push maskp |
| 4146 | else |
| 4147 | emit_push_p64(drcbe, &dst, &maskp); // push maskp |
| 4392 | 4148 | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4393 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word);// call read_word |
| 4394 | | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4395 | | emit_movsx_r32_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax |
| 4396 | | |
| 4397 | | /* 32-bit form */ |
| 4398 | | if (inst->size == 4) |
| 4149 | if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4399 | 4150 | { |
| 4400 | | /* general case */ |
| 4401 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4151 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_word_masked); |
| 4152 | // call read_word_masked |
| 4153 | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4402 | 4154 | } |
| 4403 | | |
| 4404 | | /* 64-bit form */ |
| 4405 | | else |
| 4155 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4406 | 4156 | { |
| 4407 | | /* general case */ |
| 4408 | | emit_cdq(&dst); // cdq |
| 4409 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 4157 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_dword_masked); |
| 4158 | // call read_dword_masked |
| 4159 | emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax |
| 4410 | 4160 | } |
| 4411 | | return dst; |
| 4412 | | } |
| 4413 | | |
| 4414 | | |
| 4415 | | /*------------------------------------------------- |
| 4416 | | op_read2m - process a READ2M opcode |
| 4417 | | -------------------------------------------------*/ |
| 4418 | | |
| 4419 | | static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4420 | | { |
| 4421 | | drcuml_parameter dstp, spacep, addrp, maskp; |
| 4422 | | int dstreg; |
| 4423 | | |
| 4424 | | /* validate instruction */ |
| 4425 | | assert(inst->size == 4 || inst->size == 8); |
| 4426 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4427 | | |
| 4428 | | /* normalize parameters */ |
| 4429 | | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); |
| 4430 | | |
| 4431 | | /* pick a target register for the general case */ |
| 4432 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4433 | | |
| 4434 | | /* set up a call to the read dword masked handler */ |
| 4435 | | emit_push_p32(drcbe, &dst, &maskp); // push maskp |
| 4436 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4437 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word_masked); |
| 4438 | | // call read_word_masked |
| 4439 | | emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 |
| 4440 | | emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax |
| 4441 | | |
| 4442 | | /* store low 32 bits */ |
| 4443 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4444 | | |
| 4445 | | /* 64-bit form stores upper 32 bits */ |
| 4446 | | if (inst->size == 8) |
| 4161 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4447 | 4162 | { |
| 4448 | | /* general case */ |
| 4449 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4450 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4451 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4452 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4163 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_qword_masked); |
| 4164 | // call read_qword_masked |
| 4165 | emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax |
| 4453 | 4166 | } |
| 4454 | | return dst; |
| 4455 | | } |
| 4456 | | |
| 4457 | | |
| 4458 | | /*------------------------------------------------- |
| 4459 | | op_read4u - process a READ4U opcode |
| 4460 | | -------------------------------------------------*/ |
| 4461 | | |
| 4462 | | static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4463 | | { |
| 4464 | | drcuml_parameter dstp, spacep, addrp; |
| 4465 | | |
| 4466 | | /* validate instruction */ |
| 4467 | | assert(inst->size == 4 || inst->size == 8); |
| 4468 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4469 | | |
| 4470 | | /* normalize parameters */ |
| 4471 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4472 | | |
| 4473 | | /* set up a call to the read dword handler */ |
| 4474 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4475 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword |
| 4476 | | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4477 | | |
| 4167 | emit_add_r32_imm(&dst, REG_ESP, ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) ? 8 : 12); |
| 4168 | // add esp,8/12 |
| 4478 | 4169 | /* store low 32 bits */ |
| 4479 | | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 4170 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4480 | 4171 | |
| 4481 | 4172 | /* 64-bit form stores upper 32 bits */ |
| 4482 | 4173 | if (inst->size == 8) |
| 4483 | 4174 | { |
| 4484 | | /* general case */ |
| 4485 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4486 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4487 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4488 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4489 | | } |
| 4490 | | return dst; |
| 4491 | | } |
| 4175 | /* 1, 2, or 4-byte case */ |
| 4176 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4177 | { |
| 4178 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4179 | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4180 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4181 | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4182 | } |
| 4492 | 4183 | |
| 4493 | | |
| 4494 | | /*------------------------------------------------- |
| 4495 | | op_read4s - process a READ4S opcode |
| 4496 | | -------------------------------------------------*/ |
| 4497 | | |
| 4498 | | static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4499 | | { |
| 4500 | | drcuml_parameter dstp, spacep, addrp; |
| 4501 | | |
| 4502 | | /* validate instruction */ |
| 4503 | | assert(inst->size == 8); |
| 4504 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4505 | | |
| 4506 | | /* normalize parameters */ |
| 4507 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4508 | | |
| 4509 | | /* set up a call to the read dword handler */ |
| 4510 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4511 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword |
| 4512 | | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4513 | | |
| 4514 | | /* 64-bit form */ |
| 4515 | | emit_cdq(&dst); // cdq |
| 4516 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax |
| 4517 | | |
| 4518 | | return dst; |
| 4519 | | } |
| 4520 | | |
| 4521 | | |
| 4522 | | /*------------------------------------------------- |
| 4523 | | op_read4m - process a READ4M opcode |
| 4524 | | -------------------------------------------------*/ |
| 4525 | | |
| 4526 | | static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4527 | | { |
| 4528 | | drcuml_parameter dstp, spacep, addrp, maskp; |
| 4529 | | |
| 4530 | | /* validate instruction */ |
| 4531 | | assert(inst->size == 4 || inst->size == 8); |
| 4532 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4533 | | |
| 4534 | | /* normalize parameters */ |
| 4535 | | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); |
| 4536 | | |
| 4537 | | /* set up a call to the read dword masked handler */ |
| 4538 | | emit_push_p32(drcbe, &dst, &maskp); // push maskp |
| 4539 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4540 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword_masked); |
| 4541 | | // call read_dword_masked |
| 4542 | | emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 |
| 4543 | | |
| 4544 | | /* store low 32 bits */ |
| 4545 | | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 4546 | | |
| 4547 | | /* 64-bit form stores upper 32 bits */ |
| 4548 | | if (inst->size == 8) |
| 4549 | | { |
| 4550 | | /* general case */ |
| 4551 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4552 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4553 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4554 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4184 | /* 8-byte case */ |
| 4185 | else |
| 4186 | { |
| 4187 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4188 | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx |
| 4189 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4190 | emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx |
| 4191 | } |
| 4555 | 4192 | } |
| 4556 | 4193 | return dst; |
| 4557 | 4194 | } |
| 4558 | 4195 | |
| 4559 | 4196 | |
| 4560 | 4197 | /*------------------------------------------------- |
| 4561 | | op_read8u - process a READ8U opcode |
| 4198 | op_write - process a WRITE opcode |
| 4562 | 4199 | -------------------------------------------------*/ |
| 4563 | 4200 | |
| 4564 | | static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4201 | static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4565 | 4202 | { |
| 4566 | | drcuml_parameter dstp, spacep, addrp; |
| 4203 | drcuml_parameter addrp, srcp, spacesizep; |
| 4567 | 4204 | |
| 4568 | 4205 | /* validate instruction */ |
| 4569 | | assert(inst->size == 8); |
| 4570 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4571 | | |
| 4572 | | /* normalize parameters */ |
| 4573 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 4574 | | |
| 4575 | | /* set up a call to the read qword handler */ |
| 4576 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4577 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword);// call read_qword |
| 4578 | | emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 |
| 4579 | | |
| 4580 | | /* 64-bit form */ |
| 4581 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax |
| 4582 | | |
| 4583 | | return dst; |
| 4584 | | } |
| 4585 | | |
| 4586 | | |
| 4587 | | /*------------------------------------------------- |
| 4588 | | op_read8m - process a READ8M opcode |
| 4589 | | -------------------------------------------------*/ |
| 4590 | | |
| 4591 | | static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4592 | | { |
| 4593 | | drcuml_parameter dstp, spacep, addrp, maskp; |
| 4594 | | |
| 4595 | | /* validate instruction */ |
| 4596 | | assert(inst->size == 8); |
| 4597 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4598 | | |
| 4599 | | /* normalize parameters */ |
| 4600 | | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); |
| 4601 | | |
| 4602 | | /* set up a call to the read qword masked handler */ |
| 4603 | | emit_push_p64(drcbe, &dst, &maskp); // push maskp |
| 4604 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4605 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword_masked); |
| 4606 | | // call read_qword_masked |
| 4607 | | emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 |
| 4608 | | |
| 4609 | | /* 64-bit form */ |
| 4610 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax |
| 4611 | | |
| 4612 | | return dst; |
| 4613 | | } |
| 4614 | | |
| 4615 | | |
| 4616 | | /*------------------------------------------------- |
| 4617 | | op_write1 - process a WRITE1 opcode |
| 4618 | | -------------------------------------------------*/ |
| 4619 | | |
| 4620 | | static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4621 | | { |
| 4622 | | drcuml_parameter spacep, addrp, srcp; |
| 4623 | | |
| 4624 | | /* validate instruction */ |
| 4625 | 4206 | assert(inst->size == 4 || inst->size == 8); |
| 4626 | 4207 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4627 | 4208 | |
| 4628 | 4209 | /* normalize parameters */ |
| 4629 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4210 | param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4630 | 4211 | |
| 4631 | 4212 | /* set up a call to the write byte handler */ |
| 4632 | | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4213 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4214 | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4215 | else |
| 4216 | emit_push_p64(drcbe, &dst, &srcp); // push srcp |
| 4633 | 4217 | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4634 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_byte);// call write_byte |
| 4635 | | emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 |
| 4636 | | |
| 4218 | if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) |
| 4219 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_byte); |
| 4220 | // call write_byte |
| 4221 | else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4222 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_word); |
| 4223 | // call write_word |
| 4224 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4225 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_dword); |
| 4226 | // call write_dword |
| 4227 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4228 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_qword); |
| 4229 | // call write_qword |
| 4230 | emit_add_r32_imm(&dst, REG_ESP, ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) ? 8 : 12); |
| 4231 | // add esp,8/12 |
| 4637 | 4232 | return dst; |
| 4638 | 4233 | } |
| 4639 | 4234 | |
| 4640 | 4235 | |
| 4641 | 4236 | /*------------------------------------------------- |
| 4642 | | op_write2 - process a WRITE2 opcode |
| 4237 | op_writem - process a WRITEM opcode |
| 4643 | 4238 | -------------------------------------------------*/ |
| 4644 | 4239 | |
| 4645 | | static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4240 | static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4646 | 4241 | { |
| 4647 | | drcuml_parameter spacep, addrp, srcp; |
| 4242 | drcuml_parameter addrp, srcp, maskp, spacesizep; |
| 4648 | 4243 | |
| 4649 | 4244 | /* validate instruction */ |
| 4650 | 4245 | assert(inst->size == 4 || inst->size == 8); |
| 4651 | 4246 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4652 | 4247 | |
| 4653 | 4248 | /* normalize parameters */ |
| 4654 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4249 | param_normalize_4(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); |
| 4655 | 4250 | |
| 4656 | | /* set up a call to the write word handler */ |
| 4657 | | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4658 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4659 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_word);// call write_word |
| 4660 | | emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 |
| 4661 | | |
| 4662 | | return dst; |
| 4663 | | } |
| 4664 | | |
| 4665 | | |
| 4666 | | /*------------------------------------------------- |
| 4667 | | op_writ2m - process a WRIT2M opcode |
| 4668 | | -------------------------------------------------*/ |
| 4669 | | |
| 4670 | | static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4671 | | { |
| 4672 | | drcuml_parameter spacep, addrp, maskp, srcp; |
| 4673 | | |
| 4674 | | /* validate instruction */ |
| 4675 | | assert(inst->size == 4 || inst->size == 8); |
| 4676 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4677 | | |
| 4678 | | /* normalize parameters */ |
| 4679 | | param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4680 | | |
| 4681 | | /* set up a call to the write word handler */ |
| 4682 | | emit_push_p32(drcbe, &dst, &maskp); // push maskp |
| 4683 | | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4684 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4685 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_word_masked); |
| 4686 | | // call write_word_masked |
| 4687 | | emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 |
| 4688 | | return dst; |
| 4689 | | } |
| 4690 | | |
| 4691 | | |
| 4692 | | /*------------------------------------------------- |
| 4693 | | op_write4 - process a WRITE4 opcode |
| 4694 | | -------------------------------------------------*/ |
| 4695 | | |
| 4696 | | static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4697 | | { |
| 4698 | | drcuml_parameter spacep, addrp, srcp; |
| 4699 | | |
| 4700 | | /* validate instruction */ |
| 4701 | | assert(inst->size == 4 || inst->size == 8); |
| 4702 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4703 | | |
| 4704 | | /* normalize parameters */ |
| 4705 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4706 | | |
| 4707 | | /* set up a call to the write dword handler */ |
| 4708 | | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4709 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4710 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword);// call write_dword |
| 4711 | | emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 |
| 4712 | | |
| 4713 | | return dst; |
| 4714 | | } |
| 4715 | | |
| 4716 | | |
| 4717 | | /*------------------------------------------------- |
| 4718 | | op_writ4m - process a WRIT4M opcode |
| 4719 | | -------------------------------------------------*/ |
| 4720 | | |
| 4721 | | static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4722 | | { |
| 4723 | | drcuml_parameter spacep, addrp, maskp, srcp; |
| 4724 | | |
| 4725 | | /* validate instruction */ |
| 4726 | | assert(inst->size == 4 || inst->size == 8); |
| 4727 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4728 | | |
| 4729 | | /* normalize parameters */ |
| 4730 | | param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4731 | | |
| 4732 | | /* set up a call to the write word handler */ |
| 4733 | | emit_push_p32(drcbe, &dst, &maskp); // push maskp |
| 4734 | | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4735 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4736 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword_masked); |
| 4737 | | // call write_dword_masked |
| 4738 | | emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 |
| 4739 | | return dst; |
| 4740 | | } |
| 4741 | | |
| 4742 | | |
| 4743 | | /*------------------------------------------------- |
| 4744 | | op_write8 - process a WRITE8 opcode |
| 4745 | | -------------------------------------------------*/ |
| 4746 | | |
| 4747 | | static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4748 | | { |
| 4749 | | drcuml_parameter spacep, addrp, srcp; |
| 4750 | | |
| 4751 | | /* validate instruction */ |
| 4752 | | assert(inst->size == 8); |
| 4753 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4754 | | |
| 4755 | | /* normalize parameters */ |
| 4756 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4757 | | |
| 4758 | | /* set up a call to the write qword handler */ |
| 4759 | | emit_push_p64(drcbe, &dst, &srcp); // push srcp |
| 4760 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4761 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword);// call write_qword |
| 4762 | | |
| 4763 | | emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 |
| 4764 | | return dst; |
| 4765 | | } |
| 4766 | | |
| 4767 | | |
| 4768 | | /*------------------------------------------------- |
| 4769 | | op_writ8m - process a WRIT8M opcode |
| 4770 | | -------------------------------------------------*/ |
| 4771 | | |
| 4772 | | static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4773 | | { |
| 4774 | | drcuml_parameter spacep, addrp, maskp, srcp; |
| 4775 | | |
| 4776 | | /* validate instruction */ |
| 4777 | | assert(inst->size == 8); |
| 4778 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4779 | | |
| 4780 | | /* normalize parameters */ |
| 4781 | | param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); |
| 4782 | | |
| 4783 | | /* set up a call to the write word handler */ |
| 4784 | | emit_push_p64(drcbe, &dst, &maskp); // push maskp |
| 4785 | | emit_push_p64(drcbe, &dst, &srcp); // push srcp |
| 4786 | | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4787 | | emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword_masked); |
| 4788 | | // call write_qword_masked |
| 4789 | | emit_add_r32_imm(&dst, REG_ESP, 20); // add esp,20 |
| 4790 | | return dst; |
| 4791 | | } |
| 4792 | | |
| 4793 | | |
| 4794 | | /*------------------------------------------------- |
| 4795 | | op_flags - process a FLAGS opcode |
| 4796 | | -------------------------------------------------*/ |
| 4797 | | |
| 4798 | | static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4799 | | { |
| 4800 | | drcuml_parameter dstp, maskp, tablep; |
| 4801 | | int dstreg; |
| 4802 | | |
| 4803 | | /* validate instruction */ |
| 4804 | | assert(inst->size == 4 || inst->size == 8); |
| 4805 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 4806 | | |
| 4807 | | /* normalize parameters */ |
| 4808 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &maskp, PTYPE_I, &tablep, PTYPE_M); |
| 4809 | | |
| 4810 | | /* pick a target register for the general case */ |
| 4811 | | dstreg = param_select_register(REG_ECX, &dstp, NULL); |
| 4812 | | |
| 4813 | | /* translate live flags into UML flags */ |
| 4814 | | emit_pushf(&dst); // pushf |
| 4815 | | emit_pop_r32(&dst, REG_EAX); // pop eax |
| 4816 | | emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 |
| 4817 | | emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_EAX, flags_map)); // movzx eax,[flags_map] |
| 4818 | | |
| 4819 | | /* 32-bit form */ |
| 4820 | | if (inst->size == 4) |
| 4251 | /* set up a call to the write byte handler */ |
| 4252 | if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) |
| 4821 | 4253 | { |
| 4822 | | /* no masking */ |
| 4823 | | if (maskp.value == 0xffffffff) |
| 4824 | | { |
| 4825 | | emit_mov_r32_m32(&dst, dstreg, MISD(REG_EAX, 4, tablep.value)); // mov dstreg,[eax*4+table] |
| 4826 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4827 | | } |
| 4828 | | |
| 4829 | | /* general case */ |
| 4830 | | else |
| 4831 | | { |
| 4832 | | emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp |
| 4833 | | emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 4, tablep.value)); // mov edx,[eax*4+table] |
| 4834 | | emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask |
| 4835 | | emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask |
| 4836 | | emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx |
| 4837 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4838 | | } |
| 4254 | emit_push_p32(drcbe, &dst, &maskp); // push maskp |
| 4255 | emit_push_p32(drcbe, &dst, &srcp); // push srcp |
| 4839 | 4256 | } |
| 4840 | | |
| 4841 | | /* 64-bit form */ |
| 4842 | 4257 | else |
| 4843 | 4258 | { |
| 4844 | | /* no masking */ |
| 4845 | | if (maskp.value == U64(0xffffffffffffffff)) |
| 4846 | | { |
| 4847 | | emit_mov_r32_m32(&dst, dstreg, MISD(REG_EAX, 8, tablep.value)); // mov dstreg,[eax*4+table] |
| 4848 | | emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 8, tablep.value + 4)); // mov edx,[eax*4+table+4] |
| 4849 | | emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dst,edx:dstreg |
| 4850 | | } |
| 4851 | | |
| 4852 | | /* general case */ |
| 4853 | | else |
| 4854 | | { |
| 4855 | | if ((UINT32)maskp.value != 0) |
| 4856 | | { |
| 4857 | | emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp |
| 4858 | | emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 8, tablep.value)); // mov edx,[eax*8+table] |
| 4859 | | emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask |
| 4860 | | emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask |
| 4861 | | emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx |
| 4862 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg.lo |
| 4863 | | } |
| 4864 | | if ((UINT32)(maskp.value >> 32) != 0) |
| 4865 | | { |
| 4866 | | if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4867 | | emit_mov_r32_m32(&dst, REG_ECX, MABS(drcbe->reghi[dstp.value])); // mov ecx,dstp.hi |
| 4868 | | else |
| 4869 | | emit_mov_r32_m32(&dst, REG_ECX, MABS(dstp.value + 4)); // mov ecx,dstp.hi |
| 4870 | | emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EDX, 8, tablep.value+4)); // mov edx,[eax*8+table+4] |
| 4871 | | emit_and_r32_imm(&dst, REG_ECX, ~maskp.value); // and ecx,~mask |
| 4872 | | emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask |
| 4873 | | emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or ecx,edx |
| 4874 | | if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4875 | | emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_ECX); // mov dstp.hi,ecx |
| 4876 | | else |
| 4877 | | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_ECX); // mov dstp.hi,ecx |
| 4878 | | } |
| 4879 | | } |
| 4259 | emit_push_p64(drcbe, &dst, &maskp); // push maskp |
| 4260 | emit_push_p64(drcbe, &dst, &srcp); // push srcp |
| 4880 | 4261 | } |
| 4262 | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| 4263 | if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) |
| 4264 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_word_masked); |
| 4265 | // call write_word_masked |
| 4266 | else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) |
| 4267 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_dword_masked); |
| 4268 | // call write_dword_masked |
| 4269 | else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) |
| 4270 | emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_qword_masked); |
| 4271 | // call write_qword_masked |
| 4272 | emit_add_r32_imm(&dst, REG_ESP, ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) ? 12 : 20); |
| 4273 | // add esp,12/20 |
| 4881 | 4274 | return dst; |
| 4882 | 4275 | } |
| 4883 | 4276 | |
| 4884 | 4277 | |
| 4885 | 4278 | /*------------------------------------------------- |
| 4886 | | op_setc - process a SETC opcode |
| 4279 | op_carry - process a CARRY opcode |
| 4887 | 4280 | -------------------------------------------------*/ |
| 4888 | 4281 | |
| 4889 | | static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4282 | static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4890 | 4283 | { |
| 4891 | 4284 | drcuml_parameter srcp, bitp; |
| 4892 | 4285 | |
| r2821 | r2822 | |
| 4961 | 4354 | |
| 4962 | 4355 | |
| 4963 | 4356 | /*------------------------------------------------- |
| 4357 | op_set - process a SET opcode |
| 4358 | -------------------------------------------------*/ |
| 4359 | |
| 4360 | static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4361 | { |
| 4362 | drcuml_parameter dstp; |
| 4363 | int dstreg; |
| 4364 | |
| 4365 | /* validate instruction */ |
| 4366 | assert(inst->size == 4 || inst->size == 8); |
| 4367 | assert(inst->condflags >= DRCUML_COND_Z && inst->condflags < DRCUML_COND_MAX); |
| 4368 | |
| 4369 | /* normalize parameters */ |
| 4370 | param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); |
| 4371 | |
| 4372 | /* pick a target register for the general case */ |
| 4373 | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4374 | |
| 4375 | /* set to AL */ |
| 4376 | emit_setcc_r8(&dst, X86_CONDITION(inst->condflags), REG_AL); // setcc al |
| 4377 | emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al |
| 4378 | |
| 4379 | /* store low 32 bits */ |
| 4380 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4381 | |
| 4382 | /* 64-bit form stores upper 32 bits */ |
| 4383 | if (inst->size == 8) |
| 4384 | { |
| 4385 | /* general case */ |
| 4386 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 4387 | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 4388 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 4389 | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 |
| 4390 | } |
| 4391 | return dst; |
| 4392 | } |
| 4393 | |
| 4394 | |
| 4395 | /*------------------------------------------------- |
| 4964 | 4396 | op_mov - process a MOV opcode |
| 4965 | 4397 | -------------------------------------------------*/ |
| 4966 | 4398 | |
| r2821 | r2822 | |
| 5067 | 4499 | |
| 5068 | 4500 | |
| 5069 | 4501 | /*------------------------------------------------- |
| 5070 | | op_zext1 - process a ZEXT1 opcode |
| 4502 | op_sext - process a SEXT opcode |
| 5071 | 4503 | -------------------------------------------------*/ |
| 5072 | 4504 | |
| 5073 | | static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4505 | static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5074 | 4506 | { |
| 5075 | | drcuml_parameter dstp, srcp; |
| 4507 | drcuml_parameter dstp, srcp, sizep; |
| 5076 | 4508 | int dstreg; |
| 5077 | 4509 | |
| 5078 | 4510 | /* validate instruction */ |
| r2821 | r2822 | |
| 5080 | 4512 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5081 | 4513 | |
| 5082 | 4514 | /* normalize parameters */ |
| 5083 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 4515 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI, &sizep, PTYPE_I); |
| 5084 | 4516 | |
| 5085 | 4517 | /* degenerate cases -- convert to a move */ |
| 5086 | 4518 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5087 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT8)srcp.value); |
| 5088 | | |
| 5089 | | /* pick a target register for the general case */ |
| 5090 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5091 | | |
| 5092 | | /* convert 8-bit source registers */ |
| 5093 | | if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) |
| 5094 | 4519 | { |
| 5095 | | emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp |
| 5096 | | srcp.value = REG_EAX; |
| 4520 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4521 | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); |
| 4522 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4523 | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); |
| 4524 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4525 | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); |
| 5097 | 4526 | } |
| 5098 | 4527 | |
| 5099 | | /* 32-bit form */ |
| 5100 | | if (inst->size == 4) |
| 5101 | | { |
| 5102 | | /* general case */ |
| 5103 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5104 | | emit_movzx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] |
| 5105 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5106 | | emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp |
| 5107 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5108 | | } |
| 5109 | | |
| 5110 | | /* 64-bit form */ |
| 5111 | | else if (inst->size == 8) |
| 5112 | | { |
| 5113 | | /* general case */ |
| 5114 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5115 | | emit_movzx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] |
| 5116 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5117 | | emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp |
| 5118 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5119 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 5120 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 5121 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5122 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0 |
| 5123 | | } |
| 5124 | | return dst; |
| 5125 | | } |
| 5126 | | |
| 5127 | | |
| 5128 | | /*------------------------------------------------- |
| 5129 | | op_zext2 - process a ZEXT2 opcode |
| 5130 | | -------------------------------------------------*/ |
| 5131 | | |
| 5132 | | static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5133 | | { |
| 5134 | | drcuml_parameter dstp, srcp; |
| 5135 | | int dstreg; |
| 5136 | | |
| 5137 | | /* validate instruction */ |
| 5138 | | assert(inst->size == 4 || inst->size == 8); |
| 5139 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5140 | | |
| 5141 | | /* normalize parameters */ |
| 5142 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5143 | | |
| 5144 | | /* degenerate cases -- convert to a move */ |
| 5145 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5146 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT16)srcp.value); |
| 5147 | | |
| 5148 | 4528 | /* pick a target register for the general case */ |
| 5149 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 4529 | dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL); |
| 5150 | 4530 | |
| 5151 | | /* 32-bit form */ |
| 5152 | | if (inst->size == 4) |
| 4531 | /* convert 8-bit source registers to EAX */ |
| 4532 | if (sizep.value == DRCUML_SIZE_BYTE && srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) |
| 5153 | 4533 | { |
| 5154 | | /* general case */ |
| 5155 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5156 | | emit_movzx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] |
| 5157 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5158 | | emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp |
| 5159 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5160 | | } |
| 5161 | | |
| 5162 | | /* 64-bit form */ |
| 5163 | | else if (inst->size == 8) |
| 5164 | | { |
| 5165 | | /* general case */ |
| 5166 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5167 | | emit_movzx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] |
| 5168 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5169 | | emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp |
| 5170 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5171 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 5172 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 5173 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5174 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0 |
| 5175 | | } |
| 5176 | | return dst; |
| 5177 | | } |
| 5178 | | |
| 5179 | | |
| 5180 | | /*------------------------------------------------- |
| 5181 | | op_zext4 - process a ZEXT4 opcode |
| 5182 | | -------------------------------------------------*/ |
| 5183 | | |
| 5184 | | static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5185 | | { |
| 5186 | | drcuml_parameter dstp, srcp; |
| 5187 | | int dstreg; |
| 5188 | | |
| 5189 | | /* validate instruction */ |
| 5190 | | assert(inst->size == 8); |
| 5191 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5192 | | |
| 5193 | | /* normalize parameters */ |
| 5194 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5195 | | |
| 5196 | | /* degenerate cases -- convert to a move */ |
| 5197 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5198 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)srcp.value); |
| 5199 | | |
| 5200 | | /* pick a target register for the general case */ |
| 5201 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5202 | | |
| 5203 | | /* 64-bit form */ |
| 5204 | | if (inst->size == 8) |
| 5205 | | { |
| 5206 | | /* general case */ |
| 5207 | | emit_mov_r32_p32(drcbe, &dst, dstreg, &srcp); // mov dstreg,srcp |
| 5208 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5209 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 5210 | | emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 |
| 5211 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5212 | | emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0 |
| 5213 | | } |
| 5214 | | return dst; |
| 5215 | | } |
| 5216 | | |
| 5217 | | |
| 5218 | | /*------------------------------------------------- |
| 5219 | | op_sext1 - process a SEXT1 opcode |
| 5220 | | -------------------------------------------------*/ |
| 5221 | | |
| 5222 | | static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5223 | | { |
| 5224 | | drcuml_parameter dstp, srcp; |
| 5225 | | int dstreg; |
| 5226 | | |
| 5227 | | /* validate instruction */ |
| 5228 | | assert(inst->size == 4 || inst->size == 8); |
| 5229 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5230 | | |
| 5231 | | /* normalize parameters */ |
| 5232 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5233 | | |
| 5234 | | /* degenerate cases -- convert to a move */ |
| 5235 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5236 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); |
| 5237 | | |
| 5238 | | /* pick a target register for the general case */ |
| 5239 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5240 | | |
| 5241 | | /* convert 8-bit source registers */ |
| 5242 | | if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) |
| 5243 | | { |
| 5244 | 4534 | emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp |
| 5245 | 4535 | srcp.value = REG_EAX; |
| 5246 | 4536 | } |
| 5247 | 4537 | |
| 5248 | | /* 32-bit form */ |
| 5249 | | if (inst->size == 4) |
| 4538 | /* general case */ |
| 4539 | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5250 | 4540 | { |
| 5251 | | /* general case */ |
| 5252 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 4541 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 5253 | 4542 | emit_movsx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp] |
| 5254 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5255 | | emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 5256 | | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 4543 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4544 | emit_movsx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp] |
| 4545 | else if (sizep.value == DRCUML_SIZE_DWORD) |
| 4546 | emit_mov_r32_m32(&dst, dstreg, MABS(srcp.value)); // mov dstreg,[srcp] |
| 5257 | 4547 | } |
| 5258 | | |
| 5259 | | /* 64-bit form */ |
| 5260 | | else if (inst->size == 8) |
| 4548 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5261 | 4549 | { |
| 5262 | | /* general case */ |
| 5263 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5264 | | emit_movsx_r32_m8(&dst, REG_EAX, MABS(srcp.value)); // movsx eax,[srcp] |
| 5265 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5266 | | emit_movsx_r32_r8(&dst, REG_EAX, srcp.value); // movsx eax,srcp |
| 5267 | | emit_cdq(&dst); // cdq |
| 5268 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 4550 | if (sizep.value == DRCUML_SIZE_BYTE) |
| 4551 | emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4552 | else if (sizep.value == DRCUML_SIZE_WORD) |
| 4553 | emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 4554 | else if (sizep.value == DRCUML_SIZE_DWORD && dstreg != srcp.value) |
| 4555 | emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp |
| 5269 | 4556 | } |
| 5270 | | return dst; |
| 5271 | | } |
| 5272 | 4557 | |
| 5273 | | |
| 5274 | | /*------------------------------------------------- |
| 5275 | | op_sext2 - process a SEXT2 opcode |
| 5276 | | -------------------------------------------------*/ |
| 5277 | | |
| 5278 | | static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5279 | | { |
| 5280 | | drcuml_parameter dstp, srcp; |
| 5281 | | int dstreg; |
| 5282 | | |
| 5283 | | /* validate instruction */ |
| 5284 | | assert(inst->size == 4 || inst->size == 8); |
| 5285 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5286 | | |
| 5287 | | /* normalize parameters */ |
| 5288 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5289 | | |
| 5290 | | /* degenerate cases -- convert to a move */ |
| 5291 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5292 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); |
| 5293 | | |
| 5294 | | /* pick a target register for the general case */ |
| 5295 | | dstreg = param_select_register(REG_EAX, &dstp, NULL); |
| 5296 | | |
| 5297 | | /* 32-bit form */ |
| 4558 | /* 32-bit form: store the low 32 bits */ |
| 5298 | 4559 | if (inst->size == 4) |
| 5299 | | { |
| 5300 | | /* general case */ |
| 5301 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5302 | | emit_movsx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp] |
| 5303 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5304 | | emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp |
| 5305 | 4560 | emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg |
| 5306 | | } |
| 5307 | 4561 | |
| 5308 | | /* 64-bit form */ |
| 4562 | /* 64-bit form: sign extend to 64 bits and store edx:eax */ |
| 5309 | 4563 | else if (inst->size == 8) |
| 5310 | 4564 | { |
| 5311 | | /* general case */ |
| 5312 | | if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 5313 | | emit_movsx_r32_m16(&dst, REG_EAX, MABS(srcp.value)); // movsx eax,[srcp] |
| 5314 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 5315 | | emit_movsx_r32_r16(&dst, REG_EAX, srcp.value); // movsx eax,srcp |
| 5316 | 4565 | emit_cdq(&dst); // cdq |
| 5317 | 4566 | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 5318 | 4567 | } |
| r2821 | r2822 | |
| 5321 | 4570 | |
| 5322 | 4571 | |
| 5323 | 4572 | /*------------------------------------------------- |
| 5324 | | op_sext4 - process a SEXT4 opcode |
| 4573 | op_roland - process an ROLAND opcode |
| 5325 | 4574 | -------------------------------------------------*/ |
| 5326 | 4575 | |
| 5327 | | static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4576 | static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5328 | 4577 | { |
| 5329 | | drcuml_parameter dstp, srcp; |
| 5330 | | |
| 5331 | | /* validate instruction */ |
| 5332 | | assert(inst->size == 8); |
| 5333 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 5334 | | |
| 5335 | | /* normalize parameters */ |
| 5336 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); |
| 5337 | | |
| 5338 | | /* degenerate cases -- convert to a move */ |
| 5339 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 5340 | | return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); |
| 5341 | | |
| 5342 | | /* 64-bit form */ |
| 5343 | | if (inst->size == 8) |
| 5344 | | { |
| 5345 | | /* general case */ |
| 5346 | | emit_mov_r32_p32(drcbe, &dst, REG_EAX, &srcp); // mov eax,srcp |
| 5347 | | emit_cdq(&dst); // cdq |
| 5348 | | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 5349 | | } |
| 5350 | | return dst; |
| 5351 | | } |
| 5352 | | |
| 5353 | | |
| 5354 | | /*------------------------------------------------- |
| 5355 | | op_xtract - process an XTRACT opcode |
| 5356 | | -------------------------------------------------*/ |
| 5357 | | |
| 5358 | | static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5359 | | { |
| 5360 | 4578 | drcuml_parameter dstp, srcp, shiftp, maskp; |
| 5361 | 4579 | int dstreg; |
| 5362 | 4580 | |
| r2821 | r2822 | |
| 5417 | 4635 | |
| 5418 | 4636 | |
| 5419 | 4637 | /*------------------------------------------------- |
| 5420 | | op_insert - process an INSERT opcode |
| 4638 | op_rolins - process an ROLINS opcode |
| 5421 | 4639 | -------------------------------------------------*/ |
| 5422 | 4640 | |
| 5423 | | static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 4641 | static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 5424 | 4642 | { |
| 5425 | 4643 | drcuml_parameter dstp, srcp, shiftp, maskp; |
| 5426 | 4644 | int dstreg; |
| r2821 | r2822 | |
| 5889 | 5107 | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 5890 | 5108 | if (compute_hi) |
| 5891 | 5109 | emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx |
| 5110 | |
| 5111 | /* compute flags */ |
| 5112 | if (inst->condflags != 0) |
| 5113 | { |
| 5114 | if (compute_hi) |
| 5115 | { |
| 5116 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5117 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5118 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5119 | emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx |
| 5120 | else |
| 5121 | { |
| 5122 | emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax |
| 5123 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5124 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5125 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5126 | } |
| 5127 | } |
| 5128 | else |
| 5129 | emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax |
| 5130 | } |
| 5892 | 5131 | } |
| 5893 | 5132 | |
| 5894 | 5133 | /* 64-bit form */ |
| r2821 | r2822 | |
| 5907 | 5146 | emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo |
| 5908 | 5147 | emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi |
| 5909 | 5148 | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 5910 | | if (inst->condflags != 0) |
| 5911 | | emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx |
| 5149 | if (inst->condflags != 0 && !compute_hi) |
| 5150 | { |
| 5151 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5152 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5153 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5154 | emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx |
| 5155 | else |
| 5156 | { |
| 5157 | emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax |
| 5158 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5159 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5160 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5161 | } |
| 5162 | } |
| 5912 | 5163 | if (compute_hi) |
| 5913 | 5164 | { |
| 5165 | if (inst->condflags & DRCUML_FLAG_Z) |
| 5166 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5914 | 5167 | emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo |
| 5915 | | emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi |
| 5916 | | emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax |
| 5168 | emit_mov_r32_m32(&dst, REG_ECX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov ecx,reshi.hi |
| 5169 | emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_ECX); // mov edstp,ecx:eax |
| 5170 | if (inst->condflags != 0) |
| 5171 | { |
| 5172 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5173 | { |
| 5174 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5175 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5176 | } |
| 5177 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5178 | emit_test_r32_r32(&dst, REG_ECX, REG_ECX); // test ecx,ecx |
| 5179 | else |
| 5180 | { |
| 5181 | emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx |
| 5182 | emit_movzx_r32_r16(&dst, REG_EDX, REG_AX); // movzx edx,ax |
| 5183 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5184 | emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or edx,ecx |
| 5185 | emit_or_r32_r32(&dst, REG_ECX, REG_EAX); // or edx,eax |
| 5186 | } |
| 5187 | } |
| 5917 | 5188 | } |
| 5918 | 5189 | } |
| 5919 | 5190 | return dst; |
| r2821 | r2822 | |
| 6008 | 5279 | emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax |
| 6009 | 5280 | emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx |
| 6010 | 5281 | } |
| 5282 | |
| 5283 | /* compute flags */ |
| 5284 | if (inst->condflags != 0) |
| 5285 | { |
| 5286 | if (compute_hi) |
| 5287 | { |
| 5288 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5289 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5290 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5291 | emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx |
| 5292 | else |
| 5293 | { |
| 5294 | emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax |
| 5295 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5296 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5297 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5298 | } |
| 5299 | } |
| 5300 | else |
| 5301 | emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax |
| 5302 | } |
| 6011 | 5303 | } |
| 6012 | 5304 | |
| 6013 | 5305 | /* 64-bit form */ |
| r2821 | r2822 | |
| 6026 | 5318 | emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo |
| 6027 | 5319 | emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi |
| 6028 | 5320 | emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax |
| 6029 | | if (inst->condflags != 0) |
| 6030 | | emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx |
| 5321 | if (inst->condflags != 0 && !compute_hi) |
| 5322 | { |
| 5323 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5324 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5325 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5326 | emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx |
| 5327 | else |
| 5328 | { |
| 5329 | emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax |
| 5330 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5331 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5332 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5333 | } |
| 5334 | } |
| 6031 | 5335 | if (compute_hi) |
| 6032 | 5336 | { |
| 6033 | 5337 | emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo |
| 6034 | 5338 | emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi |
| 6035 | 5339 | emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax |
| 5340 | if (inst->condflags != 0) |
| 5341 | { |
| 5342 | if (inst->condflags == DRCUML_FLAG_Z) |
| 5343 | { |
| 5344 | emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax |
| 5345 | emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx |
| 5346 | } |
| 5347 | else if (inst->condflags == DRCUML_FLAG_S) |
| 5348 | emit_test_r32_r32(&dst, REG_ECX, REG_ECX); // test ecx,ecx |
| 5349 | else |
| 5350 | { |
| 5351 | emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx |
| 5352 | emit_movzx_r32_r16(&dst, REG_EDX, REG_AX); // movzx edx,ax |
| 5353 | emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 |
| 5354 | emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or edx,ecx |
| 5355 | emit_or_r32_r32(&dst, REG_ECX, REG_EAX); // or edx,eax |
| 5356 | } |
| 5357 | } |
| 6036 | 5358 | } |
| 6037 | 5359 | } |
| 6038 | 5360 | return dst; |
| r2821 | r2822 | |
| 6963 | 6285 | /* immediate index */ |
| 6964 | 6286 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 6965 | 6287 | { |
| 6966 | | if (inst->size == 4) |
| 6967 | | emit_fld_m32(&dst, MABS(basep.value + 4*indp.value)); // fld [basep + 4*indp] |
| 6968 | | else if (inst->size == 8) |
| 6969 | | emit_fld_m64(&dst, MABS(basep.value + 8*indp.value)); // fld [basep + 8*indp] |
| 6288 | emit_mov_r32_m32(&dst, REG_EAX, MABS(basep.value + 4*indp.value)); // mov eax,[basep + 4*indp] |
| 6289 | if (inst->size == 8) |
| 6290 | emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 4 + 4*indp.value)); // mov edx,[basep + 4*indp + 4] |
| 6970 | 6291 | } |
| 6971 | 6292 | |
| 6972 | 6293 | /* other index */ |
| r2821 | r2822 | |
| 6974 | 6295 | { |
| 6975 | 6296 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 6976 | 6297 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 6977 | | if (inst->size == 4) |
| 6978 | | emit_fld_m32(&dst, MISD(indreg, 4, basep.value)); // fld [basep + 4*indp] |
| 6979 | | else if (inst->size == 8) |
| 6980 | | emit_fld_m64(&dst, MISD(indreg, 8, basep.value)); // fld [basep + 8*indp] |
| 6298 | emit_mov_r32_m32(&dst, REG_EAX, MISD(indreg, 4, basep.value)); // mov eax,[basep + 4*indp] |
| 6299 | if (inst->size == 8) |
| 6300 | emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 4, basep.value + 4)); // mov edx,[basep + 4*indp + 4] |
| 6981 | 6301 | } |
| 6982 | 6302 | |
| 6983 | 6303 | /* general case */ |
| 6984 | | emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp |
| 6985 | | |
| 6304 | emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax |
| 6305 | if (inst->size == 8) |
| 6306 | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp + 4],edx |
| 6986 | 6307 | return dst; |
| 6987 | 6308 | } |
| 6988 | 6309 | |
| r2821 | r2822 | |
| 7003 | 6324 | param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MF); |
| 7004 | 6325 | |
| 7005 | 6326 | /* general case */ |
| 7006 | | emit_fld_p(&dst, inst->size, &srcp); |
| 6327 | emit_mov_r32_m32(&dst, REG_EAX, MABS(srcp.value)); // mov eax,[srcp] |
| 6328 | if (inst->size == 8) |
| 6329 | emit_mov_r32_m32(&dst, REG_EDX, MABS(srcp.value + 4)); // mov edx,[srcp + 4] |
| 7007 | 6330 | |
| 7008 | 6331 | /* immediate index */ |
| 7009 | 6332 | if (indp.type == DRCUML_PTYPE_IMMEDIATE) |
| 7010 | 6333 | { |
| 7011 | | if (inst->size == 4) |
| 7012 | | emit_fstp_m32(&dst, MABS(basep.value + 4*indp.value)); // fstp [basep + 4*indp] |
| 7013 | | else if (inst->size == 8) |
| 7014 | | emit_fstp_m64(&dst, MABS(basep.value + 8*indp.value)); // fstp [basep + 8*indp] |
| 6334 | emit_mov_m32_r32(&dst, MABS(basep.value + 4*indp.value), REG_EAX); // mov [basep + 4*indp],eax |
| 6335 | if (inst->size == 8) |
| 6336 | emit_mov_m32_r32(&dst, MABS(basep.value + 4 + 4*indp.value), REG_EDX); // mov [basep + 4*indp + 4],edx |
| 7015 | 6337 | } |
| 7016 | 6338 | |
| 7017 | 6339 | /* other index */ |
| r2821 | r2822 | |
| 7019 | 6341 | { |
| 7020 | 6342 | int indreg = param_select_register(REG_ECX, &indp, NULL); |
| 7021 | 6343 | emit_mov_r32_p32(drcbe, &dst, indreg, &indp); |
| 7022 | | if (inst->size == 4) |
| 7023 | | emit_fstp_m32(&dst, MISD(indreg, 4, basep.value)); // fstp [basep + 4*indp] |
| 7024 | | else if (inst->size == 8) |
| 7025 | | emit_fstp_m64(&dst, MISD(indreg, 8, basep.value)); // fstp [basep + 8*indp] |
| 6344 | emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), REG_EAX); // mov [basep + 4*indp],eax |
| 6345 | if (inst->size == 8) |
| 6346 | emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value + 4), REG_EDX); // mov [basep + 4*indp + 4],edx |
| 7026 | 6347 | } |
| 7027 | 6348 | return dst; |
| 7028 | 6349 | } |
| r2821 | r2822 | |
| 7041 | 6362 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7042 | 6363 | |
| 7043 | 6364 | /* normalize parameters */ |
| 7044 | | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &spacep, PTYPE_I, &addrp, PTYPE_MRI); |
| 6365 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &addrp, PTYPE_MRI, &spacep, PTYPE_I); |
| 7045 | 6366 | |
| 7046 | 6367 | /* set up a call to the read dword/qword handler */ |
| 7047 | 6368 | emit_push_p32(drcbe, &dst, &addrp); // push addrp |
| r2821 | r2822 | |
| 7074 | 6395 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7075 | 6396 | |
| 7076 | 6397 | /* normalize parameters */ |
| 7077 | | param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MF); |
| 6398 | param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MF, &spacep, PTYPE_I); |
| 7078 | 6399 | |
| 7079 | 6400 | /* set up a call to the write dword/qword handler */ |
| 7080 | 6401 | if (inst->size == 4) |
| r2821 | r2822 | |
| 7113 | 6434 | emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip |
| 7114 | 6435 | |
| 7115 | 6436 | /* general case */ |
| 7116 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7117 | | emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp |
| 6437 | emit_mov_r32_m32(&dst, REG_EAX, MABS(srcp.value)); // mov eax,[srcp] |
| 6438 | if (inst->size == 8) |
| 6439 | emit_mov_r32_m32(&dst, REG_EDX, MABS(srcp.value + 4)); // mov edx,[srcp + 4] |
| 6440 | emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax |
| 6441 | if (inst->size == 8) |
| 6442 | emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp + 4],edx |
| 7118 | 6443 | |
| 7119 | 6444 | /* resolve the jump */ |
| 7120 | 6445 | if (skip.target != NULL) |
| r2821 | r2822 | |
| 7124 | 6449 | |
| 7125 | 6450 | |
| 7126 | 6451 | /*------------------------------------------------- |
| 7127 | | op_ftoi4 - process a FTOI4 opcode |
| 6452 | op_ftoint - process a FTOINT opcode |
| 7128 | 6453 | -------------------------------------------------*/ |
| 7129 | 6454 | |
| 7130 | | static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6455 | static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7131 | 6456 | { |
| 7132 | | drcuml_parameter dstp, srcp; |
| 6457 | drcuml_parameter dstp, srcp, sizep, roundp; |
| 7133 | 6458 | |
| 7134 | 6459 | /* validate instruction */ |
| 7135 | 6460 | assert(inst->size == 4 || inst->size == 8); |
| 7136 | 6461 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7137 | 6462 | |
| 7138 | 6463 | /* normalize parameters */ |
| 7139 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 6464 | param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF, &sizep, PTYPE_I, &roundp, PTYPE_I); |
| 7140 | 6465 | |
| 7141 | | /* general case */ |
| 7142 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7143 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7144 | | emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7145 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 6466 | /* set rounding mode if necessary */ |
| 6467 | if (roundp.value != DRCUML_FMOD_DEFAULT && (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC)) |
| 7146 | 6468 | { |
| 7147 | | emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7148 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 6469 | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 6470 | emit_fldcw_m16(&dst, MABS(&fp_control[roundp.value])); // fldcw fpcontrol[roundp] |
| 7149 | 6471 | } |
| 7150 | | return dst; |
| 7151 | | } |
| 7152 | 6472 | |
| 6473 | /* general case */ |
| 6474 | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7153 | 6475 | |
| 7154 | | /*------------------------------------------------- |
| 7155 | | op_ftoi4t - process a FTOI4T opcode |
| 7156 | | -------------------------------------------------*/ |
| 7157 | | |
| 7158 | | static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7159 | | { |
| 7160 | | drcuml_parameter dstp, srcp; |
| 7161 | | |
| 7162 | | /* validate instruction */ |
| 7163 | | assert(inst->size == 4 || inst->size == 8); |
| 7164 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7165 | | |
| 7166 | | /* normalize parameters */ |
| 7167 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7168 | | |
| 7169 | | /* non-SSE3 case */ |
| 7170 | | if (!drcbe->sse3) |
| 6476 | /* 4-byte integer case */ |
| 6477 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 7171 | 6478 | { |
| 7172 | | /* save and set the control word */ |
| 7173 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7174 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_TRUNC])); // fldcw fpcontrol[DRCUML_FMOD_TRUNC] |
| 7175 | | |
| 7176 | | /* general case */ |
| 7177 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7178 | 6479 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7179 | | emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] |
| 6480 | { |
| 6481 | if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) |
| 6482 | emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] |
| 6483 | else |
| 6484 | emit_fisttp_m32(&dst, MABS(dstp.value)); // fisttp [dstp] |
| 6485 | } |
| 7180 | 6486 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7181 | 6487 | { |
| 7182 | | emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 6488 | if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) |
| 6489 | emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 6490 | else |
| 6491 | emit_fisttp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] |
| 7183 | 6492 | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7184 | 6493 | } |
| 7185 | | |
| 7186 | | /* restore control word and proceed */ |
| 7187 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7188 | 6494 | } |
| 7189 | 6495 | |
| 7190 | | /* SSE3 case */ |
| 7191 | | else |
| 6496 | /* 8-byte integer case */ |
| 6497 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 7192 | 6498 | { |
| 7193 | | /* general case */ |
| 7194 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7195 | 6499 | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7196 | | emit_fisttp_m32(&dst, MABS(dstp.value)); // fisttp [dstp] |
| 6500 | { |
| 6501 | if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) |
| 6502 | emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] |
| 6503 | else |
| 6504 | emit_fisttp_m64(&dst, MABS(dstp.value)); // fisttp [dstp] |
| 6505 | } |
| 7197 | 6506 | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7198 | 6507 | { |
| 7199 | | emit_fisttp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] |
| 6508 | if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) |
| 6509 | emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 6510 | else |
| 6511 | emit_fisttp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] |
| 7200 | 6512 | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7201 | 6513 | } |
| 7202 | 6514 | } |
| 7203 | | return dst; |
| 7204 | | } |
| 7205 | 6515 | |
| 7206 | | |
| 7207 | | /*------------------------------------------------- |
| 7208 | | op_ftoi4r - process a FTOI4R opcode |
| 7209 | | -------------------------------------------------*/ |
| 7210 | | |
| 7211 | | static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7212 | | { |
| 7213 | | drcuml_parameter dstp, srcp; |
| 7214 | | |
| 7215 | | /* validate instruction */ |
| 7216 | | assert(inst->size == 4 || inst->size == 8); |
| 7217 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7218 | | |
| 7219 | | /* normalize parameters */ |
| 7220 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7221 | | |
| 7222 | | /* save and set the control word */ |
| 7223 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7224 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_ROUND])); // fldcw fpcontrol[DRCUML_FMOD_ROUND] |
| 7225 | | |
| 7226 | | /* general case */ |
| 7227 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7228 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7229 | | emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7230 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7231 | | { |
| 7232 | | emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7233 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7234 | | } |
| 7235 | | |
| 7236 | 6516 | /* restore control word and proceed */ |
| 7237 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7238 | | return dst; |
| 7239 | | } |
| 6517 | if (roundp.value != DRCUML_FMOD_DEFAULT && (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC)) |
| 6518 | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7240 | 6519 | |
| 7241 | | |
| 7242 | | /*------------------------------------------------- |
| 7243 | | op_ftoi4f - process a FTOI4F opcode |
| 7244 | | -------------------------------------------------*/ |
| 7245 | | |
| 7246 | | static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7247 | | { |
| 7248 | | drcuml_parameter dstp, srcp; |
| 7249 | | |
| 7250 | | /* validate instruction */ |
| 7251 | | assert(inst->size == 4 || inst->size == 8); |
| 7252 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7253 | | |
| 7254 | | /* normalize parameters */ |
| 7255 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7256 | | |
| 7257 | | /* save and set the control word */ |
| 7258 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7259 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_FLOOR])); // fldcw fpcontrol[DRCUML_FMOD_FLOOR] |
| 7260 | | |
| 7261 | | /* general case */ |
| 7262 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7263 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7264 | | emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7265 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7266 | | { |
| 7267 | | emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7268 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7269 | | } |
| 7270 | | |
| 7271 | | /* restore control word and proceed */ |
| 7272 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7273 | 6520 | return dst; |
| 7274 | 6521 | } |
| 7275 | 6522 | |
| 7276 | 6523 | |
| 7277 | 6524 | /*------------------------------------------------- |
| 7278 | | op_ftoi4c - process a FTOI4C opcode |
| 6525 | op_ffrint - process a FFRINT opcode |
| 7279 | 6526 | -------------------------------------------------*/ |
| 7280 | 6527 | |
| 7281 | | static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6528 | static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7282 | 6529 | { |
| 7283 | | drcuml_parameter dstp, srcp; |
| 6530 | drcuml_parameter dstp, srcp, sizep; |
| 7284 | 6531 | |
| 7285 | 6532 | /* validate instruction */ |
| 7286 | 6533 | assert(inst->size == 4 || inst->size == 8); |
| 7287 | 6534 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7288 | 6535 | |
| 7289 | 6536 | /* normalize parameters */ |
| 7290 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 6537 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI, &sizep, PTYPE_I); |
| 7291 | 6538 | |
| 7292 | | /* save and set the control word */ |
| 7293 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7294 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_CEIL])); // fldcw fpcontrol[DRCUML_FMOD_CEIL] |
| 7295 | | |
| 7296 | | /* general case */ |
| 7297 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7298 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7299 | | emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7300 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 6539 | /* 4-byte integer case */ |
| 6540 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 7301 | 6541 | { |
| 7302 | | emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7303 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7304 | | } |
| 7305 | | |
| 7306 | | /* restore control word and proceed */ |
| 7307 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7308 | | return dst; |
| 7309 | | } |
| 7310 | | |
| 7311 | | |
| 7312 | | /*------------------------------------------------- |
| 7313 | | op_ftoi8 - process a FTOI8 opcode |
| 7314 | | -------------------------------------------------*/ |
| 7315 | | |
| 7316 | | static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7317 | | { |
| 7318 | | drcuml_parameter dstp, srcp; |
| 7319 | | |
| 7320 | | /* validate instruction */ |
| 7321 | | assert(inst->size == 4 || inst->size == 8); |
| 7322 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7323 | | |
| 7324 | | /* normalize parameters */ |
| 7325 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7326 | | |
| 7327 | | /* general case */ |
| 7328 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7329 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7330 | | emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7331 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7332 | | { |
| 7333 | | emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7334 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7335 | | } |
| 7336 | | return dst; |
| 7337 | | } |
| 7338 | | |
| 7339 | | |
| 7340 | | /*------------------------------------------------- |
| 7341 | | op_ftoi8t - process a FTOI8T opcode |
| 7342 | | -------------------------------------------------*/ |
| 7343 | | |
| 7344 | | static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7345 | | { |
| 7346 | | drcuml_parameter dstp, srcp; |
| 7347 | | |
| 7348 | | /* validate instruction */ |
| 7349 | | assert(inst->size == 4 || inst->size == 8); |
| 7350 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7351 | | |
| 7352 | | /* normalize parameters */ |
| 7353 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7354 | | |
| 7355 | | /* non-SSE3 case */ |
| 7356 | | if (!drcbe->sse3) |
| 7357 | | { |
| 7358 | | /* save and set the control word */ |
| 7359 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7360 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_TRUNC])); // fldcw fpcontrol[DRCUML_FMOD_TRUNC] |
| 7361 | | |
| 7362 | | /* general case */ |
| 7363 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7364 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7365 | | emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7366 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 6542 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 7367 | 6543 | { |
| 7368 | | emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7369 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 6544 | emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp |
| 6545 | emit_fild_m32(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] |
| 7370 | 6546 | } |
| 7371 | | |
| 7372 | | /* restore control word and proceed */ |
| 7373 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 6547 | else if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6548 | emit_fild_m32(&dst, MABS(srcp.value)); // fild [srcp] |
| 6549 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 6550 | { |
| 6551 | emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp |
| 6552 | emit_fild_m32(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] |
| 6553 | } |
| 7374 | 6554 | } |
| 7375 | 6555 | |
| 7376 | | /* SSE3 case */ |
| 7377 | | else |
| 6556 | /* 8-bit integer case */ |
| 6557 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 7378 | 6558 | { |
| 7379 | | /* general case */ |
| 7380 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7381 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7382 | | emit_fisttp_m64(&dst, MABS(dstp.value)); // fisttp [dstp] |
| 7383 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 6559 | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 7384 | 6560 | { |
| 7385 | | emit_fisttp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] |
| 7386 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 6561 | emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp |
| 6562 | emit_mov_m32_imm(&dst, MABS((UINT8 *)&drcbe->fptemp + 4), srcp.value); // mov [fptemp+4],srcp |
| 6563 | emit_fild_m64(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] |
| 7387 | 6564 | } |
| 6565 | else if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 6566 | emit_fild_m64(&dst, MABS(srcp.value)); // fild [srcp] |
| 6567 | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 6568 | { |
| 6569 | emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp |
| 6570 | emit_fild_m64(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] |
| 6571 | } |
| 7388 | 6572 | } |
| 7389 | | return dst; |
| 7390 | | } |
| 7391 | 6573 | |
| 7392 | | |
| 7393 | | /*------------------------------------------------- |
| 7394 | | op_ftoi8r - process a FTOI8R opcode |
| 7395 | | -------------------------------------------------*/ |
| 7396 | | |
| 7397 | | static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7398 | | { |
| 7399 | | drcuml_parameter dstp, srcp; |
| 7400 | | |
| 7401 | | /* validate instruction */ |
| 7402 | | assert(inst->size == 4 || inst->size == 8); |
| 7403 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7404 | | |
| 7405 | | /* normalize parameters */ |
| 7406 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7407 | | |
| 7408 | | /* save and set the control word */ |
| 7409 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7410 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_ROUND])); // fldcw fpcontrol[DRCUML_FMOD_ROUND] |
| 7411 | | |
| 7412 | | /* general case */ |
| 7413 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7414 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7415 | | emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7416 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7417 | | { |
| 7418 | | emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7419 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7420 | | } |
| 7421 | | |
| 7422 | | /* restore control word and proceed */ |
| 7423 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 6574 | /* store the result and be done */ |
| 6575 | emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp] |
| 7424 | 6576 | return dst; |
| 7425 | 6577 | } |
| 7426 | 6578 | |
| 7427 | 6579 | |
| 7428 | 6580 | /*------------------------------------------------- |
| 7429 | | op_ftoi8f - process a FTOI8F opcode |
| 6581 | op_ffrflt - process a FFRFLT opcode |
| 7430 | 6582 | -------------------------------------------------*/ |
| 7431 | 6583 | |
| 7432 | | static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6584 | static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7433 | 6585 | { |
| 7434 | | drcuml_parameter dstp, srcp; |
| 6586 | drcuml_parameter dstp, srcp, sizep; |
| 7435 | 6587 | |
| 7436 | 6588 | /* validate instruction */ |
| 7437 | 6589 | assert(inst->size == 4 || inst->size == 8); |
| 7438 | 6590 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7439 | 6591 | |
| 7440 | 6592 | /* normalize parameters */ |
| 7441 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 6593 | param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF, &sizep, PTYPE_I); |
| 7442 | 6594 | |
| 7443 | | /* save and set the control word */ |
| 7444 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7445 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_FLOOR])); // fldcw fpcontrol[DRCUML_FMOD_FLOOR] |
| 7446 | | |
| 7447 | 6595 | /* general case */ |
| 7448 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7449 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7450 | | emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7451 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7452 | | { |
| 7453 | | emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7454 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7455 | | } |
| 6596 | if (sizep.value == DRCUML_SIZE_DWORD) |
| 6597 | emit_fld_m32(&dst, MABS(srcp.value)); // fld [srcp] |
| 6598 | else if (sizep.value == DRCUML_SIZE_QWORD) |
| 6599 | emit_fld_m64(&dst, MABS(srcp.value)); // fld [srcp] |
| 6600 | emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp |
| 7456 | 6601 | |
| 7457 | | /* restore control word and proceed */ |
| 7458 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7459 | 6602 | return dst; |
| 7460 | 6603 | } |
| 7461 | 6604 | |
| 7462 | 6605 | |
| 7463 | 6606 | /*------------------------------------------------- |
| 7464 | | op_ftoi8c - process a FTOI8C opcode |
| 6607 | op_frnds - process a FRNDS opcode |
| 7465 | 6608 | -------------------------------------------------*/ |
| 7466 | 6609 | |
| 7467 | | static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 6610 | static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7468 | 6611 | { |
| 7469 | 6612 | drcuml_parameter dstp, srcp; |
| 7470 | 6613 | |
| 7471 | 6614 | /* validate instruction */ |
| 7472 | | assert(inst->size == 4 || inst->size == 8); |
| 7473 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7474 | | |
| 7475 | | /* normalize parameters */ |
| 7476 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); |
| 7477 | | |
| 7478 | | /* save and set the control word */ |
| 7479 | | emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] |
| 7480 | | emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_CEIL])); // fldcw fpcontrol[DRCUML_FMOD_CEIL] |
| 7481 | | |
| 7482 | | /* general case */ |
| 7483 | | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 7484 | | if (dstp.type == DRCUML_PTYPE_MEMORY) |
| 7485 | | emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] |
| 7486 | | else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7487 | | { |
| 7488 | | emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] |
| 7489 | | emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] |
| 7490 | | } |
| 7491 | | |
| 7492 | | /* restore control word and proceed */ |
| 7493 | | emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] |
| 7494 | | return dst; |
| 7495 | | } |
| 7496 | | |
| 7497 | | |
| 7498 | | /*------------------------------------------------- |
| 7499 | | op_ffrfs - process a FFRFS opcode |
| 7500 | | -------------------------------------------------*/ |
| 7501 | | |
| 7502 | | static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7503 | | { |
| 7504 | | drcuml_parameter dstp, srcp; |
| 7505 | | |
| 7506 | | /* validate instruction */ |
| 7507 | 6615 | assert(inst->size == 8); |
| 7508 | 6616 | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7509 | 6617 | |
| r2821 | r2822 | |
| 7511 | 6619 | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); |
| 7512 | 6620 | |
| 7513 | 6621 | /* general case */ |
| 7514 | | emit_fld_m32(&dst, MABS(srcp.value)); // fld [srcp] |
| 7515 | | emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp |
| 7516 | | |
| 7517 | | return dst; |
| 7518 | | } |
| 7519 | | |
| 7520 | | |
| 7521 | | /*------------------------------------------------- |
| 7522 | | op_ffrfd - process a FFRFD opcode |
| 7523 | | -------------------------------------------------*/ |
| 7524 | | |
| 7525 | | static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7526 | | { |
| 7527 | | drcuml_parameter dstp, srcp; |
| 7528 | | |
| 7529 | | /* validate instruction */ |
| 7530 | | assert(inst->size == 4); |
| 7531 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7532 | | |
| 7533 | | /* normalize parameters */ |
| 7534 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); |
| 7535 | | |
| 7536 | | /* general case */ |
| 7537 | | emit_fld_m64(&dst, MABS(srcp.value)); // fld [srcp] |
| 7538 | | emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp |
| 7539 | | |
| 7540 | | return dst; |
| 7541 | | } |
| 7542 | | |
| 7543 | | |
| 7544 | | /*------------------------------------------------- |
| 7545 | | op_ffri4 - process a FFRI4 opcode |
| 7546 | | -------------------------------------------------*/ |
| 7547 | | |
| 7548 | | static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7549 | | { |
| 7550 | | drcuml_parameter dstp, srcp; |
| 7551 | | |
| 7552 | | /* validate instruction */ |
| 7553 | | assert(inst->size == 4 || inst->size == 8); |
| 7554 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7555 | | |
| 7556 | | /* normalize parameters */ |
| 7557 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI); |
| 7558 | | |
| 7559 | | /* general case */ |
| 7560 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 7561 | | { |
| 7562 | | emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp |
| 7563 | | emit_fild_m32(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] |
| 7564 | | } |
| 7565 | | else if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7566 | | emit_fild_m32(&dst, MABS(srcp.value)); // fild [srcp] |
| 7567 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7568 | | { |
| 7569 | | emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp |
| 7570 | | emit_fild_m32(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] |
| 7571 | | } |
| 6622 | emit_fld_p(&dst, inst->size, &srcp); // fld srcp |
| 6623 | emit_fstp_m32(&dst, MABS(&drcbe->fptemp)); // fstp [fptemp] |
| 6624 | emit_fld_m32(&dst, MABS(&drcbe->fptemp)); // fld [fptemp] |
| 7572 | 6625 | emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp] |
| 7573 | 6626 | return dst; |
| 7574 | 6627 | } |
| 7575 | 6628 | |
| 7576 | 6629 | |
| 7577 | 6630 | /*------------------------------------------------- |
| 7578 | | op_ffri8 - process a FFRI8 opcode |
| 7579 | | -------------------------------------------------*/ |
| 7580 | | |
| 7581 | | static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) |
| 7582 | | { |
| 7583 | | drcuml_parameter dstp, srcp; |
| 7584 | | |
| 7585 | | /* validate instruction */ |
| 7586 | | assert(inst->size == 4 || inst->size == 8); |
| 7587 | | assert(inst->condflags == DRCUML_COND_ALWAYS); |
| 7588 | | |
| 7589 | | /* normalize parameters */ |
| 7590 | | param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI); |
| 7591 | | |
| 7592 | | /* general case */ |
| 7593 | | if (srcp.type == DRCUML_PTYPE_IMMEDIATE) |
| 7594 | | { |
| 7595 | | emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp |
| 7596 | | emit_mov_m32_imm(&dst, MABS((UINT8 *)&drcbe->fptemp + 4), srcp.value); // mov [fptemp+4],srcp |
| 7597 | | emit_fild_m64(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] |
| 7598 | | } |
| 7599 | | else if (srcp.type == DRCUML_PTYPE_MEMORY) |
| 7600 | | emit_fild_m64(&dst, MABS(srcp.value)); // fild [srcp] |
| 7601 | | else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) |
| 7602 | | { |
| 7603 | | emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp |
| 7604 | | emit_fild_m64(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] |
| 7605 | | } |
| 7606 | | emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp] |
| 7607 | | return dst; |
| 7608 | | } |
| 7609 | | |
| 7610 | | |
| 7611 | | /*------------------------------------------------- |
| 7612 | 6631 | op_fadd - process a FADD opcode |
| 7613 | 6632 | -------------------------------------------------*/ |
| 7614 | 6633 | |
src/emu/cheat.c
| r2821 | r2822 | |
| 47 | 47 | |
| 48 | 48 | #define ADD_MENU_3_ITEMS(name, sub_name, enum) do { menu_item[total] = name; menu_sub_item[total] = sub_name; menu_index[total] = enum; total++; } while(0) |
| 49 | 49 | |
| 50 | | #define ADJUST_CURSOR(sel, total) if(sel < 0) sel = 0; else if(sel > (total - 1)) sel = (total - 1); |
| 51 | | #define CURSOR_TO_NEXT(sel, total) if(++sel > (total - 1)) sel = 0; |
| 52 | | #define CURSOR_TO_PREVIOUS(sel, total) if(--sel < 0) sel = (total - 1); |
| 53 | | #define CURSOR_PAGE_UP(sel) sel -= visible_items; if(sel < 0) sel = 0; |
| 54 | | #define CURSOR_PAGE_DOWN(sel, total) sel += visible_items; if(sel >= total) sel = (total - 1); |
| 50 | #define ADJUST_CURSOR(sel, total) do { if(sel < 0) sel = 0; else if(sel > (total - 1)) sel = (total - 1); } while(0); |
| 51 | #define CURSOR_TO_NEXT(sel, total) do { if(++sel > (total - 1)) sel = 0; } while(0) |
| 52 | #define CURSOR_TO_PREVIOUS(sel, total) do { if(--sel < 0) sel = (total - 1); } while(0) |
| 53 | #define CURSOR_PAGE_UP(sel) do { sel -= visible_items; if(sel < 0) sel = 0; } while (0) |
| 54 | #define CURSOR_PAGE_DOWN(sel, total) do { sel += visible_items; if(sel >= total) sel = (total - 1); } while (0) |
| 55 | #define SET_MESSAGE(type) do { message_timer = DEFAULT_MESSAGE_TIME; message_type = type; } while(0) |
| 55 | 56 | |
| 56 | 57 | /*************************************************************************** |
| 57 | 58 | CONSTANTS |
| r2821 | r2822 | |
| 65 | 66 | #define DEFAULT_CHEAT_OPTIONS (0xF) |
| 66 | 67 | #endif |
| 67 | 68 | #define DEFAULT_MESSAGE_TIME (50) |
| 68 | | #define VARIABLE_MAX_ARRAY (0x0F) // NOTE : Move code can accept max 16 variables as destination |
| 69 | #define VARIABLE_MAX_ARRAY (0x0F) /* NOTE : Destination in Move code can only accept variable[0]-[3] only */ |
| 69 | 70 | #define CHEAT_RETURN_VALUE (0xFF) |
| 70 | | #define CUSTOM_CODE (0xFF) |
| 71 | #define DEFAULT_ADDRESS_LENGTH (8) |
| 72 | #define SAFE_SEARCH_REGION_RANGE (0xFFFF) |
| 71 | 73 | |
| 72 | 74 | /********** BIT FIELD **********/ |
| 73 | 75 | |
| r2821 | r2822 | |
| 75 | 77 | { |
| 76 | 78 | /* type field */ |
| 77 | 79 | DEFINE_BITFIELD_ENUM(OneShot, 0, 0), |
| 78 | | DEFINE_BITFIELD_ENUM(DelayEnable, 1, 1), |
| 79 | | DEFINE_BITFIELD_ENUM(PrefillEnable, 2, 2), |
| 80 | | DEFINE_BITFIELD_ENUM(Return, 3, 3), |
| 81 | | DEFINE_BITFIELD_ENUM(RestoreValue, 4, 4), |
| 82 | | DEFINE_BITFIELD_ENUM(DataRead, 5, 5), // 0 = field, 1 = variable |
| 83 | | DEFINE_BITFIELD_ENUM(AddressRead, 6, 7), // 0 = field, 1 = indirect address from variable, 2 = variable |
| 84 | | DEFINE_BITFIELD_ENUM(CodeParameter, 8, 11), |
| 85 | | DEFINE_BITFIELD_ENUM(CodeType, 12, 15), |
| 86 | | DEFINE_BITFIELD_ENUM(Link, 16, 17), // 0 = master, 1 = link, 2 = sub link for label-selection, 3 = copy link for VWrite, VRWrite |
| 87 | | DEFINE_BITFIELD_ENUM(LinkValueSelectBCD, 18, 18), // used by VWrite (link) |
| 88 | | DEFINE_BITFIELD_ENUM(LinkValueSelectNegative, 19, 19), // used by VWrite (link) |
| 89 | | DEFINE_BITFIELD_ENUM(PopupParameter, 18, 19), // used by Popup |
| 80 | DEFINE_BITFIELD_ENUM(DelayEnable, 1, 3), |
| 81 | DEFINE_BITFIELD_ENUM(PrefillEnable, 4, 5), |
| 82 | DEFINE_BITFIELD_ENUM(Return, 6, 6), |
| 83 | DEFINE_BITFIELD_ENUM(RestoreValue, 7, 7), |
| 84 | DEFINE_BITFIELD_ENUM(ValueSelectEnable, 8, 8), /* = CopyValueEnable */ |
| 85 | DEFINE_BITFIELD_ENUM(ValueSelectMinimumDisplay, 9, 9), |
| 86 | DEFINE_BITFIELD_ENUM(ValueSelectMinimum, 10, 10), |
| 87 | DEFINE_BITFIELD_ENUM(ValueSelectBCD, 11, 11), /* = CopyValueBCD */ |
| 88 | DEFINE_BITFIELD_ENUM(ValueSelectNegative, 12, 12), /* = CopyValueNegative */ |
| 89 | DEFINE_BITFIELD_ENUM(PopupParameter, 13, 14), |
| 90 | DEFINE_BITFIELD_ENUM(DataRead, 15, 15), /* 0 = field, 1 = variable */ |
| 91 | DEFINE_BITFIELD_ENUM(Link, 16, 17), /* 0 = master, 1 = link, 2 = sub link, 3 = EOL */ |
| 92 | DEFINE_BITFIELD_ENUM(Endianness, 18, 18), |
| 90 | 93 | DEFINE_BITFIELD_ENUM(AddressSize, 20, 21), |
| 91 | | DEFINE_BITFIELD_ENUM(IndexSize, 22, 23), // used by IWrite, VWrite, Move, Popup |
| 92 | | DEFINE_BITFIELD_ENUM(CPURegion, 24, 31), // extract to CPU/Region field |
| 94 | DEFINE_BITFIELD_ENUM(AddressRead, 22, 23), /* 0 = field, 1 = indirect address from variable, 2 = variable */ |
| 95 | DEFINE_BITFIELD_ENUM(CodeParameter, 24, 27), |
| 96 | DEFINE_BITFIELD_ENUM(CodeParameterLower, 24, 25), |
| 97 | DEFINE_BITFIELD_ENUM(CodeParameterUpper, 26, 27), |
| 98 | DEFINE_BITFIELD_ENUM(CodeType, 28, 31), |
| 93 | 99 | |
| 94 | 100 | /* extend field */ |
| 95 | | DEFINE_BITFIELD_ENUM(LSB16, 0, 15), // lower 4 bytes |
| 96 | | DEFINE_BITFIELD_ENUM(MSB16, 16, 31), // upper 4 bytes |
| 101 | DEFINE_BITFIELD_ENUM(LSB16, 0, 15), /* lower 4 bytes */ |
| 102 | DEFINE_BITFIELD_ENUM(MSB16, 16, 31), /* upper 4 bytes */ |
| 97 | 103 | |
| 98 | | /* value-select master code */ |
| 99 | | DEFINE_BITFIELD_ENUM(ValueSelectMinimumDisplay, 8, 8), |
| 100 | | DEFINE_BITFIELD_ENUM(ValueSelectMinimum, 9, 9), |
| 101 | | DEFINE_BITFIELD_ENUM(ValueSelectBCD, 10, 10), |
| 102 | | DEFINE_BITFIELD_ENUM(ValueSelectNegative, 11, 11), |
| 103 | | |
| 104 | 104 | /* watch code */ |
| 105 | | DEFINE_BITFIELD_ENUM(WatchDisplayFormat, 8, 9), // from type field |
| 106 | | DEFINE_BITFIELD_ENUM(WatchShowLabel, 10, 10), // |
| 107 | | DEFINE_BITFIELD_ENUM(WatchNumElements, 0, 7), // from data field |
| 108 | | DEFINE_BITFIELD_ENUM(WatchSkip, 8, 15), // |
| 109 | | DEFINE_BITFIELD_ENUM(WatchElementsPerLine, 16, 23), // |
| 110 | | DEFINE_BITFIELD_ENUM(WatchAddValue, 24, 31), // |
| 105 | DEFINE_BITFIELD_ENUM(WatchDisplayFormat, 24, 25), /* from type field */ |
| 106 | DEFINE_BITFIELD_ENUM(WatchShowLabel, 26, 27), /* from type field */ |
| 107 | DEFINE_BITFIELD_ENUM(WatchNumElements, 0, 7), /* from data field */ |
| 108 | DEFINE_BITFIELD_ENUM(WatchSkip, 8, 15), /* from data field */ |
| 109 | DEFINE_BITFIELD_ENUM(WatchElementsPerLine, 16, 23), /* from data field */ |
| 110 | DEFINE_BITFIELD_ENUM(WatchAddValue, 24, 31), /* from data field */ |
| 111 | 111 | |
| 112 | 112 | /* label-selection */ |
| 113 | 113 | DEFINE_BITFIELD_ENUM(LabelSelectUseSelector, 4, 4), |
| 114 | 114 | DEFINE_BITFIELD_ENUM(LabelSelectQuickClose, 5, 5), |
| 115 | 115 | |
| 116 | 116 | /* cpu/region field */ |
| 117 | | DEFINE_BITFIELD_ENUM(CPUIndex, 0, 3), // cpu region |
| 118 | | DEFINE_BITFIELD_ENUM(AddressSpace, 4, 6), // cpu region |
| 119 | | DEFINE_BITFIELD_ENUM(RegionIndex, 0, 6), // non-cpu region |
| 120 | | DEFINE_BITFIELD_ENUM(RegionFlag, 7, 7), // 0 = cpu, 1 = non-cpu |
| 117 | DEFINE_BITFIELD_ENUM(CPUIndex, 0, 3), |
| 118 | DEFINE_BITFIELD_ENUM(AddressSpace, 4, 6), |
| 119 | // DEFINE_BITFIELD_ENUM(RegionIndex, 0, 6), /* unused ??? */ |
| 121 | 120 | |
| 122 | 121 | /* old code */ |
| 123 | | // DEFINE_BITFIELD_ENUM(OneShot, 0, 0), |
| 122 | // DEFINE_BITFIELD_ENUM(OneShot, 0, 0), /* = OneShot in new format */ |
| 124 | 123 | DEFINE_BITFIELD_ENUM(Type, 1, 2), |
| 125 | 124 | DEFINE_BITFIELD_ENUM(Operation, 3, 4), |
| 126 | 125 | DEFINE_BITFIELD_ENUM(TypeParameter, 5, 7), |
| r2821 | r2822 | |
| 136 | 135 | DEFINE_BITFIELD_ENUM(OperationParameter, 18, 18), |
| 137 | 136 | DEFINE_BITFIELD_ENUM(OperationExtend, 19, 19), |
| 138 | 137 | DEFINE_BITFIELD_ENUM(BytesUsed, 20, 21), |
| 139 | | DEFINE_BITFIELD_ENUM(Endianness, 22, 22), |
| 138 | DEFINE_BITFIELD_ENUM(EndiannessOld, 22, 22), |
| 140 | 139 | DEFINE_BITFIELD_ENUM(RestorePreviousValue, 23, 23), |
| 141 | 140 | DEFINE_BITFIELD_ENUM(LocationParameter, 24, 28), |
| 142 | 141 | DEFINE_BITFIELD_ENUM(LocationType, 29, 31), |
| r2821 | r2822 | |
| 147 | 146 | |
| 148 | 147 | /* command */ |
| 149 | 148 | DEFINE_BITFIELD_ENUM(SearchBox, 0, 1), |
| 150 | | DEFINE_BITFIELD_ENUM(DontPrintNewLabels, 2, 2), // in options menu, it is reversed display |
| 149 | DEFINE_BITFIELD_ENUM(DontPrintNewLabels, 2, 2), /* in options menu, it is reversed display */ |
| 151 | 150 | DEFINE_BITFIELD_ENUM(AutoSaveEnabled, 3, 3), |
| 152 | 151 | DEFINE_BITFIELD_ENUM(ActivationKeyMessage, 4, 4), |
| 153 | 152 | DEFINE_BITFIELD_ENUM(LoadOldFormat, 5, 5), |
| r2821 | r2822 | |
| 172 | 171 | kCodeType_IWrite, // EF = Index |
| 173 | 172 | kCodeType_RWrite, // EF = Count/Skip |
| 174 | 173 | kCodeType_CWrite, // EF = Condition |
| 175 | | kCodeType_VWrite, // EF = Index |
| 176 | | kCodeType_VRWrite, // EF = Count/Skip |
| 174 | kCodeType_CBit, // EF = Condition |
| 177 | 175 | kCodeType_PDWWrite, // EF = 2nd Data |
| 178 | | kCodeType_Move, // EF = Index |
| 179 | | kCodeType_Branch, // EF = Jump Code |
| 180 | | kCodeType_Loop, // EF = Index |
| 181 | | kCodeType_Unused1, |
| 182 | | kCodeType_Unused2, |
| 183 | | kCodeType_Unused3, |
| 184 | | kCodeType_Unused4, |
| 185 | | kCodeType_Popup, // EF = Index |
| 186 | | kCodeType_Watch }; // EF = X and Y Position |
| 176 | kCodeType_Move, // DF = Add Value, EF = Destination |
| 177 | kCodeType_Branch, // DF = Jump Code, EF = Condition |
| 178 | kCodeType_Loop, |
| 179 | kCodeType_Popup, // EF = Condition |
| 180 | kCodeType_Watch, // EF = position |
| 181 | kCodeType_Unused }; |
| 187 | 182 | |
| 188 | | enum{ // parameter for IWrite |
| 189 | | kIWrite_Write = 0, |
| 190 | | kIWrite_BitSet, |
| 191 | | kIWrite_BitClear, |
| 192 | | kIWrite_LimitedMask }; |
| 183 | enum{ /* parameter for IWrite */ |
| 184 | IWRITE_WRITE = 0, |
| 185 | IWRITE_BIT_SET, |
| 186 | IWRITE_BIT_CLEAR, |
| 187 | IWRITE_LIMITED_MASK }; |
| 193 | 188 | |
| 194 | | enum{ // conditions for CWrite, Branch, Popup |
| 189 | enum{ /* parameter for CBit */ |
| 190 | CBIT_BIT_SET = 0, |
| 191 | CBIT_BIT_CLEAR, |
| 192 | CBIT_LIMITED_MASK }; |
| 193 | |
| 194 | enum{ /* conditions for CWrite, Branch, Popup */ |
| 195 | 195 | kCondition_Equal = 0, |
| 196 | 196 | kCondition_NotEqual, |
| 197 | 197 | kCondition_Less, |
| r2821 | r2822 | |
| 209 | 209 | kCondition_KeyPressedRepeat, |
| 210 | 210 | kCondition_True }; |
| 211 | 211 | |
| 212 | enum{ /* conditions for CBit */ |
| 213 | CONDITION_CBIT_BIT_SET = 0, |
| 214 | CONDITION_CBIT_BIT_CLEAR }; |
| 215 | |
| 212 | 216 | enum{ // popup parameter |
| 213 | 217 | kPopup_Label = 0, |
| 214 | 218 | kPopup_Value, |
| 215 | 219 | kPopup_LabelValue, |
| 216 | 220 | kPopup_ValueLabel }; |
| 217 | 221 | |
| 218 | | enum{ // parameter for custom |
| 219 | | kCustomCode_NoAction = 0, |
| 220 | | kCustomCode_Comment, |
| 221 | | kCustomCode_Separator, |
| 222 | | kCustomCode_LabelSelect, |
| 223 | | kCustomCode_Layer, |
| 224 | | kCustomCode_Unused1, |
| 225 | | kCustomCode_Unused2, |
| 226 | | kCustomCode_Unused3, |
| 227 | | kCustomCode_ActivationKey1, |
| 228 | | kCustomCode_ActivationKey2, |
| 229 | | kCustomCode_PreEnable, |
| 230 | | kCustomCode_OverClock, |
| 231 | | kCustomCode_RefreshRate }; |
| 222 | enum{ /* custom code */ |
| 223 | CUSTOM_CODE = 0xF0, |
| 224 | CUSTOM_CODE_COMMENT, |
| 225 | CUSTOM_CODE_SEPARATOR, |
| 226 | CUSTOM_CODE_LABEL_SELECT, |
| 227 | CUSTOM_CODE_LAYER_TAG, |
| 228 | CUSTOM_CODE_UNUSED_1, |
| 229 | CUSTOM_CODE_UNUSED_2, |
| 230 | CUSTOM_CODE_UNUSED_3, |
| 231 | CUSTOM_CODE_ACTIVATION_KEY_1, |
| 232 | CUSTOM_CODE_ACTIVATION_KEY_2, |
| 233 | CUSTOM_CODE_PRE_ENABLE, |
| 234 | CUSTOM_CODE_OVER_CLOCK, |
| 235 | CUSTOM_CODE_REFRESH_RATE }; |
| 232 | 236 | |
| 233 | 237 | enum{ // link level |
| 234 | 238 | kLink_Master = 0, |
| 235 | 239 | kLink_Link, |
| 236 | | kLink_SubLink, |
| 237 | | kLink_CopyLink }; |
| 240 | kLink_SubLink }; |
| 238 | 241 | |
| 239 | 242 | enum{ // address read from |
| 240 | 243 | kReadFrom_Address = 0, // $xxxx |
| r2821 | r2822 | |
| 314 | 317 | /* set for one shot cheats after the operation is performed */ |
| 315 | 318 | kActionFlag_OperationDone = 1 << 3, |
| 316 | 319 | |
| 317 | | /* set if the extendData field is being used by index adress reading (IWrite, VWrite, Move, Loop, Popup)*/ |
| 320 | /* set if the extend data field is being used by index adress reading (IWrite, Move) */ |
| 318 | 321 | kActionFlag_IndexAddress = 1 << 4, |
| 319 | 322 | |
| 320 | | /* set if the code needs to check the condition (CWrite, Branch, Popup) */ |
| 321 | | kActionFlag_CheckCondition = 1 << 5, |
| 323 | /* set if the code uses limited mask which divids data field to 16-bit data and 16-bit mask (IWrite, CBit) */ |
| 324 | kActionFlag_LimitedMask = 1 << 5, |
| 322 | 325 | |
| 323 | | /* set if the code needs to repeat writing (RWrite, VRWrite) */ |
| 324 | | kActionFlag_Repeat = 1 << 6, |
| 326 | /* set if the code needs to check the condition (CWrite, CBit, Branch, Popup) */ |
| 327 | kActionFlag_CheckCondition = 1 << 6, |
| 325 | 328 | |
| 329 | /* set if the code needs to repeat writing (RWrite) */ |
| 330 | kActionFlag_Repeat = 1 << 7, |
| 331 | |
| 326 | 332 | /* set if the extendData field is being used by 2nd data (PDWWrite) */ |
| 327 | | kActionFlag_PDWWrite = 1 << 7, |
| 333 | kActionFlag_PDWWrite = 1 << 8, |
| 328 | 334 | |
| 329 | 335 | /* set if the lastValue field contains valid data and can be restored if needed */ |
| 330 | | kActionFlag_LastValueGood = 1 << 8, |
| 336 | kActionFlag_LastValueGood = 1 << 9, |
| 331 | 337 | |
| 332 | 338 | /* set after value changes from prefill value */ |
| 333 | | kActionFlag_PrefillDone = 1 << 9, |
| 339 | kActionFlag_PrefillDone = 1 << 10, |
| 334 | 340 | |
| 335 | 341 | /* set after prefill value written */ |
| 336 | | kActionFlag_PrefillWritten = 1 << 10, |
| 342 | kActionFlag_PrefillWritten = 1 << 11, |
| 337 | 343 | |
| 338 | 344 | /* set if the code is a label for label-selection code */ |
| 339 | | kActionFlag_IsLabel = 1 << 11, |
| 345 | kActionFlag_IsLabel = 1 << 12, |
| 340 | 346 | |
| 341 | 347 | /* set when read/write a data after 1st read/write and clear after 2nd read/write (PDWWrite) */ |
| 342 | | kActionFlag_IsFirst = 1 << 12, |
| 348 | kActionFlag_IsFirst = 1 << 13, |
| 343 | 349 | |
| 344 | 350 | /* masks */ |
| 345 | | kActionFlag_StateMask = kActionFlag_OperationDone | // used in ResetAction() to clear specified flags |
| 351 | kActionFlag_StateMask = kActionFlag_OperationDone | /* used in ResetAction() to clear specified flags */ |
| 346 | 352 | kActionFlag_LastValueGood | |
| 347 | 353 | kActionFlag_PrefillDone | |
| 348 | 354 | kActionFlag_PrefillWritten, |
| 349 | | kActionFlag_InfoMask = kActionFlag_IndexAddress, // ??? unused ??? |
| 350 | | kActionFlag_PersistentMask = kActionFlag_OldFormat | // used in UpdateCheatInfo() to clear other flags |
| 355 | kActionFlag_InfoMask = kActionFlag_IndexAddress, /* ??? unused ??? */ |
| 356 | kActionFlag_PersistentMask = kActionFlag_OldFormat | /* used in update_cheat_info() to clear other flags */ |
| 351 | 357 | kActionFlag_LastValueGood |
| 352 | 358 | }; |
| 353 | 359 | |
| r2821 | r2822 | |
| 380 | 386 | /* true if selected code is layer index cheat */ |
| 381 | 387 | kCheatFlag_LayerSelected = 1 << 8, |
| 382 | 388 | |
| 389 | /* true if selected code requests left/right arrow for sub item */ |
| 390 | kCheatFlag_RequestArrow = 1 << 9, |
| 391 | |
| 383 | 392 | /* true if the cheat has been assigned an 1st activation key */ |
| 384 | | kCheatFlag_HasActivationKey1 = 1 << 9, |
| 393 | kCheatFlag_HasActivationKey1 = 1 << 10, |
| 385 | 394 | |
| 386 | 395 | /* true if the cheat has been assigned an 2nd activation key */ |
| 387 | | kCheatFlag_HasActivationKey2 = 1 << 10, |
| 396 | kCheatFlag_HasActivationKey2 = 1 << 11, |
| 388 | 397 | |
| 389 | 398 | /* true if the cheat is not the newest format */ |
| 390 | | kCheatFlag_OldFormat = 1 << 11, |
| 399 | kCheatFlag_OldFormat = 1 << 12, |
| 391 | 400 | |
| 392 | 401 | /* true if wrong cheat code */ |
| 393 | | kCheatFlag_HasWrongCode = 1 << 12, |
| 402 | kCheatFlag_HasWrongCode = 1 << 13, |
| 394 | 403 | |
| 395 | 404 | /* true if the cheat has been edited or is a new cheat |
| 396 | 405 | checked at auto-save then save the code if true */ |
| 397 | | kCheatFlag_Dirty = 1 << 13, |
| 406 | kCheatFlag_Dirty = 1 << 14, |
| 398 | 407 | |
| 399 | 408 | /* masks */ |
| 400 | 409 | kCheatFlag_StateMask = kCheatFlag_Active, // used in ResetAction() and DeactivateCheat() to clear specified flag |
| 401 | | kCheatFlag_InfoMask = kCheatFlag_OneShot | // used in UpdateCheatInfo() to detect specified flags |
| 410 | kCheatFlag_InfoMask = kCheatFlag_OneShot | // used in update_cheat_info() to detect specified flags |
| 402 | 411 | kCheatFlag_Null | |
| 403 | 412 | kCheatFlag_ExtendComment | |
| 404 | 413 | kCheatFlag_Separator | |
| r2821 | r2822 | |
| 406 | 415 | kCheatFlag_Select | |
| 407 | 416 | kCheatFlag_LayerIndex | |
| 408 | 417 | kCheatFlag_OldFormat, |
| 409 | | kCheatFlag_PersistentMask = kCheatFlag_Active | // used in UpdateCheatInfo() to extract specified flags |
| 418 | kCheatFlag_PersistentMask = kCheatFlag_Active | // used in update_cheat_info() to extract specified flags |
| 410 | 419 | kCheatFlag_HasActivationKey1 | |
| 411 | 420 | kCheatFlag_HasActivationKey2 | |
| 412 | 421 | kCheatFlag_Dirty |
| r2821 | r2822 | |
| 433 | 442 | kWatchDisplayType_MaxPlusOne |
| 434 | 443 | }; |
| 435 | 444 | |
| 436 | | /********** REGION **********/ |
| 445 | /********** SEARCH REGION **********/ |
| 437 | 446 | |
| 438 | 447 | enum // flags |
| 439 | 448 | { |
| 440 | 449 | /* true if enabled for search */ |
| 441 | | kRegionFlag_Enabled = 1 << 0 |
| 450 | kRegionFlag_Enabled = 1 << 0, |
| 442 | 451 | |
| 452 | /* true if this region has an error */ |
| 453 | kRegionFlag_HasError = 1 << 1, |
| 454 | |
| 443 | 455 | /* true if the memory region has no mapped memory and uses a memory handler (unused?) */ |
| 444 | | // kRegionFlag_UsesHandler = 1 << 1 |
| 456 | /* kRegionFlag_UsesHandler = */ |
| 445 | 457 | }; |
| 446 | 458 | |
| 447 | 459 | enum // types |
| r2821 | r2822 | |
| 450 | 462 | kRegionType_Memory |
| 451 | 463 | }; |
| 452 | 464 | |
| 453 | | enum // default search regions |
| 465 | enum /* search speed */ |
| 454 | 466 | { |
| 455 | | ksearch_speed_Fast = 0, // RAM + some banks |
| 456 | | ksearch_speed_Medium, // RAM + BANKx |
| 457 | | ksearch_speed_Slow, // all memory areas except ROM, NOP, and custom handlers |
| 458 | | ksearch_speed_VerySlow, // all memory areas except ROM and NOP |
| 459 | | ksearch_speed_AllMemory, // entire CPU address space |
| 460 | | ksearch_speed_UserDefined, // user defined region |
| 467 | SEARCH_SPEED_FAST = 0, /* RAM + some banks */ |
| 468 | SEARCH_SPEED_MEDIUM, /* RAM + BANKx */ |
| 469 | SEARCH_SPEED_SLOW, /* all memory areas except ROM, NOP, and custom handlers */ |
| 470 | SEARCH_SPEED_VERY_SLOW, /* all memory areas except ROM and NOP */ |
| 471 | SEARCH_SPEED_ALL_MEMORY, /* entire CPU address space */ |
| 472 | SEARCH_SPEED_USER_DEFINED, /* user defined region */ |
| 461 | 473 | |
| 462 | | ksearch_speed_Max |
| 474 | SEARCH_SPEED_MAX |
| 463 | 475 | }; |
| 464 | 476 | |
| 465 | | /********** SEARCH **********/ |
| 477 | /********** SEARCH INFO **********/ |
| 466 | 478 | |
| 467 | 479 | enum // operands |
| 468 | 480 | { |
| r2821 | r2822 | |
| 515 | 527 | kSearchBox_Advanced |
| 516 | 528 | }; |
| 517 | 529 | |
| 530 | enum /* format level */ |
| 531 | { |
| 532 | FORMAT_NEW = 1, |
| 533 | FORMAT_STANDARD, |
| 534 | FORMAT_OLD |
| 535 | }; |
| 536 | |
| 537 | enum /* disposition for resizing a list */ |
| 538 | { |
| 539 | REQUEST_DISPOSE = 0, |
| 540 | NO_DISPOSE, |
| 541 | }; |
| 542 | |
| 518 | 543 | enum // load flags |
| 519 | 544 | { |
| 520 | 545 | kLoadFlag_CheatOption = 1, |
| r2821 | r2822 | |
| 546 | 571 | kCheatMessage_NoOldValue, |
| 547 | 572 | kCheatMessage_InitializeMemory, |
| 548 | 573 | kCheatMessage_InvalidatedRegion, |
| 549 | | kCheatMessage_DebugOnly, |
| 574 | kCheatMessage_FailedToAllocate, |
| 550 | 575 | kCheatMessage_WrongCode, |
| 551 | 576 | |
| 552 | 577 | kCheatMessage_Max |
| r2821 | r2822 | |
| 563 | 588 | kErrorFlag_NoRestorePreviousValue = 1 << 7, |
| 564 | 589 | kErrorFlag_NoLabel = 1 << 8, |
| 565 | 590 | kErrorFlag_ConflictedSelects = 1 << 9, |
| 566 | | kErrorFlag_CopyLinkWithoutSelect = 1 << 10, // new |
| 567 | | kErrorFlag_InvalidDataField = 1 << 11, |
| 568 | | kErrorFlag_InvalidExtendDataField = 1 << 12, |
| 569 | | kErrorFlag_ForbittenVariable = 1 << 13, // new |
| 570 | | kErrorFlag_NoSelectableValue = 1 << 14, |
| 591 | kErrorFlag_InvalidDataField = 1 << 10, |
| 592 | kErrorFlag_InvalidExtendDataField = 1 << 11, |
| 593 | kErrorFlag_ForbittenVariable = 1 << 12, // new |
| 594 | kErrorFlag_NoSelectableValue = 1 << 13, |
| 595 | kErrorFlag_InvalidLimitedMaskSize = 1 << 14, // new |
| 571 | 596 | kErrorFlag_NoRepeatCount = 1 << 15, // new |
| 572 | 597 | kErrorFlag_UndefinedAddressRead = 1 << 16, // new |
| 573 | 598 | kErrorFlag_AddressVariableOutRange = 1 << 17, // new |
| r2821 | r2822 | |
| 586 | 611 | |
| 587 | 612 | /********** ACTION **********/ |
| 588 | 613 | |
| 589 | | struct CheatAction |
| 614 | typedef struct _cheat_action cheat_action; |
| 615 | struct _cheat_action |
| 590 | 616 | { |
| 591 | | UINT32 type; // packed several information (cpu/region, address size, operation and parameters and so on) |
| 592 | | UINT8 region; // the number of cpu or region. in case of cpu, it has a kind of an address space together |
| 593 | | UINT32 address; // address. it is changeable by RWrite in the cheat core |
| 594 | | UINT32 originalAddress; // address. it is for edit/view/save |
| 595 | | UINT32 data; // data. it is changeable by VWrite/VRWrite in the cheat core |
| 596 | | UINT32 originalDataField; // data. it is for edit/view/save |
| 597 | | UINT32 extendData; // extend parameter. it is different using by each operations |
| 617 | UINT32 type; /* packed several information (cpu/region, address size, operation and parameters and so on) */ |
| 618 | UINT8 region; /* the number of cpu or region. in case of cpu, it has a kind of an address space together */ |
| 619 | UINT32 address; /* address. it is changeable by RWrite in the cheat core */ |
| 620 | UINT32 original_address; /* address. it is for edit/view/save */ |
| 621 | UINT32 data; /* data. it is changeable by valuse selector in the cheat core */ |
| 622 | UINT32 original_data; /* data. it is for edit/view/save */ |
| 623 | UINT32 extend_data; /* extend parameter. it is different using by each operations */ |
| 598 | 624 | |
| 599 | | INT32 frameTimer; // timer for delay, keep |
| 600 | | UINT32 * lastValue; // back up value before cheating to restore value. PDWWrite uses 2 and RWrite uses about a counter |
| 625 | INT32 frame_timer; /* timer for delay/keep */ |
| 626 | UINT32 *last_value; /* back up value before cheating to restore value. PDWWrite uses 2 and RWrite uses about a counter */ |
| 601 | 627 | |
| 602 | | UINT32 flags; // internal flags |
| 628 | UINT32 flags; /* internal flags */ |
| 603 | 629 | |
| 604 | | UINT8 ** cachedPointer; // pointer for data, I/O space or non-cpu region |
| 605 | | UINT32 cachedOffset; // offset for mapped memory |
| 630 | UINT8 **cached_pointer; /* pointer to specified address space or mapped memory */ |
| 631 | UINT32 cached_offset; /* offset for mapped memory */ |
| 606 | 632 | |
| 607 | | char * optionalName; // name to display in edit/view menu. Action doesn't have a comment |
| 633 | char *optional_name; /* label for label selection or popup */ |
| 608 | 634 | }; |
| 609 | 635 | |
| 610 | | typedef struct CheatAction CheatAction; |
| 611 | | |
| 612 | 636 | /********** ENTRY **********/ |
| 613 | 637 | |
| 614 | | struct CheatEntry |
| 638 | typedef struct _cheat_entry cheat_entry; |
| 639 | struct _cheat_entry |
| 615 | 640 | { |
| 616 | | char * name; // name to display in list menu |
| 617 | | char * comment; // comment |
| 641 | char *name; /* name to display in list menu */ |
| 642 | char *comment; /* simple comment */ |
| 618 | 643 | |
| 619 | | INT32 actionListLength; // minimum length = 1 |
| 620 | | CheatAction * actionList; |
| 644 | INT32 action_list_length; /* total codes of cheat action. NOTE : minimum length is 1 and 0 is ERROR */ |
| 645 | cheat_action *action_list; /* pointer to cheat action */ |
| 621 | 646 | |
| 622 | | int activationKey1; // activation key index for 1st key |
| 623 | | int activationKey2; // activation key index for 2nd key |
| 647 | int activation_key1; /* activation key index for 1st key */ |
| 648 | int activation_key2; /* activation key index for 2nd key */ |
| 624 | 649 | |
| 625 | | int selection; // for label-select to set selected label number |
| 626 | | int labelIndexLength; // minimum length = 1 |
| 627 | | int * labelIndex; // label index table |
| 628 | | int layerIndex; // layer index for enable/disable menu |
| 650 | int selection; /* for label-select to set selected label number */ |
| 651 | int label_index_length; /* total tables of index table. NOTE : minimum length is 1 and 0 is ERROR */ |
| 652 | int *label_index; /* pointer of label index table */ |
| 629 | 653 | |
| 630 | | UINT32 flags; // internal flags |
| 654 | int layer_index; /* layer index for enable/disable menu */ |
| 655 | UINT32 flags; /* internal flags */ |
| 631 | 656 | }; |
| 632 | 657 | |
| 633 | | typedef struct CheatEntry CheatEntry; |
| 634 | | |
| 635 | 658 | /********** WATCH **********/ |
| 636 | 659 | |
| 637 | | struct WatchInfo |
| 660 | typedef struct _watch_info watch_info; |
| 661 | struct _watch_info |
| 638 | 662 | { |
| 639 | | UINT32 address; |
| 640 | | UINT8 cpu; |
| 641 | | UINT8 numElements; |
| 642 | | UINT8 elementBytes; |
| 643 | | UINT8 labelType; |
| 644 | | UINT8 displayType; |
| 645 | | UINT8 skip; |
| 646 | | UINT8 elementsPerLine; |
| 647 | | INT8 addValue; |
| 648 | | INT8 addressShift; |
| 649 | | INT8 dataShift; |
| 650 | | UINT32 xor; |
| 663 | UINT32 address; /* address */ |
| 664 | UINT8 cpu; /* target cpu or region */ |
| 665 | UINT8 num_elements; /* length of this watchpoint */ |
| 666 | UINT8 element_bytes; /* address size of this watchpoint */ |
| 667 | UINT8 label_type; /* header label */ |
| 668 | UINT8 display_type; /* type of value display */ |
| 669 | UINT8 skip; /* address skip */ |
| 670 | UINT8 elements_per_line; /* max watchpoints in the same line */ |
| 671 | INT8 add_value; /* add value */ |
| 672 | INT8 address_shift; /* address shift */ |
| 673 | INT8 data_shift; /* data shift */ |
| 674 | UINT32 xor; /* xor */ |
| 651 | 675 | |
| 652 | | float x, y; |
| 676 | float x, y; /* position */ |
| 653 | 677 | |
| 654 | | CheatEntry * linkedCheat; |
| 678 | cheat_entry *linked_cheat; /* relative cheat_entry */ |
| 655 | 679 | |
| 656 | | char label[256]; |
| 680 | char label[256]; /* name of label */ |
| 657 | 681 | }; |
| 658 | 682 | |
| 659 | | typedef struct WatchInfo WatchInfo; |
| 660 | | |
| 661 | 683 | /********** REGION **********/ |
| 662 | 684 | |
| 663 | 685 | typedef struct _search_region search_region; |
| 664 | 686 | struct _search_region |
| 665 | 687 | { |
| 666 | | UINT32 address; |
| 667 | | UINT32 length; |
| 688 | UINT32 address; /* address */ |
| 689 | UINT32 length; /* total length */ |
| 668 | 690 | |
| 669 | | UINT8 target_type; |
| 670 | | UINT8 target_idx; |
| 691 | UINT8 target_type; /* flag for cpu or region */ |
| 692 | UINT8 target_idx; /* target cpu/region */ |
| 671 | 693 | |
| 672 | | UINT8 flags; |
| 694 | UINT8 flags; /* internal flags */ |
| 673 | 695 | |
| 674 | | UINT8 ** cached_pointer; |
| 696 | UINT8 **cached_pointer; /* pointer to except standard cpu region */ |
| 675 | 697 | const address_map_entry |
| 676 | | * write_handler; |
| 698 | *write_handler; /* pointer to write handler from address map */ |
| 677 | 699 | |
| 678 | | UINT8 * first; |
| 679 | | UINT8 * last; |
| 700 | UINT8 *first; /* first value in searching */ |
| 701 | UINT8 *last; /* current value in searching */ |
| 680 | 702 | |
| 681 | | UINT8 * status; |
| 703 | UINT8 *status; |
| 682 | 704 | |
| 683 | | UINT8 * backup_last; |
| 684 | | UINT8 * backup_status; |
| 705 | UINT8 *backup_last; /* previous value in searching */ |
| 706 | UINT8 *backup_status; /* flag of backup */ |
| 685 | 707 | |
| 686 | | char name[64]; |
| 708 | char name[64]; /* name of this region. NOTE : used in advanced search only */ |
| 687 | 709 | |
| 688 | | UINT32 num_results; |
| 689 | | UINT32 old_num_results; |
| 710 | UINT32 num_results; /* total results */ |
| 711 | UINT32 old_num_results; /* previous total results */ |
| 690 | 712 | }; |
| 691 | 713 | |
| 692 | 714 | /********** SEARCH **********/ |
| r2821 | r2822 | |
| 773 | 795 | typedef struct _cheat_menu_item_info cheat_menu_item_info; |
| 774 | 796 | struct _cheat_menu_item_info |
| 775 | 797 | { |
| 776 | | UINT32 sub_cheat; /* the number of an item */ |
| 798 | UINT32 sub_cheat; /* index of an item */ |
| 777 | 799 | UINT32 field_type; /* field type of an item */ |
| 778 | 800 | UINT32 extra_data; /* it stores an extra data but NOT read (so I don't know how to use)*/ |
| 779 | 801 | }; |
| r2821 | r2822 | |
| 793 | 815 | typedef const struct _cheat_format cheat_format; |
| 794 | 816 | struct _cheat_format |
| 795 | 817 | { |
| 796 | | const char * format_string; /* string templete of a format */ |
| 818 | const char *format_string; /* string templete of a format */ |
| 797 | 819 | UINT8 arguments_matched; /* valid arguments of a format */ |
| 798 | | UINT8 length_matched; /* valid length of a parameter */ |
| 799 | | UINT8 comment_matched; /* valid argument to add comment */ |
| 820 | UINT8 type_matched; /* valid length of a type field */ |
| 821 | UINT8 data_matched; /* valid length of a data/extend data field */ |
| 822 | UINT8 comment_matched; /* valid arguments to add comment */ |
| 800 | 823 | }; |
| 801 | 824 | |
| 802 | 825 | static const struct _cheat_format cheat_format_table[] = |
| 803 | 826 | { |
| 804 | 827 | /* option - :_command:TYPE */ |
| 805 | | { ":_command:%[^:\n\r]", 1, 8, 0 }, |
| 828 | { ":_command:%[^:\n\r]", 1, 8, 0, 0 }, |
| 806 | 829 | #ifdef MESS |
| 807 | | /* code (new) - >MACHINE_NAME:CRC:TYPE:ADDRESS:DATA:EXTEND_DATA:(DESCRIPTION:COMMENT) */ |
| 808 | | { ">%8[^:\n\r]:%8X:%8X:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 6, 8, 8 }, |
| 830 | /* code (new) - :MACHINE_NAME::CRC::TYPE::ADDRESS::DATA::EXTEND_DATA:(DESCRIPTION:COMMENT) */ |
| 831 | { ":%8[^:\n\r]::%8X::%10[^:\n\r]::%X::%8[^:\n\r]::%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 6, 10, 8, 8 }, |
| 809 | 832 | /* code (old) - :MACHINE_NAME:CRC:TYPE:ADDRESS:DATA:EXTEND_DATA:(DESCRIPTION:COMMENT) */ |
| 810 | | { ":%8s:%8X:%8X:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 6, 8, 0 }, |
| 833 | { ":%8s:8X:%8[^:\n\r]:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 6, 8, 8, 0 }, |
| 811 | 834 | /* code (older) - :MACHINE_NAME:CRC:CPU:ADDRESS:DATA:TYPE:(DESCRIPTION:COMMENT) */ |
| 812 | | { "%8[^:\n\r]:%8X:%d:%X:%X:%d:%[^:\n\r]:%[^:\n\r]", 5, 0, 8 }, |
| 835 | { "%8[^:\n\r]:%8X:%d:%X:%X:%d:%[^:\n\r]:%[^:\n\r]", 5, 0, 0, 8 }, |
| 813 | 836 | /* user region - :MACHINE_NAME:CRC:CPU:ADDRESS_SPACE:START_ADDRESS:END_ADDRESS:STATUS:(DESCRIPTION) */ |
| 814 | | { ">%8[^:\n\r]:%8X:%2X:%2X:%X:%X:%1X:%[^:\n\r]", 7, 0, 0 }, |
| 837 | { ":%8[^:\n\r]:%8X:%2X:%2X:%X:%X:%1X:%[^:\n\r]", 7, 0, 0, 0 }, |
| 815 | 838 | #else |
| 816 | | /* code (new) - >GAME_NAME:TYPE:ADDRESS:DATA:EXTEND_DATA:(DESCRIPTION:COMMENT) */ |
| 817 | | { ">%8[^:\n\r]:%8X:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 5, 8, 7 }, |
| 839 | /* code (new) - :GAME_NAME::TYPE::ADDRESS::DATA::EXTEND_DATA:(DESCRIPTION:COMMENT) */ |
| 840 | { ":%8[^:\n\r]::%10[^:\n\r]::%X::%8[^:\n\r]::%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 5, 10, 8, 7 }, |
| 818 | 841 | /* code (old) - :GAME_NAME:TYPE:ADDRESS:DATA:EXTEND_DATA:(DESCRIPTION:COMMENT) */ |
| 819 | | { ":%8s:%8X:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 5, 8, 0 }, |
| 842 | { ":%8s:%8[^:\n\r]:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 5, 8, 8, 0 }, |
| 820 | 843 | /* code (older) - :GAME_NAME:CPU:ADDRESS:DATA:TYPE:(DESCRIPTION:COMMENT) */ |
| 821 | | { "%8[^:\n\r]:%d:%X:%X:%d:%[^:\n\r]:%[^:\n\r]", 4, 0, 7 }, |
| 844 | { "%8[^:\n\r]:%d:%X:%X:%d:%[^:\n\r]:%[^:\n\r]", 4, 0, 0, 7 }, |
| 822 | 845 | /* user region - :GAME_NAME:CPU:ADDRESS_SPACE:START_ADDRESS:END_ADDRESS:STATUS:(DESCRIPTION) */ |
| 823 | | { ">%8[^:\n\r]:%2X:%2X:%X:%X:%1X:%[^:\n\r]", 6, 0, 0 }, |
| 846 | { ":%8[^:\n\r]:%2X:%2X:%X:%X:%1X:%[^:\n\r]", 6, 0, 0, 0 }, |
| 824 | 847 | #endif /* MESS */ |
| 825 | 848 | /* end of table */ |
| 826 | 849 | { 0 } |
| r2821 | r2822 | |
| 830 | 853 | EXPORTED VARIABLES |
| 831 | 854 | ***************************************************************************/ |
| 832 | 855 | |
| 833 | | static const char * cheatfile = NULL; |
| 856 | static const char *cheat_file = NULL; |
| 834 | 857 | |
| 835 | 858 | /*************************************************************************** |
| 836 | 859 | GLOBAL VARIABLES |
| 837 | 860 | ***************************************************************************/ |
| 838 | 861 | |
| 839 | | static emu_timer * periodic_timer; |
| 862 | static emu_timer *periodic_timer; |
| 840 | 863 | |
| 841 | | static CheatEntry * cheatList = NULL; |
| 842 | | static INT32 cheatListLength = 0; // NOTE : 0 means no cheat entry and error |
| 864 | static cheat_entry *cheat_list; |
| 865 | static INT32 cheat_list_length; |
| 843 | 866 | |
| 844 | | static WatchInfo * watchList = NULL; |
| 845 | | static INT32 watchListLength = 0; |
| 867 | static watch_info *watch_list; |
| 868 | static INT32 watch_list_length; |
| 846 | 869 | |
| 847 | | static search_info *search_list = NULL; |
| 848 | | static INT32 search_list_length = 0; |
| 849 | | static INT32 current_search_idx = 0; |
| 870 | static search_info *search_list; |
| 871 | static INT32 search_list_length; |
| 872 | static INT32 current_search_idx; |
| 850 | 873 | |
| 851 | 874 | static cpu_region_info cpu_info_list[MAX_CPU]; |
| 852 | 875 | static cpu_region_info region_info_list[REGION_LIST_LENGTH]; |
| 853 | 876 | |
| 854 | | static int foundCheatDatabase = 0; |
| 877 | static int found_database = 0; |
| 855 | 878 | static int cheatsDisabled = 0; |
| 856 | 879 | static int watchesDisabled = 0; |
| 857 | 880 | |
| 858 | 881 | static int fullMenuPageHeight; |
| 859 | 882 | static int visible_items; |
| 860 | 883 | |
| 861 | | static char mainDatabaseName[CHEAT_FILENAME_MAX_LEN + 1]; |
| 884 | static char main_database_name[CHEAT_FILENAME_MAX_LEN + 1]; |
| 862 | 885 | |
| 863 | 886 | static menu_string_list menu_strings; |
| 864 | 887 | |
| r2821 | r2822 | |
| 873 | 896 | |
| 874 | 897 | static int cheatVariable[VARIABLE_MAX_ARRAY] = { 0 }; |
| 875 | 898 | |
| 876 | | static UINT32 cheatOptions; |
| 899 | static UINT32 cheat_options; |
| 877 | 900 | static UINT32 driverSpecifiedFlag; |
| 878 | | static UINT8 messageType; |
| 879 | | static UINT8 messageTimer; |
| 901 | static UINT8 message_type; |
| 902 | static UINT8 message_timer; |
| 880 | 903 | |
| 881 | 904 | static cpu_region_info raw_cpu_info = |
| 882 | 905 | { |
| r2821 | r2822 | |
| 1165 | 1188 | #endif |
| 1166 | 1189 | |
| 1167 | 1190 | /********** ENTRY LIST **********/ |
| 1168 | | static void ResizeCheatList(UINT32 newLength); |
| 1169 | | static void ResizeCheatListNoDispose(UINT32 newLength); |
| 1191 | static void resize_cheat_list(UINT32 new_length, UINT8 dispose); |
| 1170 | 1192 | |
| 1171 | | static void AddCheatBefore(UINT32 idx); |
| 1172 | | static void DeleteCheatAt(UINT32 idx); |
| 1193 | static void add_cheat_before(UINT32 idx); |
| 1194 | static void delete_cheat_at(UINT32 idx); |
| 1173 | 1195 | |
| 1174 | | static void DisposeCheat(CheatEntry * entry); |
| 1175 | | static CheatEntry |
| 1176 | | *GetNewCheat(void); |
| 1196 | static void dispose_cheat(cheat_entry *entry); |
| 1197 | static cheat_entry |
| 1198 | *get_new_cheat(void); |
| 1177 | 1199 | |
| 1178 | 1200 | /********** ACTION LIST **********/ |
| 1179 | | static void ResizeCheatActionList(CheatEntry * entry, UINT32 newLength); |
| 1201 | static void resize_cheat_action_list(cheat_entry *entry, UINT32 new_length, UINT8 dispose); |
| 1180 | 1202 | #if 0 |
| 1181 | | static void ResizeCheatActionListNoDispose(CheatEntry * entry, UINT32 newLength); |
| 1182 | | |
| 1183 | 1203 | static void AddActionBefore(CheatEntry * entry, UINT32 idx); |
| 1184 | 1204 | static void DeleteActionAt(CheatEntry * entry, UINT32 idx); |
| 1185 | 1205 | #endif |
| 1186 | | static void DisposeAction(CheatAction * action); |
| 1206 | static void dispose_action(cheat_action *action); |
| 1187 | 1207 | |
| 1188 | 1208 | /********** WATCH LIST **********/ |
| 1189 | | static void InitWatch(WatchInfo * info, UINT32 idx); |
| 1190 | | static void ResizeWatchList(UINT32 newLength); |
| 1191 | | static void ResizeWatchListNoDispose(UINT32 newLength); |
| 1209 | static void init_watch(watch_info *info, UINT32 idx); |
| 1210 | static void resize_watch_list(UINT32 new_length, UINT8 dispose); |
| 1192 | 1211 | |
| 1193 | | static void AddWatchBefore(UINT32 idx); |
| 1194 | | static void DeleteWatchAt(UINT32 idx); |
| 1195 | | static void DisposeWatch(WatchInfo * watch); |
| 1196 | | static WatchInfo |
| 1197 | | *GetUnusedWatch(void); |
| 1212 | static void add_watch_before(UINT32 idx); |
| 1213 | static void delete_watch_at(UINT32 idx); |
| 1214 | static void dispose_watch(watch_info *watch); |
| 1198 | 1215 | |
| 1199 | | static void AddCheatFromWatch(WatchInfo * watch); |
| 1200 | | static void SetupCheatFromWatchAsWatch(CheatEntry * entry, WatchInfo * watch); |
| 1216 | static watch_info |
| 1217 | *get_unused_watch(void); |
| 1201 | 1218 | |
| 1202 | | static void ResetWatch(WatchInfo * watch); |
| 1219 | static void add_cheat_from_watch(watch_info *watch); |
| 1220 | static void add_cheat_from_watch_as_watch(cheat_entry *entry, watch_info *watch); |
| 1203 | 1221 | |
| 1222 | static void reset_watch(watch_info *watch); |
| 1223 | |
| 1204 | 1224 | /********** SEARCH LIST **********/ |
| 1205 | 1225 | static void resize_search_list(UINT32 newLength); |
| 1206 | 1226 | #if 0 |
| r2821 | r2822 | |
| 1224 | 1244 | static void restore_region_backup(search_region *region); |
| 1225 | 1245 | static UINT8 default_enable_region(running_machine *machine, search_region *region, search_info *info); |
| 1226 | 1246 | static void set_search_region_default_name(search_region *region); |
| 1247 | static UINT8 is_search_region_in_range(UINT8 cpu, UINT32 length); |
| 1227 | 1248 | static void allocate_search_regions(search_info *info); |
| 1228 | 1249 | static void build_search_regions(running_machine *machine, search_info *info); |
| 1229 | 1250 | |
| 1230 | 1251 | /********** LOADER **********/ |
| 1231 | 1252 | static int ConvertOldCode(int code, int cpu, int * data, int * extendData); |
| 1232 | | static int ConvertToNewCode(CheatAction * action); |
| 1233 | | static void HandleLocalCommandCheat(running_machine *machine, int cpu, int type, int address, int data, UINT8 format); |
| 1253 | static int convert_to_new_code(cheat_action *action); |
| 1254 | static void handle_local_command_cheat(running_machine *machine, int cpu, int type, int address, int data, UINT8 format); |
| 1234 | 1255 | |
| 1235 | | static void LoadCheatOption(char * fileName); |
| 1236 | | static void LoadCheatCode(running_machine *machine, char * fileName); |
| 1237 | | static void LoadUserDefinedSearchRegion(running_machine *machine, char * fileName); |
| 1238 | | static void LoadCheatDatabase(running_machine *machine, UINT8 flags); |
| 1256 | static void load_cheat_option(char *file_name); |
| 1257 | static void load_cheat_code(running_machine *machine, char *file_name); |
| 1258 | static void load_user_defined_search_region(running_machine *machine, char *file_name); |
| 1259 | static void load_cheat_database(running_machine *machine, UINT8 flags); |
| 1260 | static void reload_cheat_database(running_machine *machine); |
| 1239 | 1261 | |
| 1240 | | static void DisposeCheatDatabase(void); |
| 1241 | | static void ReloadCheatDatabase(running_machine *machine); |
| 1262 | static void dispose_cheat_database(void); |
| 1242 | 1263 | |
| 1243 | 1264 | /********** SAVER **********/ |
| 1244 | | static void SaveCheatCode(running_machine *machine, CheatEntry * entry); |
| 1245 | | static void SaveActivationKey(running_machine *machine, CheatEntry * entry, int entryIndex); |
| 1246 | | static void SavePreEnable(running_machine *machine, CheatEntry * entry, int entryIndex); |
| 1247 | | static void SaveCheatOptions(void); |
| 1265 | static void SaveCheatCode(running_machine *machine, cheat_entry *entry); |
| 1266 | static void SaveActivationKey(running_machine *machine, cheat_entry *entry, int entryIndex); |
| 1267 | static void SavePreEnable(running_machine *machine, cheat_entry *entry, int entryIndex); |
| 1268 | static void Savecheat_options(void); |
| 1248 | 1269 | static void SaveDescription(running_machine *machine); |
| 1249 | 1270 | static void DoAutoSaveCheats(running_machine *machine); |
| 1250 | 1271 | |
| r2821 | r2822 | |
| 1283 | 1304 | static void DoCPUWrite(UINT32 data, UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap); |
| 1284 | 1305 | static void DoMemoryWrite(UINT32 data, UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, cpu_region_info *info); |
| 1285 | 1306 | |
| 1286 | | static UINT32 ReadData(CheatAction * action); |
| 1287 | | static void WriteData(CheatAction * action, UINT32 data); |
| 1307 | static UINT32 ReadData(cheat_action *action); |
| 1308 | static void WriteData(cheat_action *action, UINT32 data); |
| 1288 | 1309 | |
| 1289 | 1310 | /********** WATCH **********/ |
| 1290 | | static void WatchCheatEntry(CheatEntry * entry, UINT8 associate); |
| 1291 | | static void AddActionWatch(CheatAction * action, CheatEntry * entry); |
| 1292 | | static void RemoveAssociatedWatches(CheatEntry * entry); |
| 1311 | static void WatchCheatEntry(cheat_entry *entry, UINT8 associate); |
| 1312 | static void AddActionWatch(cheat_action *action, cheat_entry *entry); |
| 1313 | static void RemoveAssociatedWatches(cheat_entry *entry); |
| 1293 | 1314 | |
| 1294 | 1315 | /********** ACTIVE/DEACTIVE ENTRY **********/ |
| 1295 | | static void ResetAction(CheatAction * action); |
| 1296 | | static void ActivateCheat(CheatEntry * entry); |
| 1297 | | static void DeactivateCheat(CheatEntry * entry); |
| 1298 | | static void TempDeactivateCheat(CheatEntry * entry); |
| 1316 | static void ResetAction(cheat_action *action); |
| 1317 | static void ActivateCheat(cheat_entry *entry); |
| 1318 | static void DeactivateCheat(cheat_entry *entry); |
| 1319 | static void TempDeactivateCheat(cheat_entry *entry); |
| 1299 | 1320 | |
| 1300 | 1321 | /********** OPERATION CORE **********/ |
| 1301 | | static void cheat_periodicOperation(CheatAction * action); |
| 1302 | | static UINT8 cheat_periodicCondition(CheatAction * action); |
| 1303 | | static int cheat_periodicAction(running_machine *machine, CheatAction * action, int selection); |
| 1304 | | static void cheat_periodicEntry(running_machine *machine, CheatEntry * entry); |
| 1322 | static void cheat_periodicOperation(cheat_action *action); |
| 1323 | static UINT8 cheat_periodicCondition(cheat_action *action); |
| 1324 | static int cheat_periodicAction(running_machine *machine, cheat_action *action, int selection); |
| 1325 | static void cheat_periodicEntry(running_machine *machine, cheat_entry *entry); |
| 1305 | 1326 | |
| 1306 | 1327 | /********** CONFIGURE ENTRY **********/ |
| 1307 | | static void UpdateAllCheatInfo(void); |
| 1308 | | static void UpdateCheatInfo(CheatEntry * entry, UINT8 isLoadTime); |
| 1309 | | static UINT32 AnalyseCodeFormat(CheatEntry * entry, CheatAction * action); |
| 1310 | | static void CheckCodeFormat(CheatEntry * entry); |
| 1311 | | static void BuildLabelIndexTable(CheatEntry *entry); |
| 1328 | static void update_all_cheat_info(void); |
| 1329 | static void update_cheat_info(cheat_entry *entry, UINT8 is_load_time); |
| 1330 | static UINT32 AnalyseCodeFormat(cheat_entry *entry, cheat_action *action); |
| 1331 | static void check_code_format(cheat_entry *entry); |
| 1332 | static void BuildLabelIndexTable(cheat_entry *entry); |
| 1312 | 1333 | static void SetLayerIndex(void); |
| 1313 | 1334 | |
| 1314 | 1335 | /********** OTHER STUFF **********/ |
| 1315 | 1336 | static void DisplayCheatMessage(void); |
| 1316 | 1337 | static UINT8 get_address_length(UINT8 region); |
| 1317 | | static char * get_region_name(UINT8 region); |
| 1338 | static char *get_region_name(UINT8 region); |
| 1318 | 1339 | static void build_cpu_region_info_list(running_machine *machine); |
| 1319 | 1340 | |
| 1320 | 1341 | /*************************************************************************** |
| r2821 | r2822 | |
| 1351 | 1372 | |
| 1352 | 1373 | INLINE cpu_region_info *get_cpu_or_region_info(UINT8 cpu_region) |
| 1353 | 1374 | { |
| 1354 | | if(TEST_FIELD(cpu_region, RegionFlag)) |
| 1355 | | return get_region_info(cpu_region); |
| 1356 | | else |
| 1375 | if(cpu_region < REGION_INVALID) |
| 1357 | 1376 | return get_cpu_info(cpu_region); |
| 1377 | else |
| 1378 | return get_region_info(cpu_region); |
| 1358 | 1379 | } |
| 1359 | 1380 | |
| 1360 | 1381 | /*----------------- |
| r2821 | r2822 | |
| 1363 | 1384 | |
| 1364 | 1385 | INLINE UINT8 cpu_needs_swap(UINT8 cpu) |
| 1365 | 1386 | { |
| 1366 | | return cpu_info_list[cpu].endianness | 1; |
| 1387 | return cpu_info_list[cpu].endianness ^ 1; |
| 1367 | 1388 | } |
| 1368 | 1389 | |
| 1369 | 1390 | /*-------------------- |
| r2821 | r2822 | |
| 1375 | 1396 | cpu_region_info *temp = get_region_info(region); |
| 1376 | 1397 | |
| 1377 | 1398 | if(temp) |
| 1378 | | return temp->endianness | 1; |
| 1399 | return temp->endianness ^ 1; |
| 1379 | 1400 | |
| 1380 | 1401 | return 0; |
| 1381 | 1402 | } |
| r2821 | r2822 | |
| 1404 | 1425 | return address; |
| 1405 | 1426 | } |
| 1406 | 1427 | |
| 1407 | | /*------------------- |
| 1408 | | IsAddressInRange |
| 1409 | | -------------------*/ |
| 1428 | /*--------------------------------------------------------------------------------- |
| 1429 | is_address_in_range - check the range of address for eeprom and non-cpu region |
| 1430 | ---------------------------------------------------------------------------------*/ |
| 1410 | 1431 | |
| 1411 | | INLINE int IsAddressInRange(CheatAction * action, UINT32 length) |
| 1432 | INLINE int is_address_in_range(cheat_action *action, UINT32 length) |
| 1412 | 1433 | { |
| 1413 | 1434 | return ((action->address + EXTRACT_FIELD(action->type, AddressSize) + 1) <= length); |
| 1414 | 1435 | } |
| r2821 | r2822 | |
| 1452 | 1473 | ReadKeyAsync - dirty hack until osd_readkey_unicode is supported in MAMEW re-implementation of osd_readkey_unicode |
| 1453 | 1474 | ---------------------------------------------------------------------------------------------------------------------*/ |
| 1454 | 1475 | |
| 1455 | | #if 1 |
| 1456 | | |
| 1457 | 1476 | #if OSD_READKEY_KLUDGE |
| 1458 | 1477 | |
| 1459 | 1478 | static int ReadKeyAsync(int flush) |
| 1460 | 1479 | { |
| 1461 | 1480 | int code; |
| 1462 | 1481 | |
| 1463 | | if(flush) // check key input |
| 1482 | if(flush) |
| 1464 | 1483 | { |
| 1484 | /* check key input */ |
| 1465 | 1485 | while(input_code_poll_keyboard_switches(TRUE) != INPUT_CODE_INVALID) ; |
| 1466 | 1486 | |
| 1467 | 1487 | return 0; |
| 1468 | 1488 | } |
| 1469 | 1489 | |
| 1470 | | while(1) // check pressed key |
| 1490 | while(1) |
| 1471 | 1491 | { |
| 1492 | /* check pressed key */ |
| 1472 | 1493 | code = input_code_poll_keyboard_switches(FALSE); |
| 1473 | 1494 | |
| 1474 | 1495 | if(code == INPUT_CODE_INVALID) |
| 1475 | 1496 | { |
| 1476 | 1497 | return 0; |
| 1477 | 1498 | } |
| 1478 | | else if((code >= KEYCODE_A) && (code <= KEYCODE_Z)) |
| 1499 | else if(code >= KEYCODE_A && code <= KEYCODE_Z) |
| 1479 | 1500 | { |
| 1480 | | if(ShiftKeyPressed()) |
| 1481 | | { |
| 1482 | | return 'A' + (code - KEYCODE_A); |
| 1483 | | } |
| 1484 | | else |
| 1485 | | { |
| 1486 | | return 'a' + (code - KEYCODE_A); |
| 1487 | | } |
| 1501 | if(ShiftKeyPressed()) return 'A' + (code - KEYCODE_A); |
| 1502 | else return 'a' + (code - KEYCODE_A); |
| 1488 | 1503 | } |
| 1489 | | else if((code >= KEYCODE_0) && (code <= KEYCODE_9)) |
| 1504 | else if(code >= KEYCODE_0 && code <= KEYCODE_9) |
| 1490 | 1505 | { |
| 1491 | | if(ShiftKeyPressed()) |
| 1492 | | { |
| 1493 | | return ")!@#$%^&*("[code - KEYCODE_0]; |
| 1494 | | } |
| 1495 | | else |
| 1496 | | { |
| 1497 | | return '0' + (code - KEYCODE_0); |
| 1498 | | } |
| 1506 | if(ShiftKeyPressed()) return ")!@#$%^&*("[code - KEYCODE_0]; |
| 1507 | else return '0' + (code - KEYCODE_0); |
| 1499 | 1508 | } |
| 1500 | | else if((code >= KEYCODE_0_PAD) && (code <= KEYCODE_9_PAD)) |
| 1509 | else if(code >= KEYCODE_0_PAD && code <= KEYCODE_9_PAD) |
| 1501 | 1510 | { |
| 1502 | | return '0' + (code - KEYCODE_0_PAD); |
| 1511 | return '0' + (code - KEYCODE_0_PAD); |
| 1503 | 1512 | } |
| 1504 | 1513 | else if(code == KEYCODE_TILDE) |
| 1505 | 1514 | { |
| 1506 | | if(ShiftKeyPressed()) |
| 1507 | | { |
| 1508 | | return '~'; |
| 1509 | | } |
| 1510 | | else |
| 1511 | | { |
| 1512 | | return '`'; |
| 1513 | | } |
| 1515 | if(ShiftKeyPressed()) return '~'; |
| 1516 | else return '`'; |
| 1514 | 1517 | } |
| 1515 | 1518 | else if(code == KEYCODE_MINUS) |
| 1516 | 1519 | { |
| 1517 | | if(ShiftKeyPressed()) |
| 1518 | | { |
| 1519 | | return '_'; |
| 1520 | | } |
| 1521 | | else |
| 1522 | | { |
| 1523 | | return '-'; |
| 1524 | | } |
| 1520 | if(ShiftKeyPressed()) return '_'; |
| 1521 | else return '-'; |
| 1525 | 1522 | } |
| 1526 | 1523 | else if(code == KEYCODE_EQUALS) |
| 1527 | 1524 | { |
| 1528 | | if(ShiftKeyPressed()) |
| 1529 | | { |
| 1530 | | return '+'; |
| 1531 | | } |
| 1532 | | else |
| 1533 | | { |
| 1534 | | return '='; |
| 1535 | | } |
| 1525 | if(ShiftKeyPressed()) return '+'; |
| 1526 | else return '='; |
| 1536 | 1527 | } |
| 1537 | 1528 | else if(code == KEYCODE_BACKSPACE) |
| 1538 | 1529 | { |
| 1539 | | return 0x08; |
| 1530 | return 0x08; |
| 1540 | 1531 | } |
| 1541 | 1532 | else if(code == KEYCODE_OPENBRACE) |
| 1542 | 1533 | { |
| 1543 | | if(ShiftKeyPressed()) |
| 1544 | | { |
| 1545 | | return '{'; |
| 1546 | | } |
| 1547 | | else |
| 1548 | | { |
| 1549 | | return '['; |
| 1550 | | } |
| 1534 | if(ShiftKeyPressed()) return '{'; |
| 1535 | else return '['; |
| 1551 | 1536 | } |
| 1552 | 1537 | else if(code == KEYCODE_CLOSEBRACE) |
| 1553 | 1538 | { |
| 1554 | | if(ShiftKeyPressed()) |
| 1555 | | { |
| 1556 | | return '}'; |
| 1557 | | } |
| 1558 | | else |
| 1559 | | { |
| 1560 | | return ']'; |
| 1561 | | } |
| 1539 | if(ShiftKeyPressed()) return '}'; |
| 1540 | else return ']'; |
| 1562 | 1541 | } |
| 1563 | 1542 | else if(code == KEYCODE_COLON) |
| 1564 | 1543 | { |
| 1565 | | if(ShiftKeyPressed()) |
| 1566 | | { |
| 1567 | | return ':'; |
| 1568 | | } |
| 1569 | | else |
| 1570 | | { |
| 1571 | | return ';'; |
| 1572 | | } |
| 1544 | if(ShiftKeyPressed()) return ':'; |
| 1545 | else return ';'; |
| 1573 | 1546 | } |
| 1574 | 1547 | else if(code == KEYCODE_QUOTE) |
| 1575 | 1548 | { |
| 1576 | | if(ShiftKeyPressed()) |
| 1577 | | { |
| 1578 | | return '\"'; |
| 1579 | | } |
| 1580 | | else |
| 1581 | | { |
| 1582 | | return '\''; |
| 1583 | | } |
| 1549 | if(ShiftKeyPressed()) return '\"'; |
| 1550 | else return '\''; |
| 1584 | 1551 | } |
| 1585 | 1552 | else if(code == KEYCODE_BACKSLASH) |
| 1586 | 1553 | { |
| 1587 | | if(ShiftKeyPressed()) |
| 1588 | | { |
| 1589 | | return '|'; |
| 1590 | | } |
| 1591 | | else |
| 1592 | | { |
| 1593 | | return '\\'; |
| 1594 | | } |
| 1554 | if(ShiftKeyPressed()) return '|'; |
| 1555 | else return '\\'; |
| 1595 | 1556 | } |
| 1596 | 1557 | else if(code == KEYCODE_COMMA) |
| 1597 | 1558 | { |
| 1598 | | if(ShiftKeyPressed()) |
| 1599 | | { |
| 1600 | | return '<'; |
| 1601 | | } |
| 1602 | | else |
| 1603 | | { |
| 1604 | | return ','; |
| 1605 | | } |
| 1559 | if(ShiftKeyPressed()) return '<'; |
| 1560 | else return ','; |
| 1606 | 1561 | } |
| 1607 | 1562 | else if(code == KEYCODE_STOP) |
| 1608 | 1563 | { |
| 1609 | | if(ShiftKeyPressed()) |
| 1610 | | { |
| 1611 | | return '>'; |
| 1612 | | } |
| 1613 | | else |
| 1614 | | { |
| 1615 | | return '.'; |
| 1616 | | } |
| 1564 | if(ShiftKeyPressed()) return '>'; |
| 1565 | else return '.'; |
| 1617 | 1566 | } |
| 1618 | 1567 | else if(code == KEYCODE_SLASH) |
| 1619 | 1568 | { |
| 1620 | | if(ShiftKeyPressed()) |
| 1621 | | { |
| 1622 | | return '?'; |
| 1623 | | } |
| 1624 | | else |
| 1625 | | { |
| 1626 | | return '/'; |
| 1627 | | } |
| 1569 | if(ShiftKeyPressed()) return '?'; |
| 1570 | else return '/'; |
| 1628 | 1571 | } |
| 1629 | 1572 | else if(code == KEYCODE_SLASH_PAD) |
| 1630 | 1573 | { |
| 1631 | | return '/'; |
| 1574 | return '/'; |
| 1632 | 1575 | } |
| 1633 | 1576 | else if(code == KEYCODE_ASTERISK) |
| 1634 | 1577 | { |
| 1635 | | return '*'; |
| 1578 | return '*'; |
| 1636 | 1579 | } |
| 1637 | 1580 | else if(code == KEYCODE_MINUS_PAD) |
| 1638 | 1581 | { |
| 1639 | | return '-'; |
| 1582 | return '-'; |
| 1640 | 1583 | } |
| 1641 | 1584 | else if(code == KEYCODE_PLUS_PAD) |
| 1642 | 1585 | { |
| 1643 | | return '+'; |
| 1586 | return '+'; |
| 1644 | 1587 | } |
| 1645 | 1588 | else if(code == KEYCODE_SPACE) |
| 1646 | 1589 | { |
| 1647 | | return ' '; |
| 1590 | return ' '; |
| 1648 | 1591 | } |
| 1649 | 1592 | } |
| 1650 | 1593 | } |
| 1651 | 1594 | |
| 1652 | 1595 | #define osd_readkey_unicode ReadKeyAsync |
| 1653 | 1596 | |
| 1654 | | #endif |
| 1597 | #endif /* OSD_READKEY_KLUDGE */ |
| 1655 | 1598 | |
| 1656 | | #endif |
| 1657 | | |
| 1658 | 1599 | /*--------------------------------------------------- |
| 1659 | 1600 | ui_pressed_repeat_throttle - key repeat handling |
| 1660 | 1601 | ---------------------------------------------------*/ |
| r2821 | r2822 | |
| 2051 | 1992 | void cheat_init(running_machine *machine) |
| 2052 | 1993 | { |
| 2053 | 1994 | /* initialize lists */ |
| 2054 | | cheatList = NULL; |
| 2055 | | cheatListLength = 0; |
| 1995 | cheat_list = NULL; |
| 1996 | cheat_list_length = 0; |
| 2056 | 1997 | |
| 2057 | | watchList = NULL; |
| 2058 | | watchListLength = 0; |
| 1998 | watch_list = NULL; |
| 1999 | watch_list_length = 0; |
| 2059 | 2000 | |
| 2060 | 2001 | search_list = NULL; |
| 2061 | 2002 | search_list_length = 0; |
| r2821 | r2822 | |
| 2066 | 2007 | |
| 2067 | 2008 | /* initialize flags */ |
| 2068 | 2009 | current_search_idx = 0; |
| 2069 | | foundCheatDatabase = 0; |
| 2010 | found_database = 0; |
| 2070 | 2011 | cheatsDisabled = 0; |
| 2071 | 2012 | watchesDisabled = 0; |
| 2072 | 2013 | editActive = 0; |
| 2073 | 2014 | editCursor = 0; |
| 2074 | | cheatOptions = DEFAULT_CHEAT_OPTIONS; |
| 2015 | cheat_options = DEFAULT_CHEAT_OPTIONS; |
| 2075 | 2016 | driverSpecifiedFlag = 0; |
| 2076 | 2017 | |
| 2077 | 2018 | fullMenuPageHeight = visible_items = floor(1.0f / ui_get_line_height()) - 1; |
| r2821 | r2822 | |
| 2080 | 2021 | build_cpu_region_info_list(machine); |
| 2081 | 2022 | |
| 2082 | 2023 | /* set cheat list from database */ |
| 2083 | | LoadCheatDatabase(machine, kLoadFlag_CheatOption | kLoadFlag_CheatCode); |
| 2024 | load_cheat_database(machine, kLoadFlag_CheatOption | kLoadFlag_CheatCode); |
| 2084 | 2025 | |
| 2085 | 2026 | /* set default search and watch lists */ |
| 2086 | 2027 | resize_search_list(1); |
| 2087 | | ResizeWatchList(fullMenuPageHeight - 1); |
| 2028 | resize_watch_list(fullMenuPageHeight - 1, 0); |
| 2088 | 2029 | |
| 2089 | 2030 | /* build search region */ |
| 2090 | 2031 | { |
| 2091 | 2032 | search_info *info = get_current_search(); |
| 2092 | 2033 | |
| 2093 | 2034 | /* attemp to load user region */ |
| 2094 | | LoadCheatDatabase(machine, kLoadFlag_UserRegion); |
| 2035 | load_cheat_database(machine, kLoadFlag_UserRegion); |
| 2095 | 2036 | |
| 2096 | 2037 | /* if no user region or fail to load the database, attempt to build default region */ |
| 2097 | 2038 | if(info->region_list_length) |
| 2098 | | info->search_speed = ksearch_speed_UserDefined; |
| 2039 | info->search_speed = SEARCH_SPEED_USER_DEFINED; |
| 2099 | 2040 | else |
| 2100 | 2041 | { |
| 2101 | | info->search_speed = ksearch_speed_VerySlow; |
| 2042 | info->search_speed = SEARCH_SPEED_VERY_SLOW; |
| 2102 | 2043 | build_search_regions(machine, info); |
| 2103 | 2044 | } |
| 2104 | 2045 | |
| r2821 | r2822 | |
| 2128 | 2069 | } |
| 2129 | 2070 | |
| 2130 | 2071 | /* NOTE : disable all cheat messages in initializing so that message parameters should be initialized here */ |
| 2131 | | messageType = 0; |
| 2132 | | messageTimer = 0; |
| 2072 | SET_MESSAGE(0); |
| 2133 | 2073 | |
| 2134 | 2074 | periodic_timer = timer_alloc(cheat_periodic, NULL); |
| 2135 | 2075 | timer_adjust_periodic(periodic_timer, video_screen_get_frame_period(machine->primary_screen), 0, video_screen_get_frame_period(machine->primary_screen)); |
| r2821 | r2822 | |
| 2146 | 2086 | int i; |
| 2147 | 2087 | |
| 2148 | 2088 | /* save all cheats automatically if needed */ |
| 2149 | | if(TEST_FIELD(cheatOptions, AutoSaveEnabled)) |
| 2089 | if(TEST_FIELD(cheat_options, AutoSaveEnabled)) |
| 2150 | 2090 | DoAutoSaveCheats(machine); |
| 2151 | 2091 | |
| 2152 | | /* free database */ |
| 2153 | | DisposeCheatDatabase(); |
| 2092 | /* free cheat list */ |
| 2093 | dispose_cheat_database(); |
| 2154 | 2094 | |
| 2155 | 2095 | /* free watch lists */ |
| 2156 | | if(watchList) |
| 2096 | if(watch_list) |
| 2157 | 2097 | { |
| 2158 | | for(i = 0; i < watchListLength; i++) |
| 2159 | | DisposeWatch(&watchList[i]); |
| 2098 | for(i = 0; i < watch_list_length; i++) |
| 2099 | dispose_watch(&watch_list[i]); |
| 2160 | 2100 | |
| 2161 | | free(watchList); |
| 2101 | free(watch_list); |
| 2162 | 2102 | |
| 2163 | | watchList = NULL; |
| 2103 | watch_list = NULL; |
| 2164 | 2104 | } |
| 2165 | 2105 | |
| 2166 | 2106 | /* free search lists */ |
| r2821 | r2822 | |
| 2188 | 2128 | #endif |
| 2189 | 2129 | |
| 2190 | 2130 | /* free flags */ |
| 2191 | | cheatListLength = 0; |
| 2192 | | watchListLength = 0; |
| 2193 | | search_list_length = 0; |
| 2194 | | current_search_idx = 0; |
| 2195 | | foundCheatDatabase = 0; |
| 2196 | | cheatsDisabled = 0; |
| 2197 | | watchesDisabled = 0; |
| 2198 | | mainDatabaseName[0] = 0; |
| 2199 | | menuItemInfoLength = 0; |
| 2200 | | cheatVariable[0] = 0; |
| 2201 | | cheatOptions = 0; |
| 2202 | | driverSpecifiedFlag = 0; |
| 2203 | | messageType = 0; |
| 2204 | | messageTimer = 0; |
| 2131 | cheat_list_length = 0; |
| 2132 | watch_list_length = 0; |
| 2133 | search_list_length = 0; |
| 2134 | current_search_idx = 0; |
| 2135 | found_database = 0; |
| 2136 | cheatsDisabled = 0; |
| 2137 | watchesDisabled = 0; |
| 2138 | main_database_name[0] = 0; |
| 2139 | menuItemInfoLength = 0; |
| 2140 | cheatVariable[0] = 0; |
| 2141 | cheat_options = 0; |
| 2142 | driverSpecifiedFlag = 0; |
| 2143 | SET_MESSAGE(0); |
| 2205 | 2144 | } |
| 2206 | 2145 | |
| 2207 | 2146 | /*---------------------------------- |
| r2821 | r2822 | |
| 2359 | 2298 | changed = 1; |
| 2360 | 2299 | } |
| 2361 | 2300 | |
| 2362 | | /* length of buffer 1*/ |
| 2301 | /* length of buffer 1 */ |
| 2363 | 2302 | if(menu_strings.main_string_length < main_string_length) |
| 2364 | 2303 | { |
| 2365 | 2304 | menu_strings.main_string_length = main_string_length; |
| r2821 | r2822 | |
| 2410 | 2349 | { |
| 2411 | 2350 | char *temp = NULL; |
| 2412 | 2351 | |
| 2413 | | if(buf) |
| 2352 | if(buf && buf[0] != 0) |
| 2414 | 2353 | { |
| 2415 | 2354 | /* allocate memory */ |
| 2416 | 2355 | size_t length = strlen(buf) + 1; |
| r2821 | r2822 | |
| 2535 | 2474 | static int user_select_value_menu(running_machine *machine, cheat_menu_stack *menu) |
| 2536 | 2475 | { |
| 2537 | 2476 | int i; |
| 2538 | | UINT8 isBCD; |
| 2477 | UINT8 is_bcd; |
| 2539 | 2478 | UINT32 min; |
| 2540 | 2479 | UINT32 max; |
| 2541 | 2480 | static int master = 0; |
| 2542 | | static int displayValue = -1; |
| 2481 | static int display_value = -1; |
| 2543 | 2482 | char buf[256]; |
| 2544 | | char * stringsBuf = buf; |
| 2545 | | CheatEntry * entry = &cheatList[menu->pre_sel]; |
| 2546 | | CheatAction * action = NULL; |
| 2483 | char *strings_buf = buf; |
| 2484 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 2485 | cheat_action *action = NULL; |
| 2547 | 2486 | |
| 2548 | 2487 | /* first setting 1 : search master code of value-selection */ |
| 2549 | 2488 | if(menu->first_time) |
| 2550 | 2489 | { |
| 2551 | | for(i = 0; i < entry->actionListLength; i++) |
| 2490 | for(i = 0; i < entry->action_list_length; i++) |
| 2552 | 2491 | { |
| 2553 | | /* get value selection master code */ |
| 2554 | | if( EXTRACT_FIELD(entry->actionList[i].type, CodeType) == kCodeType_VWrite || |
| 2555 | | EXTRACT_FIELD(entry->actionList[i].type, CodeType) == kCodeType_VRWrite) |
| 2556 | | { |
| 2557 | | master = i; |
| 2558 | | break; |
| 2559 | | } |
| 2492 | if(entry->action_list[0].flags & kActionFlag_OldFormat) { |
| 2493 | /* NOTE : old format should be always master = 0 */ |
| 2494 | master = 0; break; } |
| 2495 | |
| 2496 | /* search value selection master code */ |
| 2497 | if(TEST_FIELD(entry->action_list[i].type, ValueSelectEnable)) { |
| 2498 | master = i; break; } |
| 2560 | 2499 | } |
| 2561 | 2500 | } |
| 2562 | 2501 | |
| 2563 | | action = &entry->actionList[master]; |
| 2502 | /* set value selection master code */ |
| 2503 | action = &entry->action_list[master]; |
| 2564 | 2504 | |
| 2565 | 2505 | if(TEST_FIELD(action->type, ValueSelectMinimumDisplay) || TEST_FIELD(action->type, ValueSelectMinimum)) |
| 2566 | 2506 | min = 1; |
| 2567 | 2507 | else |
| 2568 | 2508 | min = 0; |
| 2569 | 2509 | |
| 2570 | | max = action->originalDataField + min; |
| 2571 | | isBCD = EXTRACT_FIELD(action->type, ValueSelectBCD); |
| 2510 | max = action->original_data + min; |
| 2511 | is_bcd = EXTRACT_FIELD(action->type, ValueSelectBCD); |
| 2572 | 2512 | |
| 2573 | 2513 | /* first setting 2 : save the value */ |
| 2574 | 2514 | if(menu->first_time) |
| 2575 | 2515 | { |
| 2576 | | displayValue = isBCD ? DecimalToBCD(BCDToDecimal(ReadData(action))) : ReadData(action); |
| 2516 | display_value = is_bcd ? DecimalToBCD(BCDToDecimal(ReadData(action))) : ReadData(action); |
| 2577 | 2517 | |
| 2578 | | if(displayValue < min) |
| 2579 | | displayValue = min; |
| 2580 | | else if(displayValue > max) |
| 2581 | | displayValue = max; |
| 2518 | if(display_value < min) |
| 2519 | display_value = min; |
| 2520 | else if(display_value > max) |
| 2521 | display_value = max; |
| 2582 | 2522 | else if(TEST_FIELD(action->type, ValueSelectMinimumDisplay)) |
| 2583 | | displayValue++; |
| 2523 | display_value++; |
| 2584 | 2524 | |
| 2585 | 2525 | menu->first_time = 0; |
| 2586 | 2526 | } |
| 2587 | 2527 | |
| 2588 | 2528 | /* ##### MENU CONSTRACTION ##### */ |
| 2589 | | stringsBuf += sprintf(stringsBuf, "\t%s\n\t", entry->name); |
| 2529 | strings_buf += sprintf(strings_buf, "\t%s\n\t", entry->name); |
| 2590 | 2530 | |
| 2591 | 2531 | if(editActive) |
| 2592 | 2532 | { |
| 2593 | 2533 | for(i = kSearchByteDigitsTable[EXTRACT_FIELD(action->type, AddressSize)] - 1; i >= 0; i--) |
| 2594 | 2534 | { |
| 2595 | 2535 | if(i == editCursor) |
| 2596 | | stringsBuf += sprintf(stringsBuf, "[%X]", (displayValue & kIncrementMaskTable[i]) / kIncrementValueTable[i]); |
| 2536 | strings_buf += sprintf(strings_buf, "[%X]", (display_value & kIncrementMaskTable[i]) / kIncrementValueTable[i]); |
| 2597 | 2537 | else |
| 2598 | | stringsBuf += sprintf(stringsBuf, "%X", (displayValue & kIncrementMaskTable[i]) / kIncrementValueTable[i]); |
| 2538 | strings_buf += sprintf(strings_buf, "%X", (display_value & kIncrementMaskTable[i]) / kIncrementValueTable[i]); |
| 2599 | 2539 | } |
| 2600 | 2540 | } |
| 2601 | 2541 | else |
| 2602 | | stringsBuf += sprintf(stringsBuf, "%.*X", kSearchByteDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], displayValue); |
| 2542 | strings_buf += sprintf(strings_buf, "%.*X", kSearchByteDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], display_value); |
| 2603 | 2543 | |
| 2604 | 2544 | if(TEST_FIELD(action->type, ValueSelectNegative)) |
| 2605 | | stringsBuf += sprintf( stringsBuf, " <%.*X>", |
| 2545 | strings_buf += sprintf( strings_buf, " <%.*X>", |
| 2606 | 2546 | kSearchByteDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 2607 | | (~displayValue + 1) & kSearchByteMaskTable[EXTRACT_FIELD(action->type, AddressSize)]); |
| 2547 | (~display_value + 1) & kSearchByteMaskTable[EXTRACT_FIELD(action->type, AddressSize)]); |
| 2608 | 2548 | |
| 2609 | | if(!isBCD) |
| 2610 | | stringsBuf += sprintf(stringsBuf, " (%d)", displayValue); |
| 2549 | if(is_bcd == 0) |
| 2550 | strings_buf += sprintf(strings_buf, " (%d)", display_value); |
| 2611 | 2551 | |
| 2612 | | stringsBuf += sprintf(stringsBuf, "\n\t OK "); |
| 2552 | strings_buf += sprintf(strings_buf, "\n\t OK "); |
| 2613 | 2553 | |
| 2614 | 2554 | /* print it */ |
| 2615 | 2555 | ui_draw_message_window(buf); |
| r2821 | r2822 | |
| 2619 | 2559 | { |
| 2620 | 2560 | if(editActive) |
| 2621 | 2561 | { |
| 2622 | | if(displayValue == max) |
| 2623 | | displayValue = min; |
| 2562 | if(display_value == max) |
| 2563 | display_value = min; |
| 2624 | 2564 | else |
| 2625 | 2565 | { |
| 2626 | | displayValue = isBCD ? DoIncrementDecField(displayValue, editCursor) : DoIncrementHexField(displayValue, editCursor); |
| 2566 | display_value = is_bcd ? DoIncrementDecField(display_value, editCursor) : DoIncrementHexField(display_value, editCursor); |
| 2627 | 2567 | |
| 2628 | | if(displayValue > max) |
| 2629 | | displayValue = max; |
| 2568 | if(display_value > max) |
| 2569 | display_value = max; |
| 2630 | 2570 | } |
| 2631 | 2571 | } |
| 2632 | 2572 | } |
| r2821 | r2822 | |
| 2634 | 2574 | { |
| 2635 | 2575 | if(editActive) |
| 2636 | 2576 | { |
| 2637 | | if(displayValue == min) |
| 2638 | | displayValue = max; |
| 2577 | if(display_value == min) |
| 2578 | display_value = max; |
| 2639 | 2579 | |
| 2640 | 2580 | else |
| 2641 | 2581 | { |
| 2642 | | displayValue = isBCD ? DoDecrementDecField(displayValue, editCursor) : DoDecrementHexField(displayValue, editCursor); |
| 2582 | display_value = is_bcd ? DoDecrementDecField(display_value, editCursor) : DoDecrementHexField(display_value, editCursor); |
| 2643 | 2583 | |
| 2644 | | if(displayValue > max) |
| 2645 | | displayValue = max; |
| 2584 | if(display_value > max) |
| 2585 | display_value = max; |
| 2646 | 2586 | } |
| 2647 | 2587 | } |
| 2648 | 2588 | } |
| r2821 | r2822 | |
| 2655 | 2595 | } |
| 2656 | 2596 | else |
| 2657 | 2597 | { |
| 2658 | | if(displayValue-- == min) |
| 2659 | | displayValue = max; |
| 2598 | if(display_value-- == min) |
| 2599 | display_value = max; |
| 2660 | 2600 | |
| 2661 | | if(isBCD) |
| 2662 | | displayValue = DecimalToBCD(BCDToDecimal(displayValue)); |
| 2601 | if(is_bcd) |
| 2602 | display_value = DecimalToBCD(BCDToDecimal(display_value)); |
| 2663 | 2603 | } |
| 2664 | 2604 | } |
| 2665 | 2605 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate)) |
| r2821 | r2822 | |
| 2671 | 2611 | } |
| 2672 | 2612 | else |
| 2673 | 2613 | { |
| 2674 | | if(++displayValue > max) |
| 2675 | | displayValue = min; |
| 2614 | if(++display_value > max) |
| 2615 | display_value = min; |
| 2676 | 2616 | |
| 2677 | | if(isBCD) |
| 2678 | | displayValue = DecimalToBCD(BCDToDecimal(displayValue)); |
| 2617 | if(is_bcd) |
| 2618 | display_value = DecimalToBCD(BCDToDecimal(display_value)); |
| 2679 | 2619 | } |
| 2680 | 2620 | } |
| 2681 | 2621 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| r2821 | r2822 | |
| 2687 | 2627 | |
| 2688 | 2628 | /* adjust a value */ |
| 2689 | 2629 | if(TEST_FIELD(action->type, ValueSelectMinimumDisplay)) |
| 2690 | | displayValue--; |
| 2630 | display_value--; |
| 2691 | 2631 | |
| 2692 | | if(TEST_FIELD(action->type, ValueSelectMinimum) && !displayValue) |
| 2693 | | displayValue = 1; |
| 2632 | if(TEST_FIELD(action->type, ValueSelectMinimum) && display_value == 0) |
| 2633 | display_value = 1; |
| 2694 | 2634 | |
| 2695 | | if(TEST_FIELD(action->type, ValueSelectNegative) && displayValue) |
| 2696 | | displayValue = (~displayValue + 1) & kSearchByteMaskTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 2635 | if(TEST_FIELD(action->type, ValueSelectNegative) && display_value) |
| 2636 | display_value = (~display_value + 1) & kSearchByteMaskTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 2697 | 2637 | |
| 2698 | | /* copy value */ |
| 2699 | | for(i = 0; i < entry->actionListLength; i++) |
| 2638 | /* set/copy value */ |
| 2639 | for(i = 0; i < entry->action_list_length; i++) |
| 2700 | 2640 | { |
| 2701 | | CheatAction * destination = &entry->actionList[i]; |
| 2641 | cheat_action *destination = &entry->action_list[i]; |
| 2702 | 2642 | |
| 2703 | | int copyValue = displayValue; |
| 2643 | int copy_value = display_value; |
| 2704 | 2644 | |
| 2705 | | if( EXTRACT_FIELD(destination->type, CodeType) == kCodeType_VWrite || |
| 2706 | | EXTRACT_FIELD(destination->type, CodeType) == kCodeType_VRWrite) |
| 2645 | if(i == master) |
| 2707 | 2646 | { |
| 2708 | | destination->data = displayValue; |
| 2647 | /* set value */ |
| 2648 | destination->data = display_value; |
| 2709 | 2649 | } |
| 2710 | | else if(EXTRACT_FIELD(destination->type, Link) == kLink_CopyLink) |
| 2650 | else if(TEST_FIELD(destination->type, ValueSelectEnable)) |
| 2711 | 2651 | { |
| 2712 | | int newData = destination->originalDataField; |
| 2652 | /* copy value */ |
| 2653 | int new_data = destination->original_data; |
| 2713 | 2654 | |
| 2714 | | if(TEST_FIELD(destination->type, LinkValueSelectBCD)) |
| 2655 | if(TEST_FIELD(destination->type, ValueSelectBCD)) |
| 2715 | 2656 | { |
| 2716 | | copyValue = BCDToDecimal(DecimalToBCD(copyValue)); |
| 2717 | | newData = BCDToDecimal(DecimalToBCD(newData)); |
| 2657 | copy_value = BCDToDecimal(DecimalToBCD(copy_value)); |
| 2658 | new_data = BCDToDecimal(DecimalToBCD(new_data)); |
| 2718 | 2659 | } |
| 2719 | 2660 | |
| 2720 | | copyValue += newData; |
| 2661 | copy_value += new_data; |
| 2721 | 2662 | |
| 2722 | | if(TEST_FIELD(destination->type, LinkValueSelectBCD)) |
| 2723 | | copyValue = DecimalToBCD(BCDToDecimal(copyValue)); |
| 2663 | if(TEST_FIELD(destination->type, ValueSelectBCD)) |
| 2664 | copy_value = DecimalToBCD(BCDToDecimal(copy_value)); |
| 2724 | 2665 | |
| 2725 | | if(TEST_FIELD(destination->type, LinkValueSelectNegative)) |
| 2726 | | copyValue = (~copyValue + 1) & kSearchByteMaskTable[EXTRACT_FIELD(destination->type, AddressSize)]; |
| 2666 | if(TEST_FIELD(destination->type, ValueSelectNegative)) |
| 2667 | copy_value = (~copy_value + 1) & kSearchByteMaskTable[EXTRACT_FIELD(destination->type, AddressSize)]; |
| 2727 | 2668 | |
| 2728 | | destination->data = copyValue; |
| 2669 | destination->data = copy_value; |
| 2729 | 2670 | } |
| 2730 | 2671 | } |
| 2731 | 2672 | |
| r2821 | r2822 | |
| 2740 | 2681 | } |
| 2741 | 2682 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 2742 | 2683 | { |
| 2743 | | if(editActive) |
| 2744 | | editActive = 0; |
| 2745 | | else |
| 2746 | | menu->sel = -1; |
| 2684 | if(editActive) editActive = 0; |
| 2685 | else menu->sel = -1; |
| 2747 | 2686 | } |
| 2748 | 2687 | |
| 2749 | 2688 | /* ##### EDIT ##### */ |
| 2750 | | if(!editActive) |
| 2689 | if(editActive == 0) |
| 2751 | 2690 | { |
| 2752 | 2691 | UINT32 temp; |
| 2753 | 2692 | |
| 2754 | | temp = displayValue; |
| 2755 | | displayValue = do_edit_hex_field(machine, displayValue) & kCheatSizeMaskTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 2693 | temp = display_value; |
| 2694 | display_value = do_edit_hex_field(machine, display_value) & kCheatSizeMaskTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 2756 | 2695 | |
| 2757 | | if(displayValue != temp) |
| 2696 | if(display_value != temp) |
| 2758 | 2697 | { |
| 2759 | | if(isBCD) |
| 2760 | | displayValue = DecimalToBCD(BCDToDecimal(displayValue)); |
| 2698 | if(is_bcd) |
| 2699 | display_value = DecimalToBCD(BCDToDecimal(display_value)); |
| 2761 | 2700 | |
| 2762 | | if(displayValue < min) displayValue = max; |
| 2763 | | if(displayValue > max) displayValue = min; |
| 2701 | if(display_value < min) display_value = max; |
| 2702 | if(display_value > max) display_value = min; |
| 2764 | 2703 | } |
| 2765 | 2704 | } |
| 2766 | 2705 | |
| r2821 | r2822 | |
| 2775 | 2714 | { |
| 2776 | 2715 | int i; |
| 2777 | 2716 | UINT8 total = 0; |
| 2778 | | const char ** menuItem; |
| 2779 | | char ** buf; |
| 2780 | | CheatEntry * entry = &cheatList[menu->pre_sel]; |
| 2717 | const char **menu_item; |
| 2718 | char **buf; |
| 2719 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 2781 | 2720 | |
| 2782 | 2721 | /* required items = (total items + return + terminator) & (strings buf * total items [max chars = 100]) */ |
| 2783 | | request_strings(entry->actionListLength + 2, entry->actionListLength, 100, 0); |
| 2784 | | menuItem = menu_strings.main_list; |
| 2722 | request_strings(entry->action_list_length + 2, entry->action_list_length, 100, 0); |
| 2723 | menu_item = menu_strings.main_list; |
| 2785 | 2724 | buf = menu_strings.main_strings; |
| 2786 | 2725 | |
| 2787 | 2726 | /* first setting : compute cursor position from previous menu */ |
| r2821 | r2822 | |
| 2792 | 2731 | } |
| 2793 | 2732 | |
| 2794 | 2733 | /********** MENU CONSTRUCTION **********/ |
| 2795 | | for(i = 0; i < entry->labelIndexLength; i++) |
| 2734 | for(i = 0; i < entry->label_index_length; i++) |
| 2796 | 2735 | { |
| 2797 | | if(!i) |
| 2736 | if(i == 0) |
| 2798 | 2737 | { |
| 2799 | | if(!(entry->flags & kCheatFlag_OneShot)) |
| 2738 | if((entry->flags & kCheatFlag_OneShot) == 0) |
| 2800 | 2739 | { |
| 2801 | 2740 | /* add "OFF" item if not one shot at the first time */ |
| 2802 | 2741 | if(!entry->selection) |
| r2821 | r2822 | |
| 2804 | 2743 | else |
| 2805 | 2744 | sprintf(buf[total], "Off"); |
| 2806 | 2745 | |
| 2807 | | menuItem[total] = buf[total]; |
| 2746 | menu_item[total] = buf[total]; |
| 2808 | 2747 | total++; |
| 2809 | 2748 | } |
| 2810 | 2749 | |
| 2811 | 2750 | continue; |
| 2812 | 2751 | } |
| 2813 | 2752 | else if(i == entry->selection) |
| 2814 | | sprintf(buf[total], "[ %s ]", entry->actionList[entry->labelIndex[i]].optionalName); |
| 2753 | sprintf(buf[total], "[ %s ]", entry->action_list[entry->label_index[i]].optional_name); |
| 2815 | 2754 | else |
| 2816 | | sprintf(buf[total], "%s", entry->actionList[entry->labelIndex[i]].optionalName); |
| 2755 | sprintf(buf[total], "%s", entry->action_list[entry->label_index[i]].optional_name); |
| 2817 | 2756 | |
| 2818 | | menuItem[total] = buf[total]; |
| 2757 | menu_item[total] = buf[total]; |
| 2819 | 2758 | total++; |
| 2820 | 2759 | } |
| 2821 | 2760 | |
| 2822 | 2761 | /* ##### RETURN ##### */ |
| 2823 | | menuItem[total++] = "Return to Prior Menu"; |
| 2762 | menu_item[total++] = "Return to Prior Menu"; |
| 2824 | 2763 | |
| 2825 | 2764 | /* ##### TERMINATE ARRAY ##### */ |
| 2826 | | menuItem[total] = NULL; |
| 2765 | menu_item[total] = NULL; |
| 2827 | 2766 | |
| 2828 | 2767 | /* adjust current cursor position */ |
| 2829 | | ADJUST_CURSOR(menu->sel, total) |
| 2768 | ADJUST_CURSOR(menu->sel, total); |
| 2830 | 2769 | |
| 2831 | 2770 | /* draw it */ |
| 2832 | | old_style_menu(menuItem, NULL, NULL, menu->sel, 0); |
| 2771 | old_style_menu(menu_item, NULL, NULL, menu->sel, 0); |
| 2833 | 2772 | |
| 2834 | 2773 | /********** KEY HANDLING **********/ |
| 2835 | 2774 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 2836 | 2775 | { |
| 2837 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 2776 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 2838 | 2777 | } |
| 2839 | 2778 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 2840 | 2779 | { |
| 2841 | | CURSOR_TO_NEXT(menu->sel, total) |
| 2780 | CURSOR_TO_NEXT(menu->sel, total); |
| 2842 | 2781 | } |
| 2843 | 2782 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 2844 | 2783 | { |
| r2821 | r2822 | |
| 2846 | 2785 | } |
| 2847 | 2786 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 2848 | 2787 | { |
| 2849 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 2788 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 2850 | 2789 | } |
| 2851 | 2790 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 2852 | 2791 | { |
| r2821 | r2822 | |
| 2861 | 2800 | DeactivateCheat(entry); |
| 2862 | 2801 | |
| 2863 | 2802 | /* NOTE : the index number of master code should be stored into 1st table */ |
| 2864 | | if(TEST_FIELD(entry->actionList[entry->labelIndex[0]].type, LabelSelectQuickClose)) |
| 2803 | if(TEST_FIELD(entry->action_list[entry->label_index[0]].type, LabelSelectQuickClose)) |
| 2865 | 2804 | menu->sel = -1; |
| 2866 | 2805 | } |
| 2867 | 2806 | else |
| r2821 | r2822 | |
| 2880 | 2819 | static int comment_menu(running_machine *machine, cheat_menu_stack *menu) |
| 2881 | 2820 | { |
| 2882 | 2821 | char buf[2048]; |
| 2883 | | const char * comment; |
| 2884 | | CheatEntry * entry = &cheatList[menu->pre_sel]; |
| 2822 | const char *comment; |
| 2823 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 2885 | 2824 | |
| 2886 | 2825 | /* first setting : NONE */ |
| 2887 | 2826 | if(menu->first_time) |
| 2888 | 2827 | menu->first_time = 0; |
| 2889 | 2828 | |
| 2890 | 2829 | /********** MENU CONSTRUCTION **********/ |
| 2891 | | if(entry->comment && entry->comment[0]) |
| 2892 | | comment = entry->comment; |
| 2893 | | else |
| 2894 | | comment = "this code doesn't have a comment"; |
| 2895 | | |
| 2830 | comment = entry->comment; |
| 2896 | 2831 | sprintf(buf, "%s\n\t OK ", comment); |
| 2897 | 2832 | |
| 2898 | 2833 | /* print it */ |
| r2821 | r2822 | |
| 2913 | 2848 | { |
| 2914 | 2849 | int i; |
| 2915 | 2850 | UINT8 total = 0; |
| 2916 | | const char ** menuItem; |
| 2917 | | char ** buf; |
| 2918 | | CheatEntry * entry = &cheatList[menu->pre_sel]; |
| 2851 | const char **menu_item; |
| 2852 | char **buf; |
| 2853 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 2919 | 2854 | |
| 2920 | | if(!entry->actionListLength) |
| 2921 | | return 0; |
| 2922 | | |
| 2923 | 2855 | /* first setting : NONE */ |
| 2924 | 2856 | if(menu->first_time) |
| 2925 | 2857 | menu->first_time = 0; |
| 2926 | 2858 | |
| 2927 | 2859 | /* required items = (display comment lines + return + terminator) & (strings buf * display comment lines [max char = 100]) */ |
| 2928 | | request_strings(entry->actionListLength + 1, entry->actionListLength - 1, 100, 0); |
| 2929 | | menuItem = menu_strings.main_list; |
| 2860 | request_strings(entry->action_list_length + 1, entry->action_list_length - 1, 100, 0); |
| 2861 | menu_item = menu_strings.main_list; |
| 2930 | 2862 | buf = menu_strings.main_strings; |
| 2931 | 2863 | |
| 2932 | 2864 | /********** MENU CONSTRUCTION **********/ |
| 2933 | | for(i = 1; i < entry->actionListLength; i++) |
| 2865 | for(i = 1; i < entry->action_list_length; i++) |
| 2934 | 2866 | { |
| 2935 | | CheatAction * action = &entry->actionList[i]; |
| 2867 | cheat_action *action = &entry->action_list[i]; |
| 2936 | 2868 | |
| 2937 | 2869 | /* NOTE : don't display the comment in master code */ |
| 2938 | | if(i) |
| 2870 | if(i != 0) |
| 2939 | 2871 | { |
| 2940 | | sprintf(buf[total], "%s", action->optionalName); |
| 2941 | | menuItem[total] = buf[total]; |
| 2872 | sprintf(buf[total], "%s", action->optional_name); |
| 2873 | menu_item[total] = buf[total]; |
| 2942 | 2874 | total++; |
| 2943 | 2875 | } |
| 2944 | 2876 | } |
| 2945 | 2877 | |
| 2946 | 2878 | /* ##### OK ##### */ |
| 2947 | | menuItem[total++] = "OK"; |
| 2879 | menu_item[total++] = "OK"; |
| 2948 | 2880 | |
| 2949 | 2881 | /* ##### TERMINATE ARRAY ##### */ |
| 2950 | | menuItem[total] = NULL; |
| 2882 | menu_item[total] = NULL; |
| 2951 | 2883 | |
| 2952 | 2884 | /* adjust cursor position */ |
| 2953 | | ADJUST_CURSOR(menu->sel, total) |
| 2885 | ADJUST_CURSOR(menu->sel, total); |
| 2954 | 2886 | |
| 2955 | 2887 | /* draw it */ |
| 2956 | | old_style_menu(menuItem, NULL, NULL, menu->sel, 0); |
| 2888 | old_style_menu(menu_item, NULL, NULL, menu->sel, 0); |
| 2957 | 2889 | |
| 2958 | 2890 | /********** KEY HANDLING **********/ |
| 2959 | 2891 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 2960 | 2892 | { |
| 2961 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 2893 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 2962 | 2894 | } |
| 2963 | 2895 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 2964 | 2896 | { |
| 2965 | | CURSOR_TO_NEXT(menu->sel, total) |
| 2897 | CURSOR_TO_NEXT(menu->sel, total); |
| 2966 | 2898 | } |
| 2967 | 2899 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 2968 | 2900 | { |
| 2969 | | CURSOR_PAGE_UP(menu->sel) |
| 2901 | CURSOR_PAGE_UP(menu->sel); |
| 2970 | 2902 | } |
| 2971 | 2903 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 2972 | 2904 | { |
| 2973 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 2905 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 2974 | 2906 | } |
| 2975 | 2907 | else if(input_ui_pressed(machine, IPT_UI_SELECT) || input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 2976 | 2908 | menu->sel = -1; |
| r2821 | r2822 | |
| 3017 | 2949 | menu_item[total++].text = "Add/Edit a Cheat"; |
| 3018 | 2950 | |
| 3019 | 2951 | /* ##### Search a Cheat ##### */ |
| 3020 | | switch(EXTRACT_FIELD(cheatOptions, SearchBox)) |
| 2952 | switch(EXTRACT_FIELD(cheat_options, SearchBox)) |
| 3021 | 2953 | { |
| 3022 | 2954 | case kSearchBox_Minimum: |
| 3023 | 2955 | menu_item[total++].text = "Search a Cheat (Minimum Mode)"; |
| r2821 | r2822 | |
| 3055 | 2987 | /* ##### Terminate Array ##### */ |
| 3056 | 2988 | menu_item[total].text = NULL; |
| 3057 | 2989 | |
| 3058 | | ADJUST_CURSOR(menu->sel, total) |
| 2990 | ADJUST_CURSOR(menu->sel, total); |
| 3059 | 2991 | |
| 3060 | 2992 | /* print it */ |
| 3061 | 2993 | ui_menu_draw(menu_item, total, menu->sel, NULL); |
| r2821 | r2822 | |
| 3063 | 2995 | /********** KEY HANDLING **********/ |
| 3064 | 2996 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 3065 | 2997 | { |
| 3066 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 2998 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 3067 | 2999 | } |
| 3068 | 3000 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 3069 | 3001 | { |
| 3070 | | CURSOR_TO_NEXT(menu->sel, total) |
| 3002 | CURSOR_TO_NEXT(menu->sel, total); |
| 3071 | 3003 | } |
| 3072 | 3004 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 3073 | 3005 | { |
| 3074 | | CURSOR_PAGE_UP(menu->sel) |
| 3006 | CURSOR_PAGE_UP(menu->sel); |
| 3075 | 3007 | } |
| 3076 | 3008 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 3077 | 3009 | { |
| 3078 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 3010 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 3079 | 3011 | } |
| 3080 | 3012 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 3081 | 3013 | { |
| r2821 | r2822 | |
| 3090 | 3022 | break; |
| 3091 | 3023 | |
| 3092 | 3024 | case kMenu_Search: |
| 3093 | | switch(EXTRACT_FIELD(cheatOptions, SearchBox)) |
| 3025 | switch(EXTRACT_FIELD(cheat_options, SearchBox)) |
| 3094 | 3026 | { |
| 3095 | 3027 | case kSearchBox_Minimum: |
| 3096 | 3028 | cheat_menu_stack_push(search_minimum_menu, menu->handler, menu->sel); |
| r2821 | r2822 | |
| 3128 | 3060 | } |
| 3129 | 3061 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 3130 | 3062 | { |
| 3131 | | ReloadCheatDatabase(machine); |
| 3063 | reload_cheat_database(machine); |
| 3132 | 3064 | } |
| 3133 | 3065 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 3134 | 3066 | { |
| r2821 | r2822 | |
| 3146 | 3078 | { |
| 3147 | 3079 | int i; |
| 3148 | 3080 | UINT8 total = 0; |
| 3149 | | UINT8 length = cheatListLength ? cheatListLength : 2; |
| 3150 | | UINT8 isEmpty = 0; |
| 3151 | | UINT8 * menuIndex; |
| 3152 | | static INT8 currentLayer; |
| 3153 | | const char ** menu_item; |
| 3154 | | const char ** menu_subitem; |
| 3155 | | char * flagBuf; |
| 3156 | | CheatEntry * entry; |
| 3081 | UINT8 length = cheat_list_length ? cheat_list_length : 2; |
| 3082 | UINT8 is_empty = 0; |
| 3083 | UINT8 request_arrow = 0; |
| 3084 | UINT8 *menu_index; |
| 3085 | static INT8 current_layer; |
| 3086 | const char **menu_item; |
| 3087 | const char **menu_sub_item; |
| 3088 | char *flag_buf; |
| 3089 | cheat_entry *entry; |
| 3157 | 3090 | |
| 3158 | 3091 | /* first setting : always starts with root layer level */ |
| 3159 | 3092 | if(menu->first_time) |
| 3160 | 3093 | { |
| 3161 | | currentLayer = 0; |
| 3094 | current_layer = 0; |
| 3162 | 3095 | menu->first_time = 0; |
| 3163 | 3096 | } |
| 3164 | 3097 | |
| r2821 | r2822 | |
| 3166 | 3099 | request_strings(length + 2, 0, 0, 0); |
| 3167 | 3100 | |
| 3168 | 3101 | menu_item = menu_strings.main_list; |
| 3169 | | menu_subitem = menu_strings.sub_list; |
| 3170 | | flagBuf = menu_strings.flag_list; |
| 3102 | menu_sub_item = menu_strings.sub_list; |
| 3103 | flag_buf = menu_strings.flag_list; |
| 3171 | 3104 | |
| 3172 | | menuIndex = malloc_or_die(sizeof(INT8) * (length + 1)); |
| 3173 | | memset(menuIndex, 0, sizeof(INT8) * (length + 1)); |
| 3105 | menu_index = malloc_or_die(sizeof(INT8) * (length + 1)); |
| 3106 | memset(menu_index, 0, sizeof(INT8) * (length + 1)); |
| 3174 | 3107 | |
| 3175 | 3108 | /********** MENU CONSTRUCTION **********/ |
| 3176 | | for(i = 0; i < cheatListLength; i++) |
| 3109 | for(i = 0; i < cheat_list_length; i++) |
| 3177 | 3110 | { |
| 3178 | | CheatEntry * traverse = &cheatList[i]; |
| 3111 | cheat_entry *traverse = &cheat_list[i]; |
| 3179 | 3112 | |
| 3180 | 3113 | if(total >= fullMenuPageHeight) break; |
| 3181 | 3114 | |
| r2821 | r2822 | |
| 3186 | 3119 | traverse->flags &= ~kCheatFlag_LayerSelected; |
| 3187 | 3120 | } |
| 3188 | 3121 | |
| 3189 | | if(traverse->layerIndex == currentLayer) |
| 3122 | if(traverse->layer_index == current_layer) |
| 3190 | 3123 | { |
| 3191 | 3124 | /* ##### SEPARAOTR ##### */ |
| 3192 | 3125 | if(traverse->flags & kCheatFlag_Separator) |
| 3193 | 3126 | { |
| 3194 | 3127 | menu_item[total] = MENU_SEPARATOR_ITEM; |
| 3195 | | menu_subitem[total] = NULL; |
| 3196 | | menuIndex[total++] = i; |
| 3128 | menu_sub_item[total] = NULL; |
| 3129 | menu_index[total++] = i; |
| 3130 | traverse->flags &= ~kCheatFlag_RequestArrow; |
| 3197 | 3131 | } |
| 3198 | 3132 | else |
| 3199 | 3133 | { |
| r2821 | r2822 | |
| 3207 | 3141 | if(traverse->flags & kCheatFlag_HasWrongCode) |
| 3208 | 3142 | { |
| 3209 | 3143 | /* "LOCKED" if wrong code */ |
| 3210 | | menu_subitem[total] = "Locked"; |
| 3144 | menu_sub_item[total] = "Locked"; |
| 3211 | 3145 | traverse->selection = 0; |
| 3146 | traverse->flags &= ~kCheatFlag_RequestArrow; |
| 3212 | 3147 | } |
| 3213 | 3148 | else if(traverse->flags & kCheatFlag_Select) |
| 3214 | 3149 | { |
| 3215 | 3150 | /* label or "OFF" if label-selection though one-shot should ignore "OFF" */ |
| 3216 | 3151 | if(traverse->selection) |
| 3217 | | menu_subitem[total] = traverse->actionList[traverse->labelIndex[traverse->selection]].optionalName; |
| 3152 | menu_sub_item[total] = traverse->action_list[traverse->label_index[traverse->selection]].optional_name; |
| 3218 | 3153 | else |
| 3219 | | menu_subitem[total] = "Off"; |
| 3154 | menu_sub_item[total] = "Off"; |
| 3155 | |
| 3156 | traverse->flags |= kCheatFlag_RequestArrow; |
| 3220 | 3157 | } |
| 3221 | 3158 | else if(traverse->flags & kCheatFlag_ExtendComment) |
| 3222 | 3159 | { |
| 3223 | 3160 | /* "READ" if extend comment code */ |
| 3224 | | menu_subitem[total] = "Read"; |
| 3161 | menu_sub_item[total] = "Read"; |
| 3162 | traverse->flags &= ~kCheatFlag_RequestArrow; |
| 3225 | 3163 | } |
| 3226 | 3164 | else if(traverse->flags & kCheatFlag_LayerIndex) |
| 3227 | 3165 | { |
| 3228 | 3166 | /* ">>>" (next layer) if layer label code */ |
| 3229 | | menu_subitem[total] = ">>>"; |
| 3167 | menu_sub_item[total] = ">>>"; |
| 3168 | traverse->flags &= ~kCheatFlag_RequestArrow; |
| 3230 | 3169 | } |
| 3231 | | else if(!(traverse->flags & kCheatFlag_Null)) |
| 3170 | else if((traverse->flags & kCheatFlag_Null) == 0) |
| 3232 | 3171 | { |
| 3233 | 3172 | /* otherwise, add sub-items */ |
| 3234 | 3173 | if(traverse->flags & kCheatFlag_OneShot) |
| 3235 | | menu_subitem[total] = "Set"; |
| 3236 | | else if(traverse->flags & kCheatFlag_Active) |
| 3237 | | menu_subitem[total] = "On"; |
| 3174 | { |
| 3175 | menu_sub_item[total] = "Set"; |
| 3176 | traverse->flags &= ~kCheatFlag_RequestArrow; |
| 3177 | } |
| 3238 | 3178 | else |
| 3239 | | menu_subitem[total] = "Off"; |
| 3179 | { |
| 3180 | if(traverse->flags & kCheatFlag_Active) |
| 3181 | menu_sub_item[total] = "On"; |
| 3182 | else |
| 3183 | menu_sub_item[total] = "Off"; |
| 3184 | |
| 3185 | traverse->flags |= kCheatFlag_RequestArrow; |
| 3186 | } |
| 3240 | 3187 | } |
| 3241 | 3188 | |
| 3242 | 3189 | /* set highlight flag if comment is set */ |
| 3243 | 3190 | if(traverse->comment && traverse->comment[0]) |
| 3244 | | flagBuf[total] = 1; |
| 3191 | flag_buf[total] = 1; |
| 3245 | 3192 | else |
| 3246 | | flagBuf[total] = 0; |
| 3247 | | menuIndex[total++] = i; |
| 3193 | flag_buf[total] = 0; |
| 3194 | menu_index[total++] = i; |
| 3248 | 3195 | } |
| 3249 | 3196 | } |
| 3250 | 3197 | else if(traverse->flags & kCheatFlag_LayerIndex) |
| 3251 | 3198 | { |
| 3252 | | if(currentLayer == traverse->actionList[0].data) |
| 3199 | if(current_layer == traverse->action_list[0].data) |
| 3253 | 3200 | { |
| 3254 | 3201 | /* specified handling previous layer label code with "<<<" (previous layer) */ |
| 3255 | 3202 | if(traverse->comment) |
| 3256 | 3203 | menu_item[total] = traverse->comment; |
| 3257 | 3204 | else |
| 3258 | 3205 | menu_item[total] = "Return to Prior Layer"; |
| 3259 | | menu_subitem[total] = "<<<"; |
| 3260 | | flagBuf[total] = 0; |
| 3261 | | menuIndex[total++] = i; |
| 3206 | menu_sub_item[total] = "<<<"; |
| 3207 | flag_buf[total] = 0; |
| 3208 | menu_index[total++] = i; |
| 3209 | traverse->flags &= ~kCheatFlag_RequestArrow; |
| 3262 | 3210 | } |
| 3263 | 3211 | } |
| 3264 | 3212 | } |
| 3265 | 3213 | |
| 3266 | 3214 | /* if no code, set special message */ |
| 3267 | | if(!cheatListLength) |
| 3215 | if(cheat_list_length == 0) |
| 3268 | 3216 | { |
| 3269 | | if(foundCheatDatabase) |
| 3217 | if(found_database) |
| 3270 | 3218 | { |
| 3271 | 3219 | /* the database is found but no code */ |
| 3272 | | menu_item[total] = "there are no cheats for this game"; |
| 3273 | | menu_subitem[total] = NULL; |
| 3274 | | menuIndex[total] = total; |
| 3275 | | flagBuf[total++] = 0; |
| 3276 | | isEmpty = 1; |
| 3220 | menu_item[total] = "there are no cheats for this game"; |
| 3221 | menu_sub_item[total] = NULL; |
| 3222 | menu_index[total] = total; |
| 3223 | flag_buf[total++] = 0; |
| 3224 | is_empty = 1; |
| 3277 | 3225 | } |
| 3278 | 3226 | else |
| 3279 | 3227 | { |
| 3280 | 3228 | /* the database itself is not found */ |
| 3281 | | menu_item[total] = "cheat database not found"; |
| 3282 | | menu_subitem[total] = NULL; |
| 3283 | | menuIndex[total] = total; |
| 3284 | | flagBuf[total++] = 0; |
| 3229 | menu_item[total] = "cheat database not found"; |
| 3230 | menu_sub_item[total] = NULL; |
| 3231 | menu_index[total] = total; |
| 3232 | flag_buf[total++] = 0; |
| 3285 | 3233 | |
| 3286 | | menu_item[total] = "unzip it and place it in the MAME directory"; |
| 3287 | | menu_subitem[total] = NULL; |
| 3288 | | menuIndex[total] = total; |
| 3289 | | flagBuf[total++] = 0; |
| 3290 | | isEmpty = 2; |
| 3234 | menu_item[total] = "unzip it and place it in the MAME directory"; |
| 3235 | menu_sub_item[total] = NULL; |
| 3236 | menu_index[total] = total; |
| 3237 | flag_buf[total++] = 0; |
| 3238 | is_empty = 2; |
| 3291 | 3239 | } |
| 3292 | 3240 | } |
| 3293 | | else if(currentLayer && total == 1) |
| 3241 | else if(current_layer && total == 1) |
| 3294 | 3242 | { |
| 3295 | 3243 | /* selected layer doesn't have code */ |
| 3296 | | menu_item[total] = "selected layer doesn't have sub code"; |
| 3297 | | menu_subitem[total] = NULL; |
| 3298 | | menuIndex[total] = menuIndex[total - 1]; |
| 3299 | | flagBuf[total++] = 0; |
| 3300 | | isEmpty = 3; |
| 3244 | menu_item[total] = "selected layer doesn't have sub code"; |
| 3245 | menu_sub_item[total] = NULL; |
| 3246 | menu_index[total] = menu_index[total - 1]; |
| 3247 | flag_buf[total++] = 0; |
| 3248 | is_empty = 3; |
| 3301 | 3249 | } |
| 3302 | 3250 | |
| 3303 | 3251 | /* ##### RETURN ##### */ |
| 3304 | | if(currentLayer) |
| 3305 | | menu_item[total] = "Return to Root Layer"; |
| 3252 | if(current_layer) |
| 3253 | menu_item[total] = "Return to Root Layer"; |
| 3306 | 3254 | else |
| 3307 | | menu_item[total] = "Return to Prior Menu"; |
| 3308 | | menu_subitem[total] = NULL; |
| 3309 | | flagBuf[total++] = 0; |
| 3255 | menu_item[total] = "Return to Prior Menu"; |
| 3256 | menu_sub_item[total] = NULL; |
| 3257 | flag_buf[total++] = 0; |
| 3310 | 3258 | |
| 3311 | 3259 | /* ##### TERMINATE ARRAY ##### */ |
| 3312 | | menu_item[total] = NULL; |
| 3313 | | menu_subitem[total] = NULL; |
| 3314 | | flagBuf[total] = 0; |
| 3260 | menu_item[total] = NULL; |
| 3261 | menu_sub_item[total] = NULL; |
| 3262 | flag_buf[total] = 0; |
| 3315 | 3263 | |
| 3316 | 3264 | /* adjust cursor position */ |
| 3317 | | switch(isEmpty) |
| 3265 | switch(is_empty) |
| 3318 | 3266 | { |
| 3319 | 3267 | default: |
| 3320 | | ADJUST_CURSOR(menu->sel, total) |
| 3268 | ADJUST_CURSOR(menu->sel, total); |
| 3321 | 3269 | |
| 3322 | 3270 | /* if cursor is on comment code, skip it */ |
| 3323 | | while(menu->sel < total - 1 && (cheatList[menuIndex[menu->sel]].flags & kCheatFlag_Null)) |
| 3271 | while(menu->sel < total - 1 && (cheat_list[menu_index[menu->sel]].flags & kCheatFlag_Null)) |
| 3324 | 3272 | menu->sel++; |
| 3325 | 3273 | break; |
| 3326 | 3274 | |
| r2821 | r2822 | |
| 3336 | 3284 | menu->sel = 0; |
| 3337 | 3285 | } |
| 3338 | 3286 | |
| 3287 | /* set selected item's cheat entry */ |
| 3288 | if(is_empty == 0 && menu->sel < total - 1) |
| 3289 | { |
| 3290 | entry = &cheat_list[menu_index[menu->sel]]; |
| 3291 | |
| 3292 | if(entry->flags & kCheatFlag_Null) |
| 3293 | entry = NULL; |
| 3294 | |
| 3295 | if(entry->flags & kCheatFlag_Separator) |
| 3296 | entry = NULL; |
| 3297 | |
| 3298 | if(entry->flags & kCheatFlag_RequestArrow) |
| 3299 | request_arrow = 3; |
| 3300 | } |
| 3301 | else |
| 3302 | entry = NULL; |
| 3303 | |
| 3339 | 3304 | /* draw it */ |
| 3340 | | old_style_menu(menu_item, menu_subitem, flagBuf, menu->sel, 3); |
| 3305 | old_style_menu(menu_item, menu_sub_item, flag_buf, menu->sel, request_arrow); |
| 3341 | 3306 | |
| 3342 | 3307 | /********** KEY HANDLING **********/ |
| 3343 | 3308 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 3344 | 3309 | { |
| 3345 | | switch(isEmpty) |
| 3310 | switch(is_empty) |
| 3346 | 3311 | { |
| 3347 | 3312 | default: |
| 3348 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 3349 | | if(cheatListLength) |
| 3313 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 3314 | |
| 3315 | if(cheat_list_length) |
| 3350 | 3316 | { |
| 3351 | 3317 | /* if cursor is on comment code, skip it */ |
| 3352 | | for(i = 0; (i < fullMenuPageHeight / 2) && menu->sel != total - 1 && (cheatList[menuIndex[menu->sel]].flags & kCheatFlag_Null); i++) |
| 3318 | for(i = 0; (i < fullMenuPageHeight / 2) && menu->sel != total - 1 && (cheat_list[menu_index[menu->sel]].flags & kCheatFlag_Null); i++) |
| 3353 | 3319 | { |
| 3354 | 3320 | if(--menu->sel < 0) |
| 3355 | 3321 | menu->sel = total - 1; |
| r2821 | r2822 | |
| 3369 | 3335 | } |
| 3370 | 3336 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 3371 | 3337 | { |
| 3372 | | switch(isEmpty) |
| 3338 | switch(is_empty) |
| 3373 | 3339 | { |
| 3374 | 3340 | default: |
| 3375 | | CURSOR_TO_NEXT(menu->sel, total) |
| 3376 | | if(cheatListLength) |
| 3341 | CURSOR_TO_NEXT(menu->sel, total); |
| 3342 | |
| 3343 | if(cheat_list_length) |
| 3377 | 3344 | { |
| 3378 | 3345 | /* if cursor is on comment code, skip it */ |
| 3379 | | for(i = 0; (i < fullMenuPageHeight / 2) && menu->sel < total - 1 && (cheatList[menuIndex[menu->sel]].flags & kCheatFlag_Null); i++) |
| 3346 | for(i = 0; (i < fullMenuPageHeight / 2) && menu->sel < total - 1 && (cheat_list[menu_index[menu->sel]].flags & kCheatFlag_Null); i++) |
| 3380 | 3347 | menu->sel++; |
| 3381 | 3348 | } |
| 3382 | 3349 | |
| r2821 | r2822 | |
| 3392 | 3359 | } |
| 3393 | 3360 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 3394 | 3361 | { |
| 3395 | | CURSOR_PAGE_UP(menu->sel) |
| 3362 | CURSOR_PAGE_UP(menu->sel); |
| 3396 | 3363 | } |
| 3397 | 3364 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 3398 | 3365 | { |
| 3399 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 3366 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 3400 | 3367 | } |
| 3401 | 3368 | |
| 3402 | | if(menu->sel >= 0 && menu->sel < total - 1) |
| 3403 | | entry = &cheatList[menuIndex[menu->sel]]; |
| 3404 | | else |
| 3405 | | entry = NULL; |
| 3406 | | |
| 3407 | | if(entry && !(entry->flags & kCheatFlag_Null) && !(entry->flags & kCheatFlag_ExtendComment) && !(entry->flags & kCheatFlag_HasWrongCode)) |
| 3369 | if(entry && (entry->flags & kCheatFlag_Null) == 0 && (entry->flags & kCheatFlag_ExtendComment) == 0&& (entry->flags & kCheatFlag_HasWrongCode) == 0) |
| 3408 | 3370 | { |
| 3409 | 3371 | UINT8 toggle = 0; |
| 3410 | 3372 | |
| r2821 | r2822 | |
| 3412 | 3374 | { |
| 3413 | 3375 | if(entry->flags & kCheatFlag_Select) |
| 3414 | 3376 | { |
| 3415 | | if(TEST_FIELD(entry->actionList[entry->labelIndex[0]].type, LabelSelectUseSelector)) |
| 3377 | if(TEST_FIELD(entry->action_list[entry->label_index[0]].type, LabelSelectUseSelector)) |
| 3416 | 3378 | { |
| 3417 | 3379 | /* activate label selector */ |
| 3418 | 3380 | cheat_menu_stack_push(user_select_label_menu, menu->handler, menu->sel); |
| r2821 | r2822 | |
| 3421 | 3383 | { |
| 3422 | 3384 | /* select previous label */ |
| 3423 | 3385 | if(--entry->selection < 0) |
| 3424 | | entry->selection = entry->labelIndexLength - 1; |
| 3386 | entry->selection = entry->label_index_length - 1; |
| 3425 | 3387 | |
| 3426 | 3388 | /* NOTE : one shot cheat should not be activated by changing label */ |
| 3427 | | if(!entry->labelIndex[entry->selection]) |
| 3389 | if(entry->label_index[entry->selection] == 0) |
| 3428 | 3390 | DeactivateCheat(entry); |
| 3429 | | else if(!(entry->flags & kCheatFlag_OneShot) && !(entry->flags & kCheatFlag_Active)) |
| 3391 | else if((entry->flags & kCheatFlag_OneShot) == 0 && (entry->flags & kCheatFlag_Active) == 0) |
| 3430 | 3392 | ActivateCheat(entry); |
| 3431 | 3393 | } |
| 3432 | 3394 | } |
| r2821 | r2822 | |
| 3446 | 3408 | if(entry->flags & kCheatFlag_Select) |
| 3447 | 3409 | { |
| 3448 | 3410 | /* label-selection special handling */ |
| 3449 | | if(TEST_FIELD(entry->actionList[entry->labelIndex[0]].type, LabelSelectUseSelector)) |
| 3411 | if(TEST_FIELD(entry->action_list[entry->label_index[0]].type, LabelSelectUseSelector)) |
| 3450 | 3412 | { |
| 3451 | 3413 | /* activate label selector */ |
| 3452 | 3414 | cheat_menu_stack_push(user_select_label_menu, menu->handler, menu->sel); |
| r2821 | r2822 | |
| 3454 | 3416 | else |
| 3455 | 3417 | { |
| 3456 | 3418 | /* select next label index */ |
| 3457 | | if(++entry->selection >= entry->labelIndexLength) |
| 3419 | if(++entry->selection >= entry->label_index_length) |
| 3458 | 3420 | entry->selection = 0; |
| 3459 | 3421 | |
| 3460 | 3422 | /* NOTE : one shot cheat should not be activated by changing label */ |
| 3461 | | if(!entry->labelIndex[entry->selection]) |
| 3423 | if(entry->label_index[entry->selection] == 0) |
| 3462 | 3424 | DeactivateCheat(entry); |
| 3463 | | else if(!(entry->flags & kCheatFlag_OneShot) && !(entry->flags & kCheatFlag_Active)) |
| 3425 | else if((entry->flags & kCheatFlag_OneShot) == 0 && (entry->flags & kCheatFlag_Active) == 0) |
| 3464 | 3426 | ActivateCheat(entry); |
| 3465 | 3427 | } |
| 3466 | 3428 | } |
| r2821 | r2822 | |
| 3500 | 3462 | case 2: |
| 3501 | 3463 | { |
| 3502 | 3464 | /* go to next/previous layer level */ |
| 3503 | | if(entry->actionList[0].data == currentLayer) |
| 3504 | | currentLayer = entry->actionList[0].address; |
| 3465 | if(entry->action_list[0].data == current_layer) |
| 3466 | current_layer = entry->action_list[0].address; |
| 3505 | 3467 | else |
| 3506 | | currentLayer = entry->actionList[0].data; |
| 3468 | current_layer = entry->action_list[0].data; |
| 3507 | 3469 | |
| 3508 | 3470 | entry->flags |= kCheatFlag_LayerSelected; |
| 3509 | 3471 | } |
| r2821 | r2822 | |
| 3516 | 3478 | |
| 3517 | 3479 | if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 3518 | 3480 | { |
| 3519 | | if(!entry) |
| 3481 | if(entry == NULL) |
| 3520 | 3482 | { |
| 3521 | | if(currentLayer) |
| 3522 | | currentLayer = menu->sel = 0; |
| 3483 | if(current_layer) |
| 3484 | current_layer = menu->sel = 0; |
| 3523 | 3485 | else |
| 3524 | 3486 | menu->sel = -1; |
| 3525 | 3487 | } |
| 3526 | | else if(!(entry->flags & kCheatFlag_Null)) |
| 3488 | else if((entry->flags & kCheatFlag_Null) == 0) |
| 3527 | 3489 | { |
| 3528 | 3490 | if(ShiftKeyPressed() && (entry->comment && entry->comment[0])) |
| 3529 | 3491 | { |
| r2821 | r2822 | |
| 3532 | 3494 | } |
| 3533 | 3495 | else if(entry->flags & kCheatFlag_ExtendComment) |
| 3534 | 3496 | { |
| 3535 | | /* activate extend comment menu */ |
| 3497 | /* display extend comment */ |
| 3536 | 3498 | cheat_menu_stack_push(extend_comment_menu, menu->handler, menu->sel); |
| 3537 | 3499 | } |
| 3538 | 3500 | else if(entry->flags & kCheatFlag_UserSelect) |
| r2821 | r2822 | |
| 3540 | 3502 | /* activate value-selection menu */ |
| 3541 | 3503 | cheat_menu_stack_push(user_select_value_menu, menu->handler, menu->sel); |
| 3542 | 3504 | } |
| 3543 | | else if((entry->flags & kCheatFlag_Select) && TEST_FIELD(entry->actionList[entry->labelIndex[0]].type, LabelSelectUseSelector)) |
| 3505 | else if((entry->flags & kCheatFlag_Select) && TEST_FIELD(entry->action_list[entry->label_index[0]].type, LabelSelectUseSelector)) |
| 3544 | 3506 | { |
| 3545 | 3507 | /* activate label selector */ |
| 3546 | 3508 | cheat_menu_stack_push(user_select_label_menu, menu->handler, menu->sel); |
| r2821 | r2822 | |
| 3548 | 3510 | else if(entry->flags & kCheatFlag_LayerIndex) |
| 3549 | 3511 | { |
| 3550 | 3512 | /* go to next/previous layer level */ |
| 3551 | | if(entry->actionList[0].data == currentLayer) |
| 3552 | | currentLayer = entry->actionList[0].address; |
| 3513 | if(entry->action_list[0].data == current_layer) |
| 3514 | current_layer = entry->action_list[0].address; |
| 3553 | 3515 | else |
| 3554 | | currentLayer = entry->actionList[0].data; |
| 3516 | current_layer = entry->action_list[0].data; |
| 3555 | 3517 | |
| 3556 | 3518 | entry->flags |= kCheatFlag_LayerSelected; |
| 3557 | 3519 | } |
| r2821 | r2822 | |
| 3572 | 3534 | if(ShiftKeyPressed()) |
| 3573 | 3535 | { |
| 3574 | 3536 | /* shift + save : save all codes */ |
| 3575 | | for(i = 0; i < cheatListLength; i++) |
| 3576 | | SaveCheatCode(machine, &cheatList[i]); |
| 3537 | for(i = 0; i < cheat_list_length; i++) |
| 3538 | SaveCheatCode(machine, &cheat_list[i]); |
| 3577 | 3539 | |
| 3578 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 3579 | | messageType = kCheatMessage_AllCheatSaved; |
| 3540 | SET_MESSAGE(kCheatMessage_AllCheatSaved); |
| 3580 | 3541 | } |
| 3581 | 3542 | else if(ControlKeyPressed()) |
| 3582 | 3543 | { |
| 3583 | 3544 | /* ctrl + save : save activation key */ |
| 3584 | | SaveActivationKey(machine, entry, menuIndex[menu->sel]); |
| 3545 | SaveActivationKey(machine, entry, menu_index[menu->sel]); |
| 3585 | 3546 | } |
| 3586 | 3547 | else if(AltKeyPressed()) |
| 3587 | 3548 | { |
| 3588 | 3549 | /* alt + save : save pre-enable */ |
| 3589 | | SavePreEnable(machine, entry, menuIndex[menu->sel]); |
| 3550 | SavePreEnable(machine, entry, menu_index[menu->sel]); |
| 3590 | 3551 | } |
| 3591 | 3552 | } |
| 3592 | 3553 | else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT)) |
| 3593 | 3554 | { |
| 3594 | | AddCheatBefore(menuIndex[menu->sel]); |
| 3555 | add_cheat_before(menu_index[menu->sel]); |
| 3595 | 3556 | } |
| 3596 | 3557 | else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT)) |
| 3597 | 3558 | { |
| 3598 | 3559 | if(entry) |
| 3599 | | DeleteCheatAt(menuIndex[menu->sel]); |
| 3560 | delete_cheat_at(menu_index[menu->sel]); |
| 3600 | 3561 | else |
| 3601 | | { |
| 3602 | | messageType = kCheatMessage_FailedToDelete; |
| 3603 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 3604 | | } |
| 3562 | SET_MESSAGE(kCheatMessage_FailedToDelete); |
| 3605 | 3563 | } |
| 3606 | 3564 | else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT)) |
| 3607 | 3565 | { |
| r2821 | r2822 | |
| 3616 | 3574 | } |
| 3617 | 3575 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 3618 | 3576 | { |
| 3619 | | ReloadCheatDatabase(machine); |
| 3577 | reload_cheat_database(machine); |
| 3620 | 3578 | } |
| 3621 | 3579 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 3622 | 3580 | { |
| r2821 | r2822 | |
| 3624 | 3582 | menu->sel = -1; |
| 3625 | 3583 | } |
| 3626 | 3584 | |
| 3627 | | free(menuIndex); |
| 3585 | free(menu_index); |
| 3628 | 3586 | |
| 3629 | 3587 | return menu->sel + 1; |
| 3630 | 3588 | } |
| r2821 | r2822 | |
| 3636 | 3594 | static int add_edit_cheat_menu(running_machine *machine, cheat_menu_stack *menu) |
| 3637 | 3595 | { |
| 3638 | 3596 | int i; |
| 3639 | | UINT8 total = 0; |
| 3640 | | const char ** menu_item; |
| 3641 | | CheatEntry * entry; |
| 3597 | UINT8 total = 0; |
| 3598 | const char **menu_item; |
| 3599 | cheat_entry *entry; |
| 3642 | 3600 | |
| 3643 | 3601 | /* first setting : NONE */ |
| 3644 | 3602 | if(menu->first_time) |
| 3645 | 3603 | menu->first_time = 0; |
| 3646 | 3604 | |
| 3647 | 3605 | /* required items = total codes + return + terminator */ |
| 3648 | | request_strings(cheatListLength + 2, 0, 0, 0); |
| 3606 | request_strings(cheat_list_length + 2, 0, 0, 0); |
| 3649 | 3607 | menu_item = menu_strings.main_list; |
| 3650 | 3608 | |
| 3651 | 3609 | /********** MENU CONSTRUCTION **********/ |
| 3652 | | for(i = 0; i < cheatListLength; i++) |
| 3610 | for(i = 0; i < cheat_list_length; i++) |
| 3653 | 3611 | { |
| 3654 | | CheatEntry * traverse = &cheatList[i]; |
| 3612 | cheat_entry *traverse = &cheat_list[i]; |
| 3655 | 3613 | |
| 3656 | 3614 | /* ##### NAME ##### */ |
| 3657 | 3615 | if(traverse->name) |
| r2821 | r2822 | |
| 3667 | 3625 | menu_item[total] = NULL; |
| 3668 | 3626 | |
| 3669 | 3627 | /* adjust cursor position */ |
| 3670 | | ADJUST_CURSOR(menu->sel, total) |
| 3628 | ADJUST_CURSOR(menu->sel, total); |
| 3671 | 3629 | |
| 3672 | 3630 | /* draw it */ |
| 3673 | 3631 | old_style_menu(menu_item, NULL, NULL, menu->sel, 0); |
| 3674 | 3632 | |
| 3633 | /* set entry for selected item if valid, otherwise null (return item) */ |
| 3675 | 3634 | if(menu->sel < total - 1) |
| 3676 | | entry = &cheatList[menu->sel]; |
| 3635 | entry = &cheat_list[menu->sel]; |
| 3677 | 3636 | else |
| 3678 | 3637 | entry = NULL; |
| 3679 | 3638 | |
| 3680 | 3639 | /********** KEY HANDLING **********/ |
| 3681 | 3640 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 3682 | 3641 | { |
| 3683 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 3642 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 3684 | 3643 | } |
| 3685 | 3644 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 3686 | 3645 | { |
| 3687 | | CURSOR_TO_NEXT(menu->sel, total) |
| 3646 | CURSOR_TO_NEXT(menu->sel, total); |
| 3688 | 3647 | } |
| 3689 | 3648 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 3690 | 3649 | { |
| 3691 | | CURSOR_PAGE_UP(menu->sel) |
| 3650 | CURSOR_PAGE_UP(menu->sel); |
| 3692 | 3651 | } |
| 3693 | 3652 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 3694 | 3653 | { |
| 3695 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 3654 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 3696 | 3655 | } |
| 3697 | 3656 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 3698 | 3657 | { |
| r2821 | r2822 | |
| 3710 | 3669 | } |
| 3711 | 3670 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 3712 | 3671 | { |
| 3713 | | ReloadCheatDatabase(machine); |
| 3672 | reload_cheat_database(machine); |
| 3714 | 3673 | } |
| 3715 | 3674 | else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT)) |
| 3716 | 3675 | { |
| r2821 | r2822 | |
| 3726 | 3685 | } |
| 3727 | 3686 | else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT)) |
| 3728 | 3687 | { |
| 3729 | | AddCheatBefore(menu->sel); |
| 3688 | add_cheat_before(menu->sel); |
| 3730 | 3689 | } |
| 3731 | 3690 | else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT)) |
| 3732 | 3691 | { |
| 3733 | | DeleteCheatAt(menu->sel); |
| 3692 | delete_cheat_at(menu->sel); |
| 3734 | 3693 | } |
| 3735 | 3694 | else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT)) |
| 3736 | 3695 | { |
| 3737 | 3696 | if(ShiftKeyPressed()) |
| 3738 | 3697 | { |
| 3739 | 3698 | /* shift + save = save all codes */ |
| 3740 | | for(i = 0; i < cheatListLength; i++) |
| 3741 | | SaveCheatCode(machine, &cheatList[i]); |
| 3699 | for(i = 0; i < cheat_list_length; i++) |
| 3700 | SaveCheatCode(machine, &cheat_list[i]); |
| 3742 | 3701 | |
| 3743 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 3744 | | messageType = kCheatMessage_AllCheatSaved; |
| 3702 | SET_MESSAGE(kCheatMessage_AllCheatSaved); |
| 3745 | 3703 | } |
| 3746 | 3704 | else if(ControlKeyPressed()) |
| 3747 | 3705 | { |
| r2821 | r2822 | |
| 3797 | 3755 | int i; |
| 3798 | 3756 | UINT8 total = 0; |
| 3799 | 3757 | ui_menu_item menu_item[kMenu_Max + 1]; |
| 3800 | | CheatEntry *entry = &cheatList[menu->pre_sel]; |
| 3758 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 3801 | 3759 | |
| 3802 | 3760 | memset(menu_item, 0, sizeof(menu_item)); |
| 3803 | 3761 | |
| r2821 | r2822 | |
| 3829 | 3787 | menu_item[total].text = NULL; |
| 3830 | 3788 | |
| 3831 | 3789 | /* adjust cursor position */ |
| 3832 | | ADJUST_CURSOR(menu->sel, total) |
| 3790 | ADJUST_CURSOR(menu->sel, total); |
| 3833 | 3791 | |
| 3834 | 3792 | /* print it */ |
| 3835 | 3793 | ui_menu_draw(menu_item, total, menu->sel, NULL); |
| r2821 | r2822 | |
| 3837 | 3795 | /********** KEY HANDLING **********/ |
| 3838 | 3796 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 3839 | 3797 | { |
| 3840 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 3798 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 3841 | 3799 | } |
| 3842 | 3800 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 3843 | 3801 | { |
| 3844 | | CURSOR_TO_NEXT(menu->sel, total) |
| 3802 | CURSOR_TO_NEXT(menu->sel, total); |
| 3845 | 3803 | } |
| 3846 | 3804 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 3847 | 3805 | { |
| 3848 | | CURSOR_PAGE_UP(menu->sel) |
| 3806 | CURSOR_PAGE_UP(menu->sel); |
| 3849 | 3807 | } |
| 3850 | 3808 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 3851 | 3809 | { |
| 3852 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 3810 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 3853 | 3811 | } |
| 3854 | 3812 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 3855 | 3813 | { |
| r2821 | r2822 | |
| 3863 | 3821 | break; |
| 3864 | 3822 | |
| 3865 | 3823 | case kMenu_ReloadDatabase: |
| 3866 | | ReloadCheatDatabase(machine); |
| 3824 | reload_cheat_database(machine); |
| 3867 | 3825 | cheat_menu_stack_pop(); |
| 3868 | 3826 | break; |
| 3869 | 3827 | |
| r2821 | r2822 | |
| 3885 | 3843 | |
| 3886 | 3844 | case kMenu_SaveAllCodes: |
| 3887 | 3845 | { |
| 3888 | | for(i = 0; i < cheatListLength; i++) |
| 3889 | | SaveCheatCode(machine, &cheatList[i]); |
| 3846 | for(i = 0; i < cheat_list_length; i++) |
| 3847 | SaveCheatCode(machine, &cheat_list[i]); |
| 3890 | 3848 | |
| 3891 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 3892 | | messageType = kCheatMessage_AllCheatSaved; |
| 3849 | SET_MESSAGE(kCheatMessage_AllCheatSaved); |
| 3893 | 3850 | } |
| 3894 | 3851 | break; |
| 3895 | 3852 | |
| 3896 | 3853 | case kMenu_AddCode: |
| 3897 | | AddCheatBefore(menu->pre_sel); |
| 3854 | add_cheat_before(menu->pre_sel); |
| 3898 | 3855 | menu->sel = -1; |
| 3899 | 3856 | break; |
| 3900 | 3857 | |
| 3901 | 3858 | case kMenu_DeleteCode: |
| 3902 | | DeleteCheatAt(menu->pre_sel); |
| 3859 | delete_cheat_at(menu->pre_sel); |
| 3903 | 3860 | menu->sel = -1; |
| 3904 | 3861 | break; |
| 3905 | 3862 | |
| 3906 | 3863 | #ifdef MAME_DEBUG |
| 3907 | 3864 | case kMenu_ConvertFormat: |
| 3908 | | if(!(entry->flags & kCheatFlag_OldFormat)) |
| 3865 | if((entry->flags & kCheatFlag_OldFormat) == 0) |
| 3909 | 3866 | { |
| 3910 | | for(i = 0; i < entry->actionListLength; i++) |
| 3867 | /* new -> old (UNDERCONSTRUCTION) */ |
| 3868 | for(i = 0; i < entry->action_list_length; i++) |
| 3911 | 3869 | { |
| 3912 | | entry->actionList[i].flags |= kActionFlag_OldFormat; |
| 3913 | | UpdateCheatInfo(entry, 0); |
| 3870 | entry->action_list[i].flags |= kActionFlag_OldFormat; |
| 3871 | update_cheat_info(entry, 0); |
| 3914 | 3872 | } |
| 3915 | 3873 | } |
| 3916 | 3874 | else |
| 3917 | 3875 | { |
| 3918 | | for(i = 0; i < entry->actionListLength; i++) |
| 3876 | /* old -> new (UNDERCONSTRUCTION) */ |
| 3877 | for(i = 0; i < entry->action_list_length; i++) |
| 3919 | 3878 | { |
| 3920 | | entry->actionList[i].flags &= ~kActionFlag_OldFormat; |
| 3921 | | UpdateCheatInfo(entry, 0); |
| 3879 | entry->action_list[i].flags &= ~kActionFlag_OldFormat; |
| 3880 | update_cheat_info(entry, 0); |
| 3922 | 3881 | } |
| 3923 | 3882 | } |
| 3924 | 3883 | break; |
| r2821 | r2822 | |
| 3934 | 3893 | } |
| 3935 | 3894 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 3936 | 3895 | { |
| 3937 | | ReloadCheatDatabase(machine); |
| 3896 | reload_cheat_database(machine); |
| 3938 | 3897 | } |
| 3939 | 3898 | else if(input_ui_pressed(machine, IPT_UI_CANCEL) || input_ui_pressed(machine, IPT_UI_LEFT) || input_ui_pressed(machine, IPT_UI_RIGHT)) |
| 3940 | 3899 | { |
| r2821 | r2822 | |
| 4833 | 4792 | break; |
| 4834 | 4793 | |
| 4835 | 4794 | case kType_WatchSize: |
| 4836 | | action->originalDataField = (action->originalDataField & 0xFFFFFF00) | ((action->originalDataField - 0x00000001) & 0x000000FF); |
| 4837 | | action->data = action->originalDataField; |
| 4795 | action->originalData = (action->originalData & 0xFFFFFF00) | ((action->originalData - 0x00000001) & 0x000000FF); |
| 4796 | action->data = action->originalData; |
| 4838 | 4797 | break; |
| 4839 | 4798 | |
| 4840 | 4799 | case kType_WatchSkip: |
| 4841 | | action->originalDataField = (action->originalDataField & 0xFFFF00FF) | ((action->originalDataField - 0x00000100) & 0x0000FF00); |
| 4842 | | action->data = action->originalDataField; |
| 4800 | action->original_data = (action->originalData & 0xFFFF00FF) | ((action->originalData - 0x00000100) & 0x0000FF00); |
| 4801 | action->data = action->originalData; |
| 4843 | 4802 | break; |
| 4844 | 4803 | |
| 4845 | 4804 | case kType_WatchPerLine: |
| 4846 | | action->originalDataField = (action->originalDataField & 0xFF00FFFF) | ((action->originalDataField - 0x00010000) & 0x00FF0000); |
| 4847 | | action->data = action->originalDataField; |
| 4805 | action->originalData = (action->originalData & 0xFF00FFFF) | ((action->originalData - 0x00010000) & 0x00FF0000); |
| 4806 | action->data = action->originalData; |
| 4848 | 4807 | break; |
| 4849 | 4808 | |
| 4850 | 4809 | case kType_WatchAddValue: |
| 4851 | | action->originalDataField = (action->originalDataField & 0x00FFFFFF) | ((action->originalDataField - 0x01000000) & 0xFF000000); |
| 4852 | | action->data = action->originalDataField; |
| 4810 | action->original_data = (action->originalData & 0x00FFFFFF) | ((action->originalData - 0x01000000) & 0xFF000000); |
| 4811 | action->data = action->originalData; |
| 4853 | 4812 | break; |
| 4854 | 4813 | |
| 4855 | 4814 | case kType_WatchFormat: |
| r2821 | r2822 | |
| 4912 | 4871 | break; |
| 4913 | 4872 | |
| 4914 | 4873 | case kType_Data: |
| 4915 | | action->originalDataField -= 1; |
| 4916 | | action->originalDataField &= info->extraData; |
| 4917 | | action->data = action->originalDataField; |
| 4874 | action->originalData -= 1; |
| 4875 | action->originalData &= info->extraData; |
| 4876 | action->data = action->originalData; |
| 4918 | 4877 | break; |
| 4919 | 4878 | |
| 4920 | 4879 | case kType_UserSelect: |
| r2821 | r2822 | |
| 5133 | 5092 | break; |
| 5134 | 5093 | |
| 5135 | 5094 | case kType_WatchSize: |
| 5136 | | action->originalDataField = (action->originalDataField & 0xFFFFFF00) | ((action->originalDataField + 0x00000001) & 0x000000FF); |
| 5137 | | action->data = action->originalDataField; |
| 5095 | action->originalData = (action->originalData & 0xFFFFFF00) | ((action->originalData + 0x00000001) & 0x000000FF); |
| 5096 | action->data = action->originalData; |
| 5138 | 5097 | break; |
| 5139 | 5098 | |
| 5140 | 5099 | case kType_WatchSkip: |
| 5141 | | action->originalDataField = (action->originalDataField & 0xFFFF00FF) | ((action->originalDataField + 0x00000100) & 0x0000FF00); |
| 5142 | | action->data = action->originalDataField; |
| 5100 | action->originalData = (action->originalData & 0xFFFF00FF) | ((action->originalData + 0x00000100) & 0x0000FF00); |
| 5101 | action->data = action->originalData; |
| 5143 | 5102 | break; |
| 5144 | 5103 | |
| 5145 | 5104 | case kType_WatchPerLine: |
| 5146 | | action->originalDataField = (action->originalDataField & 0xFF00FFFF) | ((action->originalDataField + 0x00010000) & 0x00FF0000); |
| 5147 | | action->data = action->originalDataField; |
| 5105 | action->originalData = (action->originalData & 0xFF00FFFF) | ((action->originalData + 0x00010000) & 0x00FF0000); |
| 5106 | action->data = action->originalData; |
| 5148 | 5107 | break; |
| 5149 | 5108 | |
| 5150 | 5109 | case kType_WatchAddValue: |
| 5151 | | action->originalDataField = (action->originalDataField & 0x00FFFFFF) | ((action->originalDataField + 0x01000000) & 0xFF000000); |
| 5152 | | action->data = action->originalDataField; |
| 5110 | action->originalData = (action->originalData & 0x00FFFFFF) | ((action->originalData + 0x01000000) & 0xFF000000); |
| 5111 | action->data = action->originalData; |
| 5153 | 5112 | break; |
| 5154 | 5113 | |
| 5155 | 5114 | case kType_WatchFormat: |
| r2821 | r2822 | |
| 5218 | 5177 | break; |
| 5219 | 5178 | |
| 5220 | 5179 | case kType_Data: |
| 5221 | | action->originalDataField += 1; |
| 5222 | | action->originalDataField &= info->extraData; |
| 5223 | | action->data = action->originalDataField; |
| 5180 | action->originalData += 1; |
| 5181 | action->originalData &= info->extraData; |
| 5182 | action->data = action->originalData; |
| 5224 | 5183 | break; |
| 5225 | 5184 | |
| 5226 | 5185 | case kType_UserSelect: |
| r2821 | r2822 | |
| 5491 | 5450 | |
| 5492 | 5451 | case kType_WatchSize: |
| 5493 | 5452 | { |
| 5494 | | UINT32 temp = (action->originalDataField >> 0) & 0xFF; |
| 5453 | UINT32 temp = (action->originalData >> 0) & 0xFF; |
| 5495 | 5454 | |
| 5496 | 5455 | temp++; |
| 5497 | 5456 | temp = do_edit_hex_field(machine, temp) & 0xFF; |
| 5498 | 5457 | temp--; |
| 5499 | 5458 | |
| 5500 | | action->originalDataField = (action->originalDataField & 0xFFFFFF00) | ((temp << 0) & 0x000000FF); |
| 5501 | | action->data = action->originalDataField; |
| 5459 | action->originalData = (action->originalData & 0xFFFFFF00) | ((temp << 0) & 0x000000FF); |
| 5460 | action->data = action->originalData; |
| 5502 | 5461 | } |
| 5503 | 5462 | break; |
| 5504 | 5463 | |
| 5505 | 5464 | case kType_WatchSkip: |
| 5506 | 5465 | { |
| 5507 | | UINT32 temp = (action->originalDataField >> 8) & 0xFF; |
| 5466 | UINT32 temp = (action->originalData >> 8) & 0xFF; |
| 5508 | 5467 | |
| 5509 | 5468 | temp = do_edit_hex_field(machine, temp) & 0xFF; |
| 5510 | 5469 | |
| 5511 | | action->originalDataField = (action->originalDataField & 0xFFFF00FF) | ((temp << 8) & 0x0000FF00); |
| 5512 | | action->data = action->originalDataField; |
| 5470 | action->originalData = (action->originalData & 0xFFFF00FF) | ((temp << 8) & 0x0000FF00); |
| 5471 | action->data = action->originalData; |
| 5513 | 5472 | } |
| 5514 | 5473 | break; |
| 5515 | 5474 | |
| 5516 | 5475 | case kType_WatchPerLine: |
| 5517 | 5476 | { |
| 5518 | | UINT32 temp = (action->originalDataField >> 16) & 0xFF; |
| 5477 | UINT32 temp = (action->originalData >> 16) & 0xFF; |
| 5519 | 5478 | |
| 5520 | 5479 | temp = do_edit_hex_field(machine, temp) & 0xFF; |
| 5521 | 5480 | |
| 5522 | | action->originalDataField = (action->originalDataField & 0xFF00FFFF) | ((temp << 16) & 0x00FF0000); |
| 5523 | | action->data = action->originalDataField; |
| 5481 | action->originalData = (action->originalData & 0xFF00FFFF) | ((temp << 16) & 0x00FF0000); |
| 5482 | action->data = action->originalData; |
| 5524 | 5483 | } |
| 5525 | 5484 | break; |
| 5526 | 5485 | |
| 5527 | 5486 | case kType_WatchAddValue: |
| 5528 | 5487 | { |
| 5529 | | UINT32 temp = (action->originalDataField >> 24) & 0xFF; |
| 5488 | UINT32 temp = (action->originalData >> 24) & 0xFF; |
| 5530 | 5489 | |
| 5531 | 5490 | temp = DoEditHexFieldSigned(temp, 0xFFFFFF80) & 0xFF; |
| 5532 | 5491 | |
| 5533 | | action->originalDataField = (action->originalDataField & 0x00FFFFFF) | ((temp << 24) & 0xFF000000); |
| 5534 | | action->data = action->originalDataField; |
| 5492 | action->originalData = (action->originalData & 0x00FFFFFF) | ((temp << 24) & 0xFF000000); |
| 5493 | action->data = action->originalData; |
| 5535 | 5494 | } |
| 5536 | 5495 | break; |
| 5537 | 5496 | |
| r2821 | r2822 | |
| 5588 | 5547 | break; |
| 5589 | 5548 | |
| 5590 | 5549 | case kType_Data: |
| 5591 | | action->originalDataField = do_edit_hex_field(machine, action->originalDataField); |
| 5592 | | action->originalDataField &= info->extraData; |
| 5593 | | action->data = action->originalDataField; |
| 5550 | action->originalData = do_edit_hex_field(machine, action->originalData); |
| 5551 | action->originalData &= info->extraData; |
| 5552 | action->data = action->originalData; |
| 5594 | 5553 | break; |
| 5595 | 5554 | |
| 5596 | 5555 | case kType_Address: |
| r2821 | r2822 | |
| 5615 | 5574 | |
| 5616 | 5575 | entry->actionList[info->sub_cheat].extendData = ~0; |
| 5617 | 5576 | |
| 5618 | | for(i = 0; i < entry->actionListLength; i++) |
| 5577 | for(i = 0; i < entry->action_list_length; i++) |
| 5619 | 5578 | { |
| 5620 | | CheatAction * action = &entry->actionList[i]; |
| 5579 | cheat_action *action = &entry->action_list[i]; |
| 5621 | 5580 | |
| 5622 | 5581 | if(i) |
| 5623 | 5582 | SET_MASK_FIELD(action->type, LinkEnable); |
| r2821 | r2822 | |
| 5630 | 5589 | if(!info->sub_cheat) |
| 5631 | 5590 | { |
| 5632 | 5591 | /* don't delete MASTER Action due to crash */ |
| 5633 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 5634 | | messageType = kCheatMessage_FailedToDelete; |
| 5592 | SET_MESSAGE(kCheatMessage_FailedToDelete); |
| 5635 | 5593 | } |
| 5636 | 5594 | else |
| 5637 | 5595 | DeleteActionAt(entry, info->sub_cheat); |
| r2821 | r2822 | |
| 5651 | 5609 | if(entry->flags & kCheatFlag_Select) |
| 5652 | 5610 | BuildLabelIndexTable(entry); |
| 5653 | 5611 | |
| 5654 | | CheckCodeFormat(entry); |
| 5612 | check_code_format(entry); |
| 5655 | 5613 | |
| 5656 | 5614 | editActive = 0; |
| 5657 | 5615 | dirty = 1; |
| r2821 | r2822 | |
| 5674 | 5632 | "Program", "Data Space", "I/O Space", "Opcode RAM", "Mapped Memory", "Direct Memory", "EEPROM" }; |
| 5675 | 5633 | |
| 5676 | 5634 | static const char *const kCodeTypeNames[] = { |
| 5677 | | "Write", "PDWWrite", "RWrite", "IWrite", "CWrite", "VWrite", "VRWrite", "Move", "Branch", "Loop", |
| 5678 | | "Unused 1", "Unused 2", "Unused 3", "Unused 4", |
| 5679 | | "Popup", "Watch" }; |
| 5635 | "Write", "IWrite", "RWrite", "CWrite", "CBit", "PDWWrite", "Move", "Branch", "Loop", "Popup", "Watch" }; |
| 5680 | 5636 | |
| 5681 | 5637 | static const char *const kCustomCodeTypeNames[] = { |
| 5682 | | "No Action", "Comment", "Separator", "Label Select", "Layer", |
| 5638 | "NOP", "Comment", "Separator", "Label Select", "Layer Tag", |
| 5683 | 5639 | "Unused 1", "Unused2", "Unused 3", |
| 5684 | 5640 | /* NOTE : the following command codes should be removed when database is loaded */ |
| 5685 | 5641 | "Activation Key 1", "Activation Key 2", "Pre-enable", "Overclock", "Refresh Rate" }; |
| 5686 | 5642 | |
| 5643 | static const char *const kIWriteParameterNames[] = { |
| 5644 | "Write", "Bit Set", "Bit Clear", "Limited Mask" }; |
| 5645 | |
| 5646 | static const char *const kCBitParameterNames[] = { |
| 5647 | "Bit Set", "Bit Clear", "Limited Mask" }; |
| 5648 | |
| 5687 | 5649 | static const char *const kConditionNames[] = { |
| 5688 | | "EQ", "NE", "LS", "LSEQ", "GR", "GREQ", "BSET", "BCLR", |
| 5650 | "Equal", "Not Equal", "Less", "Less or Equal", "Greater", "Greater or Equal", "Bit Set", "Bit Clear", |
| 5689 | 5651 | "Unused 1", "Unused 2", "Unused 3", "Unused 4", |
| 5690 | | "PVAL", "KEY", "KEYR", "TRUE" }; |
| 5652 | "Previous Value", "Key Pressed", "Key Hold", "TRUE" }; |
| 5691 | 5653 | |
| 5654 | static const char *const kCBitConditionNames[] = { |
| 5655 | "Bis Set", "Bit Clear" }; |
| 5656 | |
| 5692 | 5657 | static const char *const kDataNames[] = { |
| 5693 | | "Data", "1st Data", "Data", "Data", "Data", "Max Data", "Max Data", "Add Value", "Comparison", "Count", |
| 5694 | | "-----", "-----", "-----", "-----", |
| 5695 | | "Comparison", "-----" }; |
| 5658 | "Data", "Data", "Data", "Data", "Bit", "1st Data", "Add Value", "Jump Index", "-----", "-----", "-----" }; |
| 5696 | 5659 | |
| 5697 | 5660 | static const char *const kPopupOptionNames[] = { |
| 5698 | 5661 | "Label", "Value", "Label + Value", "Value + Label" }; |
| 5699 | 5662 | |
| 5700 | 5663 | enum{ |
| 5701 | | kViewMenu_Header = 1, // format : total index / current index |
| 5702 | | kViewMenu_CodeLayer, // internal value of code and layer index |
| 5703 | | kViewMenu_Name, // master code = entry->name, linked code = action->optionalName |
| 5664 | kViewMenu_Header = 1, /* format : [total index / current index] */ |
| 5665 | kViewMenu_Layer, /* internal value of code and layer index */ |
| 5666 | kViewMenu_Name, /* master code = entry->name, linked code = action->optionalName */ |
| 5704 | 5667 | kViewMenu_Comment, |
| 5705 | 5668 | kViewMenu_ActivationKey1, |
| 5706 | 5669 | kViewMenu_ActivationKey2, |
| 5707 | | // if(!CustomCode) |
| 5708 | | kViewMenu_CodeType, // CodeType - CodeParameter / Return |
| 5709 | | kViewMenu_CPURegion, // add Address Space if CPU region |
| 5670 | /* if(CustomCode == 0) */ |
| 5671 | kViewMenu_CPURegion, /* add address space if CPU region */ |
| 5672 | kViewMenu_CodeType, |
| 5673 | /* if(CodeType == IWrite) */ |
| 5674 | kViewMenu_IWriteParameter, |
| 5675 | /* if(CodeType == CWrite, CBit, Branch, Popup) */ |
| 5676 | kViewMenu_Condition, |
| 5677 | /* if(CodeType == CBit) */ |
| 5678 | kViewMenu_CBitParameter, |
| 5679 | kViewMenu_CBitCondition, |
| 5680 | /* if(CodeType == Watch) */ |
| 5681 | kViewMenu_WatchParameter, |
| 5682 | /* if(CodeType == Popup) */ |
| 5683 | kViewMenu_PopupParameter, |
| 5684 | /* if(CodeType == RWrite, CWrite, CBit, Branch, Popup */ |
| 5685 | kViewMenu_Extend, |
| 5710 | 5686 | kViewMenu_Address, |
| 5711 | | kViewMenu_Size, // address size / index size |
| 5687 | kViewMenu_AddressSize, |
| 5688 | /* if(CodeType == IWrite, Move) */ |
| 5689 | kViewMenu_IndexOffset, |
| 5690 | kViewMenu_IndexAddressSize, |
| 5691 | /* if(CodeType == Move) */ |
| 5692 | kViewMenu_MoveParameter, /* variable 0-3 */ |
| 5712 | 5693 | kViewMenu_Data, |
| 5713 | | kViewMenu_Extend, |
| 5714 | | // if(ValueSelect) |
| 5694 | /* if(LimitedMask) */ |
| 5695 | kViewMenu_LimitedMask, /* for IWrite, CBit */ |
| 5696 | /* if(CodeType == PDWWRite) */ |
| 5697 | kViewMenu_SubData, |
| 5698 | kViewMenu_SubDataSize, |
| 5699 | /* if(ValueSelect) */ |
| 5715 | 5700 | kViewMenu_ValueSelectOptions, |
| 5716 | | // if(Popup) |
| 5717 | | kViewMenu_PopupOptions, |
| 5718 | | // if(CopyLink) |
| 5719 | | kViewMenu_CopyLinkOptions, |
| 5720 | | kViewMenu_Options, // One-shot, Delay, Prefill, RestoreValue |
| 5721 | | // if(CustomCode) |
| 5722 | | //if(LayerIndex) |
| 5701 | kViewMenu_Options, /* One-shot, Delay, Return, Prefill, RestoreValue */ |
| 5702 | /* if(CustomCode) */ |
| 5703 | /* if(LayerIndex) */ |
| 5723 | 5704 | kViewMenu_LayerDisplayLevel, |
| 5724 | 5705 | kViewMenu_LayerSetLevel, |
| 5725 | 5706 | kViewMenu_LayerSetLength, |
| r2821 | r2822 | |
| 5729 | 5710 | int total = 0; |
| 5730 | 5711 | int menu_index[kViewMenu_Max] = { 0 }; |
| 5731 | 5712 | static int page_index = 0; |
| 5732 | | UINT8 address_length = 0; |
| 5733 | | UINT8 address_size = 0; |
| 5734 | | const char ** menu_item; |
| 5735 | | const char ** menu_sub_item; |
| 5736 | | char * flag_buf; |
| 5737 | | char * header; |
| 5738 | | char * buf_code; |
| 5739 | | char * buf_type; |
| 5740 | | char * buf_cpu; |
| 5741 | | char * buf_address; |
| 5742 | | char * buf_size; |
| 5743 | | char * buf_data; |
| 5744 | | char * buf_extend; |
| 5745 | | char * buf_options; |
| 5746 | | char * buf_code_type_options; |
| 5747 | | CheatEntry * entry = &cheatList[menu->pre_sel]; |
| 5748 | | CheatAction * action = NULL; |
| 5749 | | astring * activation_key_string1 = NULL; |
| 5750 | | astring * activation_key_string2 = NULL; |
| 5713 | INT8 code_type = 0; |
| 5714 | INT8 address_length = 0; |
| 5715 | INT8 address_size = 0; |
| 5716 | INT8 request_arrow = 0; |
| 5717 | const char **menu_item; |
| 5718 | const char **menu_sub_item; |
| 5719 | char *flag_buf; |
| 5720 | char *header; |
| 5721 | char *buf_code; |
| 5722 | char *buf_type; |
| 5723 | char *buf_cpu; |
| 5724 | char *buf_address; |
| 5725 | char *buf_size; |
| 5726 | char *buf_sub_size; |
| 5727 | char *buf_data; |
| 5728 | char *buf_extend; |
| 5729 | char *buf_limited_mask; |
| 5730 | char *buf_options; |
| 5731 | char *buf_code_type_options; |
| 5732 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 5733 | cheat_action *action = NULL; |
| 5734 | astring *activation_key_string1 = NULL; |
| 5735 | astring *activation_key_string2 = NULL; |
| 5751 | 5736 | |
| 5752 | 5737 | /* first setting : forced set page as 0 when first open */ |
| 5753 | 5738 | if(menu->first_time) |
| r2821 | r2822 | |
| 5756 | 5741 | menu->first_time = 0; |
| 5757 | 5742 | } |
| 5758 | 5743 | |
| 5759 | | action = &entry->actionList[page_index]; |
| 5744 | action = &entry->action_list[page_index]; |
| 5745 | code_type = EXTRACT_FIELD(action->type, CodeType); |
| 5760 | 5746 | address_length = get_address_length(action->region); |
| 5761 | 5747 | address_size = EXTRACT_FIELD(action->type, AddressSize); |
| 5762 | 5748 | |
| 5763 | | /* required items = (total items + return + terminator) & (strings buf * 10) */ |
| 5764 | | request_strings(kViewMenu_Max + 2, 0x0A, 32, 0); |
| 5749 | /* required items = (total items + return + terminator) + (strings buf * 12) */ |
| 5750 | request_strings(kViewMenu_Max + 2, 12, 32, 0); |
| 5765 | 5751 | menu_item = menu_strings.main_list; |
| 5766 | 5752 | menu_sub_item = menu_strings.sub_list; |
| 5767 | 5753 | flag_buf = menu_strings.flag_list; |
| 5768 | 5754 | header = menu_strings.main_strings[0]; |
| 5769 | 5755 | buf_code = menu_strings.main_strings[1]; |
| 5770 | | buf_type = menu_strings.main_strings[2]; |
| 5756 | buf_type = menu_strings.main_strings[1]; |
| 5771 | 5757 | buf_cpu = menu_strings.main_strings[3]; |
| 5772 | 5758 | buf_address = menu_strings.main_strings[4]; |
| 5773 | 5759 | buf_size = menu_strings.main_strings[5]; |
| 5774 | | buf_data = menu_strings.main_strings[6]; |
| 5775 | | buf_extend = menu_strings.main_strings[7]; |
| 5776 | | buf_options = menu_strings.main_strings[8]; |
| 5777 | | buf_code_type_options = menu_strings.main_strings[9]; |
| 5760 | buf_sub_size = menu_strings.main_strings[6]; |
| 5761 | buf_data = menu_strings.main_strings[7]; |
| 5762 | buf_extend = menu_strings.main_strings[8]; |
| 5763 | buf_limited_mask = menu_strings.main_strings[9]; |
| 5764 | buf_options = menu_strings.main_strings[10]; |
| 5765 | buf_code_type_options = menu_strings.main_strings[11]; |
| 5778 | 5766 | |
| 5779 | 5767 | memset(flag_buf, 0, kViewMenu_Max + 2); |
| 5780 | 5768 | |
| 5781 | 5769 | /********** MENU CONSTRUCTION **********/ |
| 5782 | 5770 | /* ##### HEADER ##### */ |
| 5783 | | sprintf(header, "[%2.2d/%2.2d]", page_index + 1, entry->actionListLength); |
| 5771 | sprintf(header, "%2.2d/%2.2d", page_index + 1, entry->action_list_length); |
| 5784 | 5772 | ADD_MENU_3_ITEMS("Page", header, kViewMenu_Header); |
| 5785 | 5773 | |
| 5786 | | /* ##### CODE / LAYER INDEX ##### */ |
| 5787 | | sprintf(buf_code, "%8.8X / %2.2X", action->type, entry->layerIndex); |
| 5788 | | ADD_MENU_3_ITEMS("Code / Layer", buf_code, kViewMenu_CodeLayer); |
| 5774 | /* ##### LAYER INDEX ##### */ |
| 5775 | sprintf(buf_code, "%2.2X", entry->layer_index); |
| 5776 | ADD_MENU_3_ITEMS("Layer Index", buf_code, kViewMenu_Layer); |
| 5789 | 5777 | |
| 5790 | 5778 | /* ##### NAME ##### */ |
| 5791 | 5779 | if(entry->name) |
| 5792 | 5780 | { |
| 5793 | | if(page_index) |
| 5794 | | ADD_MENU_3_ITEMS("Name", action->optionalName, kViewMenu_Name); |
| 5795 | | else |
| 5796 | | ADD_MENU_3_ITEMS("Name", entry->name, kViewMenu_Name); |
| 5781 | /* NOTE : master code is from cheat entry and others are from cheat action */ |
| 5782 | ADD_MENU_3_ITEMS("Name", page_index ? action->optional_name : entry->name, kViewMenu_Name); |
| 5797 | 5783 | } |
| 5798 | 5784 | else |
| 5799 | 5785 | ADD_MENU_3_ITEMS("Name", "< none >", kViewMenu_Name); |
| r2821 | r2822 | |
| 5808 | 5794 | if(entry->flags & kCheatFlag_HasActivationKey1) |
| 5809 | 5795 | { |
| 5810 | 5796 | activation_key_string1 = astring_alloc(); |
| 5811 | | ADD_MENU_3_ITEMS("Activation Key", astring_c(input_code_name(activation_key_string1, entry->activationKey1)), kViewMenu_ActivationKey1); |
| 5797 | ADD_MENU_3_ITEMS("Activation Key - Prev", astring_c(input_code_name(activation_key_string1, entry->activation_key1)), kViewMenu_ActivationKey1); |
| 5812 | 5798 | } |
| 5799 | |
| 5800 | if(entry->flags & kCheatFlag_HasActivationKey2) |
| 5801 | { |
| 5802 | activation_key_string2 = astring_alloc(); |
| 5803 | ADD_MENU_3_ITEMS("Activation Key - Next", astring_c(input_code_name(activation_key_string2, entry->activation_key2)), kViewMenu_ActivationKey2); |
| 5804 | } |
| 5813 | 5805 | } |
| 5814 | 5806 | else |
| 5815 | 5807 | { |
| 5816 | 5808 | if(entry->flags & kCheatFlag_HasActivationKey1) |
| 5817 | 5809 | { |
| 5818 | 5810 | activation_key_string1 = astring_alloc(); |
| 5819 | | ADD_MENU_3_ITEMS("Activation Key - Prev", astring_c(input_code_name(activation_key_string1, entry->activationKey1)), kViewMenu_ActivationKey1); |
| 5811 | ADD_MENU_3_ITEMS("Activation Key", astring_c(input_code_name(activation_key_string1, entry->activation_key1)), kViewMenu_ActivationKey1); |
| 5820 | 5812 | } |
| 5813 | } |
| 5821 | 5814 | |
| 5822 | | if(entry->flags & kCheatFlag_HasActivationKey2) |
| 5815 | /* ##### CPU/REGION ##### */ |
| 5816 | if((action->flags & kActionFlag_Custom) == 0) |
| 5817 | { |
| 5818 | if(action->region < REGION_INVALID) |
| 5823 | 5819 | { |
| 5824 | | activation_key_string2 = astring_alloc(); |
| 5825 | | ADD_MENU_3_ITEMS("Activation Key - Next", astring_c(input_code_name(activation_key_string2, entry->activationKey2)), kViewMenu_ActivationKey2); |
| 5820 | /* cpu region */ |
| 5821 | sprintf(buf_cpu, "%s (%s)", kRegionNames[EXTRACT_FIELD(action->region, CPUIndex) + 1], kAddressSpaceNames[EXTRACT_FIELD(action->region, AddressSpace)]); |
| 5822 | ADD_MENU_3_ITEMS("CPU", buf_cpu, kViewMenu_CPURegion); |
| 5826 | 5823 | } |
| 5824 | else |
| 5825 | /* non-cpu region */ |
| 5826 | ADD_MENU_3_ITEMS("Region", kRegionNames[action->region - REGION_INVALID], kViewMenu_CPURegion); |
| 5827 | 5827 | } |
| 5828 | 5828 | |
| 5829 | 5829 | /* ##### CODE TYPE ##### */ |
| r2821 | r2822 | |
| 5833 | 5833 | } |
| 5834 | 5834 | else |
| 5835 | 5835 | { |
| 5836 | | char * type_strings = buf_type; |
| 5836 | ADD_MENU_3_ITEMS("Code Type", kCodeTypeNames[code_type], kViewMenu_CodeType); |
| 5837 | } |
| 5837 | 5838 | |
| 5838 | | type_strings += sprintf(type_strings, "%s", kCodeTypeNames[EXTRACT_FIELD(action->type, CodeType)]); |
| 5839 | if((action->flags & kActionFlag_Custom) == 0) |
| 5840 | { |
| 5841 | /* ##### CODE PARAMETER ##### */ |
| 5842 | if(code_type == kCodeType_IWrite) |
| 5843 | { |
| 5844 | /* writing parameter */ |
| 5845 | ADD_MENU_3_ITEMS("Parameter", kIWriteParameterNames[EXTRACT_FIELD(action->type, CodeParameterUpper)], kViewMenu_IWriteParameter); |
| 5846 | } |
| 5839 | 5847 | |
| 5848 | if(code_type == kCodeType_RWrite) |
| 5849 | { |
| 5850 | /* repeat parameter */ |
| 5851 | sprintf(buf_extend, "%4.4X / %4.4X", |
| 5852 | EXTRACT_FIELD(action->extend_data, LSB16), |
| 5853 | EXTRACT_FIELD(action->extend_data, MSB16)); |
| 5854 | ADD_MENU_3_ITEMS("Count / Skip", buf_extend, kViewMenu_Extend); |
| 5855 | } |
| 5856 | |
| 5840 | 5857 | if(action->flags & kActionFlag_CheckCondition) |
| 5841 | | type_strings += sprintf(type_strings, "-%s", kConditionNames[EXTRACT_FIELD(action->type, CodeParameter)]); |
| 5858 | { |
| 5859 | if(code_type == kCodeType_CBit) |
| 5860 | { |
| 5861 | /* bit parameter for CBit */ |
| 5862 | ADD_MENU_3_ITEMS("Parameter", kCBitParameterNames[EXTRACT_FIELD(action->type, CodeParameterUpper)], kViewMenu_CBitParameter); |
| 5842 | 5863 | |
| 5843 | | if(TEST_FIELD(action->type, Return)) |
| 5844 | | type_strings += sprintf(type_strings, "/Ret"); |
| 5864 | /* bit condition for CBit */ |
| 5865 | ADD_MENU_3_ITEMS("Condition", kCBitConditionNames[EXTRACT_FIELD(action->type, CodeParameterLower)], kViewMenu_CBitCondition); |
| 5845 | 5866 | |
| 5846 | | ADD_MENU_3_ITEMS("Type", buf_type, kViewMenu_CodeType); |
| 5847 | | } |
| 5867 | } |
| 5868 | else |
| 5869 | { |
| 5870 | /* condition for CWrite, Branch, Popup */ |
| 5871 | ADD_MENU_3_ITEMS("Condition", kConditionNames[EXTRACT_FIELD(action->type, CodeParameter)], kViewMenu_Condition); |
| 5872 | } |
| 5848 | 5873 | |
| 5849 | | if((action->flags & kActionFlag_Custom) == 0) |
| 5850 | | { |
| 5851 | | /* ##### CPU/REGION ##### */ |
| 5852 | | if(TEST_FIELD(action->region, RegionFlag)) |
| 5853 | | { |
| 5854 | | ADD_MENU_3_ITEMS("Region", kRegionNames[EXTRACT_FIELD(action->region, RegionIndex)], kViewMenu_CPURegion); |
| 5874 | sprintf(buf_extend, "%*.*X", kCheatSizeDigitsTable[address_size], kCheatSizeDigitsTable[address_size], action->extend_data); |
| 5875 | |
| 5876 | ADD_MENU_3_ITEMS("Comparison", buf_extend, kViewMenu_Extend); |
| 5855 | 5877 | } |
| 5856 | | else |
| 5878 | |
| 5879 | if(code_type == kCodeType_Popup) |
| 5857 | 5880 | { |
| 5858 | | sprintf(buf_cpu, "%s (%s)", kRegionNames[EXTRACT_FIELD(action->region, CPUIndex) + 1], kAddressSpaceNames[EXTRACT_FIELD(action->region, AddressSpace)]); |
| 5859 | | ADD_MENU_3_ITEMS("CPU", buf_cpu, kViewMenu_CPURegion); |
| 5881 | /* popup parameter */ |
| 5882 | ADD_MENU_3_ITEMS("Parameter", kPopupOptionNames[EXTRACT_FIELD(action->type, PopupParameter)], kViewMenu_PopupParameter); |
| 5860 | 5883 | } |
| 5861 | 5884 | |
| 5862 | 5885 | /* ##### ADDRESS ##### */ |
| 5863 | 5886 | switch(EXTRACT_FIELD(action->type, AddressRead)) |
| 5864 | 5887 | { |
| 5865 | 5888 | case kReadFrom_Address: |
| 5866 | | sprintf(buf_address, "%*.*X", address_length, address_length, action->originalAddress); |
| 5889 | sprintf(buf_address, "%*.*X", address_length, address_length, action->original_address); |
| 5867 | 5890 | break; |
| 5868 | 5891 | |
| 5869 | 5892 | case kReadFrom_Index: |
| 5870 | | sprintf(buf_address, "(V%s)", kNumbersTable[action->originalAddress]); |
| 5893 | sprintf(buf_address, "(V%s)", kNumbersTable[action->original_address]); |
| 5871 | 5894 | break; |
| 5872 | 5895 | |
| 5873 | 5896 | case kReadFrom_Variable: |
| 5874 | | sprintf(buf_address, "V%s", kNumbersTable[action->originalAddress]); |
| 5897 | sprintf(buf_address, "V%s", kNumbersTable[action->original_address]); |
| 5875 | 5898 | } |
| 5876 | 5899 | |
| 5877 | 5900 | ADD_MENU_3_ITEMS("Address", buf_address, kViewMenu_Address); |
| 5878 | 5901 | |
| 5879 | 5902 | /* ##### SIZE ##### */ |
| 5880 | | if(action->flags & kActionFlag_PDWWrite) |
| 5903 | sprintf(buf_size, "%s", kByteSizeStringList[address_size]); |
| 5904 | ADD_MENU_3_ITEMS("Size", buf_size, kViewMenu_AddressSize); |
| 5905 | |
| 5906 | /* ##### INDEX ##### */ |
| 5907 | if(action->flags & kActionFlag_IndexAddress) |
| 5881 | 5908 | { |
| 5882 | | sprintf(buf_size, "%s / %s", kByteSizeStringList[address_size], kByteSizeStringList[EXTRACT_FIELD(action->type, IndexSize)]); |
| 5883 | | ADD_MENU_3_ITEMS("Size 1st / 2nd", buf_size, kViewMenu_Size); |
| 5884 | | } |
| 5885 | | else if(action->flags & kActionFlag_IndexAddress) |
| 5886 | | { |
| 5887 | | if(action->extendData != ~0) |
| 5888 | | { |
| 5889 | | sprintf(buf_size, "%s / %s", kByteSizeStringList[address_size], kByteSizeStringList[EXTRACT_FIELD(action->type, IndexSize)]); |
| 5890 | | } |
| 5891 | | else |
| 5892 | | sprintf(buf_size, "%s / < None >", kByteSizeStringList[address_size]); |
| 5909 | /* index offset for IWrite, Move */ |
| 5910 | sprintf(buf_extend, "%*.*X", address_length, address_length, action->extend_data); |
| 5911 | ADD_MENU_3_ITEMS("Index Offset", buf_extend, kViewMenu_IndexOffset); |
| 5893 | 5912 | |
| 5894 | | ADD_MENU_3_ITEMS("Size Adr / Idx", buf_size, kViewMenu_Size); |
| 5913 | /* index size for IWrite, Move */ |
| 5914 | sprintf(buf_sub_size, "%s", kByteSizeStringList[EXTRACT_FIELD(action->type, CodeParameterLower)]); |
| 5915 | ADD_MENU_3_ITEMS("Index Size", buf_sub_size, kViewMenu_IndexAddressSize); |
| 5895 | 5916 | } |
| 5896 | | else |
| 5917 | |
| 5918 | /* ##### DESTINATION ##### */ |
| 5919 | if(code_type == kCodeType_Move) |
| 5897 | 5920 | { |
| 5898 | | sprintf(buf_size, "%s", kByteSizeStringList[address_size]); |
| 5899 | | ADD_MENU_3_ITEMS("Size", buf_size, kViewMenu_Size); |
| 5921 | sprintf(buf_type, "%s", kNumbersTable[EXTRACT_FIELD(action->type, CodeParameterUpper)]); |
| 5922 | ADD_MENU_3_ITEMS("Destination", buf_type, kViewMenu_MoveParameter); |
| 5900 | 5923 | } |
| 5901 | 5924 | |
| 5902 | 5925 | /* ##### DATA ##### */ |
| 5903 | | if(EXTRACT_FIELD(action->type, CodeType) != kCodeType_Watch) |
| 5926 | if(code_type != kCodeType_Watch) |
| 5904 | 5927 | { |
| 5905 | | if(TEST_FIELD(action->type, DataRead)) |
| 5928 | if(action->flags & kActionFlag_LimitedMask) |
| 5906 | 5929 | { |
| 5907 | | sprintf(buf_data, "V%s", kNumbersTable[action->originalDataField]); |
| 5930 | /* NOTE : data is upper 2 bytes from data field in case of limite mask */ |
| 5931 | if(TEST_FIELD(action->type, DataRead)) |
| 5932 | sprintf(buf_data, "V%s", kNumbersTable[EXTRACT_FIELD(action->original_data, MSB16)]); |
| 5933 | else |
| 5934 | sprintf(buf_data, "%*.*X", kCheatSizeDigitsTable[address_size], kCheatSizeDigitsTable[address_size], EXTRACT_FIELD(action->original_data, MSB16)); |
| 5908 | 5935 | } |
| 5909 | 5936 | else |
| 5910 | 5937 | { |
| 5911 | | sprintf(buf_data, "%*.*X", kCheatSizeDigitsTable[address_size], kCheatSizeDigitsTable[address_size], action->originalDataField); |
| 5938 | if(TEST_FIELD(action->type, DataRead)) |
| 5939 | sprintf(buf_data, "V%s", kNumbersTable[action->original_data]); |
| 5940 | else |
| 5941 | sprintf(buf_data, "%*.*X", kCheatSizeDigitsTable[address_size], kCheatSizeDigitsTable[address_size], action->original_data); |
| 5912 | 5942 | } |
| 5913 | 5943 | |
| 5914 | | if(EXTRACT_FIELD(action->type, Link) != kLink_CopyLink) |
| 5915 | | ADD_MENU_3_ITEMS(kDataNames[EXTRACT_FIELD(action->type, CodeType)], buf_data, kViewMenu_Data); |
| 5916 | | else |
| 5917 | | ADD_MENU_3_ITEMS("Add Value", buf_data, kViewMenu_Data); |
| 5944 | ADD_MENU_3_ITEMS(kDataNames[EXTRACT_FIELD(action->type, CodeType)], buf_data, kViewMenu_Data); |
| 5918 | 5945 | } |
| 5919 | 5946 | |
| 5920 | | /* ##### EXTEND DATA ##### */ |
| 5921 | | if(action->flags & kActionFlag_IndexAddress) |
| 5947 | /* ##### MASK ##### */ |
| 5948 | if(code_type == kCodeType_Write) |
| 5922 | 5949 | { |
| 5923 | | if(action->extendData != ~0) |
| 5924 | | sprintf(buf_extend, "%*.8X", address_length, action->extendData); |
| 5925 | | else |
| 5926 | | sprintf(buf_extend, "< none >"); |
| 5927 | | |
| 5928 | | ADD_MENU_3_ITEMS("Index", buf_extend, kViewMenu_Extend); |
| 5950 | sprintf(buf_extend, "%*.*X", address_size, address_size, action->extend_data); |
| 5951 | ADD_MENU_3_ITEMS("Mask", buf_extend, kViewMenu_Extend); |
| 5929 | 5952 | } |
| 5930 | | else if(action->flags & kActionFlag_PDWWrite) |
| 5953 | else if(action->flags & kActionFlag_LimitedMask) |
| 5931 | 5954 | { |
| 5955 | /* NOTE : mask is lower 2 bytes from data field in case of limited mask */ |
| 5956 | sprintf(buf_limited_mask, "%*.*X", address_size, address_size, EXTRACT_FIELD(action->original_data, LSB16)); |
| 5957 | ADD_MENU_3_ITEMS("Mask", buf_limited_mask, kViewMenu_LimitedMask); |
| 5958 | } |
| 5959 | |
| 5960 | /* ##### SUB DATA ##### */ |
| 5961 | if(code_type == kCodeType_PDWWrite) |
| 5962 | { |
| 5963 | /* 2nd data */ |
| 5932 | 5964 | sprintf(buf_extend, "%*.*X", |
| 5933 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, IndexSize)], |
| 5934 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, IndexSize)], |
| 5935 | | action->extendData); |
| 5965 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, CodeParameterLower)], |
| 5966 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, CodeParameterLower)], |
| 5967 | action->extend_data); |
| 5936 | 5968 | ADD_MENU_3_ITEMS("2nd Data", buf_extend, kViewMenu_Extend); |
| 5969 | |
| 5970 | /* 2nd data size */ |
| 5971 | sprintf(buf_sub_size, "%s", kByteSizeStringList[EXTRACT_FIELD(action->type, CodeParameterLower)]); |
| 5972 | ADD_MENU_3_ITEMS("2nd Data Size", buf_sub_size, kViewMenu_SubDataSize); |
| 5937 | 5973 | } |
| 5938 | | else if(action->flags & kActionFlag_Repeat) |
| 5974 | |
| 5975 | /* ##### JUMP INDEX ##### */ |
| 5976 | if(code_type == kCodeType_Branch) |
| 5939 | 5977 | { |
| 5940 | | sprintf(buf_extend, "%4.4X / %4.4X", |
| 5941 | | EXTRACT_FIELD(action->extendData, LSB16), |
| 5942 | | EXTRACT_FIELD(action->extendData, MSB16)); |
| 5943 | | ADD_MENU_3_ITEMS("Count / Skip", buf_extend, kViewMenu_Extend); |
| 5978 | /* jump index for branch */ |
| 5979 | sprintf(buf_extend, "%2.2d", action->extend_data + 1); |
| 5980 | ADD_MENU_3_ITEMS("Jump Index", buf_extend, kViewMenu_Extend); |
| 5944 | 5981 | } |
| 5945 | | else |
| 5946 | | { |
| 5947 | | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 5948 | | { |
| 5949 | | case kCodeType_Write: |
| 5950 | | case kCodeType_IWrite: |
| 5951 | | case kCodeType_VWrite: |
| 5952 | | sprintf(buf_extend, "%*.*X", address_size, address_size, action->extendData); |
| 5953 | | ADD_MENU_3_ITEMS("Mask", buf_extend, kViewMenu_Extend); |
| 5954 | | break; |
| 5955 | 5982 | |
| 5956 | | case kCodeType_CWrite: |
| 5957 | | sprintf(buf_extend, "%*.*X", address_size, address_size, action->extendData); |
| 5958 | | ADD_MENU_3_ITEMS("Comparison", buf_extend, kViewMenu_Extend); |
| 5959 | | break; |
| 5960 | | |
| 5961 | | case kCodeType_Branch: |
| 5962 | | sprintf(buf_extend, "%2.2d", action->extendData + 1); |
| 5963 | | ADD_MENU_3_ITEMS("Jump Index", buf_extend, kViewMenu_Extend); |
| 5964 | | break; |
| 5965 | | |
| 5966 | | default: |
| 5967 | | ADD_MENU_3_ITEMS("UNKNOWN", "?????", kViewMenu_Extend); |
| 5968 | | } |
| 5969 | | } |
| 5970 | | |
| 5971 | 5983 | /* ##### OPTIONS ##### */ |
| 5972 | | sprintf(buf_options, "%s %s %s %s", |
| 5973 | | TEST_FIELD(action->type, OneShot) ? "O" : "-", |
| 5974 | | TEST_FIELD(action->type, DelayEnable) ? "D" : "-", |
| 5975 | | TEST_FIELD(action->type, PrefillEnable) ? "P" : "-", |
| 5976 | | TEST_FIELD(action->type, RestoreValue) ? "R" : "-"); |
| 5984 | sprintf(buf_options, "%s %s %s %s %s", |
| 5985 | TEST_FIELD(action->type, OneShot) ? "One" : "-", |
| 5986 | TEST_FIELD(action->type, DelayEnable) ? "Del" : "-", |
| 5987 | TEST_FIELD(action->type, PrefillEnable) ? "Pre" : "-", |
| 5988 | TEST_FIELD(action->type, Return) ? "Ret" : "-", |
| 5989 | TEST_FIELD(action->type, RestoreValue) ? "Rst" : "-"); |
| 5977 | 5990 | ADD_MENU_3_ITEMS("Options", buf_options, kViewMenu_Options); |
| 5978 | 5991 | |
| 5979 | 5992 | /* ##### CODE TYPE OPTIONS ##### */ |
| 5980 | | if( EXTRACT_FIELD(action->type, CodeType) == kCodeType_VWrite || |
| 5981 | | EXTRACT_FIELD(action->type, CodeType) == kCodeType_VRWrite) |
| 5993 | if(TEST_FIELD(action->type, ValueSelectEnable)) |
| 5982 | 5994 | { |
| 5983 | 5995 | sprintf(buf_code_type_options, "%s %s %s %s", |
| 5984 | | TEST_FIELD(action->type, ValueSelectMinimumDisplay) ? "D" : "-", |
| 5985 | | TEST_FIELD(action->type, ValueSelectMinimum) ? "M" : "-", |
| 5986 | | TEST_FIELD(action->type, ValueSelectBCD) ? "B" : "-", |
| 5987 | | TEST_FIELD(action->type, ValueSelectNegative) ? "N" : "-"); |
| 5996 | TEST_FIELD(action->type, ValueSelectMinimumDisplay) ? "MinD" : "-", |
| 5997 | TEST_FIELD(action->type, ValueSelectMinimum) ? "Min" : "-", |
| 5998 | TEST_FIELD(action->type, ValueSelectBCD) ? "BCD" : "-", |
| 5999 | TEST_FIELD(action->type, ValueSelectNegative) ? "Neg" : "-"); |
| 5988 | 6000 | ADD_MENU_3_ITEMS("Value Select Options", buf_code_type_options, kViewMenu_ValueSelectOptions); |
| 5989 | 6001 | } |
| 5990 | | else if(EXTRACT_FIELD(action->type, CodeType) == kCodeType_Popup) |
| 5991 | | { |
| 5992 | | ADD_MENU_3_ITEMS("Popup Options", kPopupOptionNames[EXTRACT_FIELD(action->type, PopupParameter)], kViewMenu_PopupOptions); |
| 5993 | | } |
| 5994 | | else if(EXTRACT_FIELD(action->type, Link) == kLink_CopyLink) |
| 5995 | | { |
| 5996 | | sprintf(buf_code_type_options, "%s %s", |
| 5997 | | TEST_FIELD(action->type, LinkValueSelectBCD) ? "B" : "-", |
| 5998 | | TEST_FIELD(action->type, LinkValueSelectNegative) ? "N" : "-"); |
| 5999 | | ADD_MENU_3_ITEMS("Copy Link Options", buf_code_type_options, kViewMenu_CopyLinkOptions); |
| 6000 | | } |
| 6001 | 6002 | } |
| 6002 | 6003 | else |
| 6003 | 6004 | { |
| 6004 | | if(EXTRACT_FIELD(action->type, CodeType) == kCustomCode_Layer) |
| 6005 | /* ##### CUSTOM CODE PARAMETER ##### */ |
| 6006 | if(EXTRACT_FIELD(action->type, CodeType) == CUSTOM_CODE_LAYER_TAG) |
| 6005 | 6007 | { |
| 6006 | | /* ##### LAYER ##### */ |
| 6007 | | sprintf(buf_address, "%2.2X", action->originalAddress); |
| 6008 | /* ##### LAYER TAG ##### */ |
| 6009 | sprintf(buf_address, "%2.2X", action->original_address); |
| 6008 | 6010 | ADD_MENU_3_ITEMS("Display Level", buf_address, kViewMenu_LayerDisplayLevel); |
| 6009 | 6011 | |
| 6010 | | sprintf(buf_data, "%2.2X", action->originalDataField); |
| 6012 | sprintf(buf_data, "%2.2X", action->original_data); |
| 6011 | 6013 | ADD_MENU_3_ITEMS("Set Level", buf_data, kViewMenu_LayerSetLevel); |
| 6012 | 6014 | |
| 6013 | | sprintf(buf_extend, "%2.2X", action->extendData); |
| 6015 | sprintf(buf_extend, "%2.2X", action->extend_data); |
| 6014 | 6016 | ADD_MENU_3_ITEMS("Set Length", buf_extend, kViewMenu_LayerSetLength); |
| 6015 | 6017 | } |
| 6016 | 6018 | } |
| r2821 | r2822 | |
| 6022 | 6024 | TERMINATE_MENU_2_ITEMS; |
| 6023 | 6025 | |
| 6024 | 6026 | /* adjust current cursor position */ |
| 6025 | | ADJUST_CURSOR(menu->sel, total) |
| 6027 | ADJUST_CURSOR(menu->sel, total); |
| 6026 | 6028 | |
| 6029 | if(menu_index[menu->sel] == kViewMenu_Header) |
| 6030 | { |
| 6031 | if(entry->action_list_length > 1) |
| 6032 | request_arrow = 3; |
| 6033 | } |
| 6034 | |
| 6027 | 6035 | /* draw it */ |
| 6028 | | old_style_menu(menu_item, menu_sub_item, flag_buf, menu->sel, 0); |
| 6036 | old_style_menu(menu_item, menu_sub_item, flag_buf, menu->sel, request_arrow); |
| 6029 | 6037 | |
| 6030 | 6038 | /********** KEY HANDLING **********/ |
| 6031 | 6039 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 6032 | 6040 | { |
| 6033 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 6041 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 6034 | 6042 | } |
| 6035 | 6043 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 6036 | 6044 | { |
| 6037 | | CURSOR_TO_NEXT(menu->sel, total) |
| 6045 | CURSOR_TO_NEXT(menu->sel, total); |
| 6038 | 6046 | } |
| 6039 | 6047 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate)) |
| 6040 | 6048 | { |
| 6041 | 6049 | if(--page_index < 0) |
| 6042 | | page_index = entry->actionListLength - 1; |
| 6050 | page_index = entry->action_list_length - 1; |
| 6043 | 6051 | } |
| 6044 | 6052 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate)) |
| 6045 | 6053 | { |
| 6046 | | if(++page_index > entry->actionListLength - 1) |
| 6054 | if(++page_index > entry->action_list_length - 1) |
| 6047 | 6055 | page_index = 0; |
| 6048 | 6056 | } |
| 6049 | 6057 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 6050 | 6058 | { |
| 6051 | | CURSOR_PAGE_UP(menu->sel) |
| 6059 | CURSOR_PAGE_UP(menu->sel); |
| 6052 | 6060 | } |
| 6053 | 6061 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 6054 | 6062 | { |
| 6055 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 6063 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 6056 | 6064 | } |
| 6057 | 6065 | else if(input_ui_pressed(machine, IPT_UI_SELECT) || input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 6058 | 6066 | { |
| r2821 | r2822 | |
| 6088 | 6096 | "Missing Restore Previous Value flag", |
| 6089 | 6097 | "Missing label link code", |
| 6090 | 6098 | "Both Value and Label Select are defined", |
| 6091 | | "Copy Link is defined though no value-select code", |
| 6092 | 6099 | "Invalid Data Field", |
| 6093 | 6100 | "Invalid Extend Data Field", |
| 6094 | 6101 | "Don't set Variable in this type", |
| 6095 | 6102 | "Value Select can't select any value", |
| 6103 | "Limited Mask is over length", |
| 6096 | 6104 | "RWrite doesn't have counter", |
| 6097 | 6105 | "Invalid Address Read", |
| 6098 | 6106 | "Invalid Variable in address field", |
| r2821 | r2822 | |
| 6105 | 6113 | |
| 6106 | 6114 | int i, j; |
| 6107 | 6115 | int total = 0; |
| 6108 | | UINT8 isEdit = 0; |
| 6109 | | const char ** menuItem; |
| 6110 | | CheatEntry * entry = &cheatList[menu->pre_sel]; |
| 6116 | UINT8 is_edit = 0; |
| 6117 | const char **menu_item; |
| 6118 | cheat_entry *entry = &cheat_list[menu->pre_sel]; |
| 6111 | 6119 | |
| 6112 | 6120 | /* first setting : NONE */ |
| 6113 | 6121 | if(menu->first_time) |
| 6114 | 6122 | menu->first_time = 0; |
| 6115 | 6123 | |
| 6116 | 6124 | /* required items = ((items + header + 2 separators) * total_actions) + edit + return + terminator) */ |
| 6117 | | request_strings(((kErrorFlag_Max + 3) * entry->actionListLength) + 3, 0, 0, 0); |
| 6118 | | menuItem = menu_strings.main_list; |
| 6125 | request_strings(((kErrorFlag_Max + 3) * entry->action_list_length) + 3, 0, 0, 0); |
| 6126 | menu_item = menu_strings.main_list; |
| 6119 | 6127 | |
| 6120 | 6128 | /********** MENU CONSTRUCTION **********/ |
| 6121 | | for(i = 0; i < entry->actionListLength; i++) |
| 6129 | for(i = 0; i < entry->action_list_length; i++) |
| 6122 | 6130 | { |
| 6123 | | CheatAction * action = &entry->actionList[i]; |
| 6131 | cheat_action *action = &entry->action_list[i]; |
| 6124 | 6132 | |
| 6125 | 6133 | UINT32 flags = AnalyseCodeFormat(entry, action); |
| 6126 | 6134 | |
| 6127 | | menuItem[total++] = action->optionalName ? action->optionalName : "(Null)"; |
| 6128 | | menuItem[total++] = MENU_SEPARATOR_ITEM; |
| 6135 | menu_item[total++] = action->optional_name ? action->optional_name : "(Null)"; |
| 6136 | menu_item[total++] = MENU_SEPARATOR_ITEM; |
| 6129 | 6137 | |
| 6130 | 6138 | if(flags) |
| 6131 | 6139 | { |
| 6132 | 6140 | for(j = 0; j < kErrorFlag_Max; j++) |
| 6133 | 6141 | { |
| 6134 | 6142 | if((flags >> j) & 1) |
| 6135 | | menuItem[total++] = kAnalyseItemName[j]; |
| 6143 | menu_item[total++] = kAnalyseItemName[j]; |
| 6136 | 6144 | } |
| 6137 | 6145 | } |
| 6138 | 6146 | else |
| 6139 | | menuItem[total++] = "No Problem"; |
| 6147 | menu_item[total++] = "No Problem"; |
| 6140 | 6148 | |
| 6141 | | menuItem[total++] = MENU_SEPARATOR_ITEM; |
| 6149 | menu_item[total++] = MENU_SEPARATOR_ITEM; |
| 6142 | 6150 | } |
| 6143 | 6151 | |
| 6144 | | menuItem[total++] = "Edit This Entry"; |
| 6145 | | menuItem[total++] = "Return to Prior Menu"; |
| 6146 | | menuItem[total] = NULL; |
| 6152 | menu_item[total++] = "Edit This Entry"; |
| 6153 | menu_item[total++] = "Return to Prior Menu"; |
| 6154 | menu_item[total] = NULL; |
| 6147 | 6155 | |
| 6148 | 6156 | /* adjust cursor position */ |
| 6149 | | ADJUST_CURSOR(menu->sel, total) |
| 6157 | ADJUST_CURSOR(menu->sel, total); |
| 6150 | 6158 | |
| 6151 | | old_style_menu(menuItem, NULL, NULL, menu->sel, 0); |
| 6159 | old_style_menu(menu_item, NULL, NULL, menu->sel, 0); |
| 6152 | 6160 | |
| 6153 | 6161 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 6154 | 6162 | { |
| 6155 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 6163 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 6156 | 6164 | } |
| 6157 | 6165 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 6158 | 6166 | { |
| 6159 | | CURSOR_TO_NEXT(menu->sel, total) |
| 6167 | CURSOR_TO_NEXT(menu->sel, total); |
| 6160 | 6168 | } |
| 6161 | 6169 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 6162 | 6170 | { |
| 6163 | | CURSOR_PAGE_UP(menu->sel) |
| 6171 | CURSOR_PAGE_UP(menu->sel); |
| 6164 | 6172 | } |
| 6165 | 6173 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 6166 | 6174 | { |
| 6167 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 6175 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 6168 | 6176 | } |
| 6169 | 6177 | else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT)) |
| 6170 | 6178 | { |
| 6171 | | isEdit = 1; |
| 6179 | is_edit = 1; |
| 6172 | 6180 | } |
| 6173 | 6181 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 6174 | 6182 | { |
| 6175 | 6183 | if(menu->sel == total - 2) |
| 6176 | | isEdit = 1; |
| 6184 | is_edit = 1; |
| 6177 | 6185 | else |
| 6178 | 6186 | menu->sel = -1; |
| 6179 | 6187 | } |
| r2821 | r2822 | |
| 6182 | 6190 | menu->sel = -1; |
| 6183 | 6191 | } |
| 6184 | 6192 | |
| 6185 | | if(isEdit) |
| 6193 | if(is_edit) |
| 6186 | 6194 | { |
| 6187 | 6195 | if(entry->flags & kCheatFlag_OldFormat) |
| 6188 | 6196 | cheat_menu_stack_push(edit_cheat_menu, menu->return_handler, menu->pre_sel); |
| r2821 | r2822 | |
| 6446 | 6454 | } |
| 6447 | 6455 | else |
| 6448 | 6456 | { |
| 6449 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 6457 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 6450 | 6458 | |
| 6451 | 6459 | if(menu->sel == kMenu_Divider1 || menu->sel == kMenu_Divider2) |
| 6452 | 6460 | { |
| r2821 | r2822 | |
| 6484 | 6492 | } |
| 6485 | 6493 | else |
| 6486 | 6494 | { |
| 6487 | | CURSOR_TO_NEXT(menu->sel, total) |
| 6495 | CURSOR_TO_NEXT(menu->sel, total); |
| 6488 | 6496 | |
| 6489 | 6497 | if(menu->sel == kMenu_Divider1 || menu->sel == kMenu_Divider2) |
| 6490 | 6498 | menu->sel++; |
| r2821 | r2822 | |
| 6584 | 6592 | } |
| 6585 | 6593 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 6586 | 6594 | { |
| 6587 | | CURSOR_PAGE_UP(menu->sel) |
| 6595 | CURSOR_PAGE_UP(menu->sel); |
| 6588 | 6596 | } |
| 6589 | 6597 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 6590 | 6598 | { |
| 6591 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 6599 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 6592 | 6600 | } |
| 6593 | 6601 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 6594 | 6602 | { |
| r2821 | r2822 | |
| 6685 | 6693 | else |
| 6686 | 6694 | { |
| 6687 | 6695 | /* if no search region (eg, sms.c in HazeMD), don't open result viewer to avoid the crash */ |
| 6688 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 6689 | | messageType = kCheatMessage_NoSearchRegion; |
| 6696 | SET_MESSAGE(kCheatMessage_NoSearchRegion); |
| 6690 | 6697 | } |
| 6691 | 6698 | break; |
| 6692 | 6699 | |
| r2821 | r2822 | |
| 6740 | 6747 | update_search(search); |
| 6741 | 6748 | |
| 6742 | 6749 | if(doneSaveMemory || menu->sel == kMenu_Value) |
| 6743 | | messageType = kCheatMessage_CheatFound; |
| 6750 | SET_MESSAGE(kCheatMessage_CheatFound); |
| 6744 | 6751 | else |
| 6745 | | messageType = kCheatMessage_InitializeMemory; |
| 6752 | SET_MESSAGE(kCheatMessage_InitializeMemory); |
| 6746 | 6753 | |
| 6747 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 6748 | | |
| 6749 | 6754 | doneSaveMemory = 1; |
| 6750 | 6755 | |
| 6751 | 6756 | if(search->num_results == 1) |
| 6752 | 6757 | { |
| 6753 | 6758 | AddCheatFromFirstResult(search); |
| 6754 | 6759 | |
| 6755 | | messageType = kCheatMessage_1CheatFound; |
| 6760 | SET_MESSAGE(kCheatMessage_1CheatFound); |
| 6756 | 6761 | } |
| 6757 | 6762 | } |
| 6758 | 6763 | |
| r2821 | r2822 | |
| 6991 | 6996 | menuSubItem[total] = NULL; |
| 6992 | 6997 | |
| 6993 | 6998 | /* adjust current cursor position */ |
| 6994 | | ADJUST_CURSOR(menu->sel, total) |
| 6999 | ADJUST_CURSOR(menu->sel, total); |
| 6995 | 7000 | |
| 6996 | 7001 | /* draw it */ |
| 6997 | 7002 | old_style_menu(menuItem, menuSubItem, 0, menu->sel, 0); |
| r2821 | r2822 | |
| 7018 | 7023 | } |
| 7019 | 7024 | else |
| 7020 | 7025 | { |
| 7021 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 7026 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 7022 | 7027 | |
| 7023 | 7028 | if(menu->sel == kMenu_Separator) menu->sel--; |
| 7024 | 7029 | } |
| r2821 | r2822 | |
| 7044 | 7049 | } |
| 7045 | 7050 | else |
| 7046 | 7051 | { |
| 7047 | | CURSOR_TO_NEXT(menu->sel, total) |
| 7052 | CURSOR_TO_NEXT(menu->sel, total); |
| 7048 | 7053 | |
| 7049 | 7054 | if(menu->sel == kMenu_Separator) menu->sel++; |
| 7050 | 7055 | } |
| r2821 | r2822 | |
| 7052 | 7057 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 7053 | 7058 | { |
| 7054 | 7059 | if(!editActive) |
| 7055 | | CURSOR_PAGE_UP(menu->sel) |
| 7060 | CURSOR_PAGE_UP(menu->sel); |
| 7056 | 7061 | } |
| 7057 | 7062 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 7058 | 7063 | { |
| 7059 | 7064 | if(!editActive) |
| 7060 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 7065 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 7061 | 7066 | } |
| 7062 | 7067 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, kHorizontalFastKeyRepeatRate)) |
| 7063 | 7068 | { |
| r2821 | r2822 | |
| 7405 | 7410 | else |
| 7406 | 7411 | sprintf(valueBuffer, "%.*X", kSearchByteDigitsTable[search->bytes], search->value & kSearchByteMaskTable[search->bytes]); |
| 7407 | 7412 | |
| 7408 | | if(TEST_FIELD(cheatOptions, DontPrintNewLabels)) |
| 7413 | if(TEST_FIELD(cheat_options, DontPrintNewLabels)) |
| 7409 | 7414 | { |
| 7410 | 7415 | menu_item[total] = kOperandNameTable[search->lhs]; |
| 7411 | 7416 | menu_subitem[total++] = NULL; |
| r2821 | r2822 | |
| 7788 | 7793 | "User Defined" |
| 7789 | 7794 | }; |
| 7790 | 7795 | |
| 7791 | | int total = 0; |
| 7792 | | UINT8 doRebuild = 0; |
| 7793 | | const char ** menuItem; |
| 7794 | | const char ** menuSubItem; |
| 7796 | int total = 0; |
| 7797 | UINT8 do_rebuild = 0; |
| 7798 | UINT8 do_reallocate = 0; |
| 7799 | const char **menu_item; |
| 7800 | const char **menu_sub_item; |
| 7795 | 7801 | search_info *search = get_current_search(); |
| 7796 | 7802 | search_region *region; |
| 7797 | 7803 | |
| r2821 | r2822 | |
| 7800 | 7806 | menu->first_time = 0; |
| 7801 | 7807 | |
| 7802 | 7808 | /* required items = speed + total regions + return + terminator */ |
| 7803 | | request_strings(search->region_list_length + 3, 0, 0, 0); |
| 7804 | | menuItem = menu_strings.main_list; |
| 7805 | | menuSubItem = menu_strings.sub_list; |
| 7809 | request_strings(search->region_list_length + 4, 0, 0, 0); |
| 7810 | menu_item = menu_strings.main_list; |
| 7811 | menu_sub_item = menu_strings.sub_list; |
| 7806 | 7812 | |
| 7807 | 7813 | /********** MENU CONSTRUCTION **********/ |
| 7808 | 7814 | /* ##### SEARCH SPEED ##### */ |
| 7809 | | menuItem[total] = "Search Speed"; |
| 7810 | | menuSubItem[total++] = ksearch_speedList[search->search_speed]; |
| 7815 | menu_item[total] = "Search Speed"; |
| 7816 | menu_sub_item[total++] = ksearch_speedList[search->search_speed]; |
| 7811 | 7817 | |
| 7812 | 7818 | /* ##### REGIONS ##### */ |
| 7813 | 7819 | if(search->region_list_length) |
| r2821 | r2822 | |
| 7818 | 7824 | { |
| 7819 | 7825 | search_region *region = &search->region_list[i]; |
| 7820 | 7826 | |
| 7821 | | menuItem[total] = region->name; |
| 7822 | | menuSubItem[total++] = region->flags & kRegionFlag_Enabled ? "On" : "Off"; |
| 7827 | menu_item[total] = region->name; |
| 7828 | |
| 7829 | if(region->flags & kRegionFlag_HasError) |
| 7830 | menu_sub_item[total++] = "Locked"; |
| 7831 | else |
| 7832 | menu_sub_item[total++] = region->flags & kRegionFlag_Enabled ? "On" : "Off"; |
| 7823 | 7833 | } |
| 7824 | 7834 | } |
| 7825 | 7835 | else |
| 7826 | 7836 | { |
| 7827 | | /* in case of no SearchRegion */ |
| 7828 | | menuItem[total] = "No Search Region"; |
| 7829 | | menuSubItem[total++] = NULL; |
| 7837 | |
| 7838 | /* in case of no search region */ |
| 7839 | menu_item[total] = "No Search Region"; |
| 7840 | menu_sub_item[total++] = NULL; |
| 7830 | 7841 | } |
| 7831 | 7842 | |
| 7832 | 7843 | /* ##### RETURN ##### */ |
| 7833 | | menuItem[total] = "Return to Prior Menu"; |
| 7834 | | menuSubItem[total++] = NULL; |
| 7844 | menu_item[total] = "Return to Prior Menu"; |
| 7845 | menu_sub_item[total++] = NULL; |
| 7835 | 7846 | |
| 7836 | 7847 | /* ##### TERMINATE ARRAY ##### */ |
| 7837 | | menuItem[total] = NULL; |
| 7838 | | menuSubItem[total] = NULL; |
| 7848 | menu_item[total] = NULL; |
| 7849 | menu_sub_item[total] = NULL; |
| 7839 | 7850 | |
| 7840 | 7851 | /* adjust current cursor position */ |
| 7841 | | ADJUST_CURSOR(menu->sel, total) |
| 7852 | ADJUST_CURSOR(menu->sel, total); |
| 7842 | 7853 | |
| 7843 | 7854 | /* draw it */ |
| 7844 | | old_style_menu(menuItem, menuSubItem, NULL, menu->sel, 0); |
| 7855 | old_style_menu(menu_item, menu_sub_item, NULL, menu->sel, 0); |
| 7845 | 7856 | |
| 7846 | | if(search->region_list_length && menu->sel && menu->sel < total -1) |
| 7857 | if(search->region_list_length && menu->sel && menu->sel < total - 1) |
| 7858 | { |
| 7847 | 7859 | region = &search->region_list[menu->sel - 1]; |
| 7860 | |
| 7861 | if(region->flags & kRegionFlag_HasError) |
| 7862 | region = NULL; |
| 7863 | } |
| 7848 | 7864 | else |
| 7849 | 7865 | region = NULL; |
| 7850 | 7866 | |
| 7851 | 7867 | /********** KEY HANDLING **********/ |
| 7852 | 7868 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 7853 | 7869 | { |
| 7854 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 7870 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 7855 | 7871 | } |
| 7856 | 7872 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 7857 | 7873 | { |
| 7858 | | CURSOR_TO_NEXT(menu->sel, total) |
| 7874 | CURSOR_TO_NEXT(menu->sel, total); |
| 7859 | 7875 | } |
| 7860 | 7876 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 7861 | 7877 | { |
| 7862 | | CURSOR_PAGE_UP(menu->sel) |
| 7878 | CURSOR_PAGE_UP(menu->sel); |
| 7863 | 7879 | } |
| 7864 | 7880 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 7865 | 7881 | { |
| 7866 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 7882 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 7867 | 7883 | } |
| 7868 | 7884 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate)) |
| 7869 | 7885 | { |
| r2821 | r2822 | |
| 7871 | 7887 | { |
| 7872 | 7888 | /* toggle ON/OFF */ |
| 7873 | 7889 | region->flags ^= kRegionFlag_Enabled; |
| 7890 | |
| 7891 | do_reallocate = 1; |
| 7874 | 7892 | } |
| 7875 | | else if(!menu->sel) |
| 7893 | else if(menu->sel == 0) |
| 7876 | 7894 | { |
| 7877 | 7895 | if(--search->search_speed < 0) |
| 7878 | 7896 | /* "Fast" -> "User Defined" */ |
| 7879 | | search->search_speed = ksearch_speed_Max - 1; |
| 7897 | search->search_speed = SEARCH_SPEED_MAX - 1; |
| 7880 | 7898 | |
| 7881 | | doRebuild = 1; |
| 7899 | do_rebuild = 1; |
| 7900 | do_reallocate = 1; |
| 7882 | 7901 | } |
| 7883 | 7902 | } |
| 7884 | 7903 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate)) |
| r2821 | r2822 | |
| 7887 | 7906 | { |
| 7888 | 7907 | /* toggle ON/OFF */ |
| 7889 | 7908 | region->flags ^= kRegionFlag_Enabled; |
| 7909 | |
| 7910 | do_reallocate = 1; |
| 7890 | 7911 | } |
| 7891 | | else if(!menu->sel) |
| 7912 | else if(menu->sel == 0) |
| 7892 | 7913 | { |
| 7893 | | if(++search->search_speed >= ksearch_speed_Max) |
| 7914 | if(++search->search_speed >= SEARCH_SPEED_MAX) |
| 7894 | 7915 | /* "User Defined" -> "Fast" */ |
| 7895 | | search->search_speed = ksearch_speed_Fast; |
| 7916 | search->search_speed = SEARCH_SPEED_FAST; |
| 7896 | 7917 | |
| 7897 | | doRebuild = 1; |
| 7918 | do_rebuild = 1; |
| 7919 | do_reallocate = 1; |
| 7898 | 7920 | } |
| 7899 | 7921 | } |
| 7900 | 7922 | else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT)) |
| r2821 | r2822 | |
| 7903 | 7925 | { |
| 7904 | 7926 | /* SHIFT + CHEAT DELETE = invalidate selected region */ |
| 7905 | 7927 | invalidate_entire_region(search, region); |
| 7906 | | // ui_popup_time(1, "region invalidated - %d results remain", search->num_results); |
| 7907 | 7928 | } |
| 7908 | 7929 | } |
| 7909 | 7930 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 7910 | 7931 | { |
| 7911 | | if(search->search_speed == ksearch_speed_UserDefined) |
| 7932 | if(search->search_speed == SEARCH_SPEED_USER_DEFINED) |
| 7912 | 7933 | /* reload user region */ |
| 7913 | | doRebuild = 1; |
| 7934 | do_rebuild = 1; |
| 7935 | do_reallocate = 1; |
| 7914 | 7936 | } |
| 7915 | 7937 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 7916 | 7938 | { |
| 7917 | 7939 | if(region) |
| 7940 | { |
| 7918 | 7941 | region->flags ^= kRegionFlag_Enabled; |
| 7919 | | else if(!menu->sel) |
| 7920 | | doRebuild = 1; |
| 7921 | | else |
| 7942 | do_reallocate = 1; |
| 7943 | } |
| 7944 | else if(menu->sel == 0) |
| 7945 | { |
| 7946 | do_rebuild = 1; |
| 7947 | do_reallocate = 1; |
| 7948 | } |
| 7949 | else if(menu->sel == total - 1) |
| 7922 | 7950 | menu->sel = -1; |
| 7923 | 7951 | } |
| 7924 | 7952 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 7925 | 7953 | menu->sel = -1; |
| 7926 | 7954 | |
| 7927 | 7955 | /********** REBUILD SEARCH REGION **********/ |
| 7928 | | if(doRebuild) |
| 7956 | if(do_rebuild) |
| 7929 | 7957 | { |
| 7930 | | if(search->search_speed != ksearch_speed_UserDefined) |
| 7931 | | /* rebuild SearchRegion from memory map */ |
| 7958 | if(search->search_speed != SEARCH_SPEED_USER_DEFINED) |
| 7959 | /* rebuild search region from memory map */ |
| 7932 | 7960 | build_search_regions(machine, search); |
| 7933 | 7961 | else |
| 7934 | | /* rebuild SearchRegion from user-defined map */ |
| 7935 | | LoadCheatDatabase(machine, kLoadFlag_UserRegion); |
| 7962 | /* rebuild search region from user-defined map */ |
| 7963 | load_cheat_database(machine, kLoadFlag_UserRegion); |
| 7964 | } |
| 7936 | 7965 | |
| 7937 | | /* reallocate SearchRegions */ |
| 7966 | if(do_reallocate) |
| 7967 | /* reallocate search region */ |
| 7938 | 7968 | allocate_search_regions(search); |
| 7939 | | } |
| 7940 | 7969 | |
| 7941 | 7970 | return menu->sel + 1; |
| 7942 | 7971 | } |
| r2821 | r2822 | |
| 8234 | 8263 | search->num_results--; |
| 8235 | 8264 | region->num_results--; |
| 8236 | 8265 | |
| 8237 | | messageType = kCheatMessage_SucceededToDelete; |
| 8238 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 8266 | SET_MESSAGE(kCheatMessage_SucceededToDelete); |
| 8239 | 8267 | } |
| 8240 | 8268 | } |
| 8241 | 8269 | else if(input_ui_pressed(machine, IPT_UI_WATCH_VALUE)) |
| r2821 | r2822 | |
| 8329 | 8357 | const char ** menuItem; |
| 8330 | 8358 | char ** buf; |
| 8331 | 8359 | char * stringsBuf; // "USER20 FFFFFFFF (99:32 Bit)" 27 chars |
| 8332 | | WatchInfo * watch; |
| 8360 | watch_info *watch; |
| 8333 | 8361 | |
| 8334 | 8362 | /* first setting : NONE */ |
| 8335 | 8363 | if(menu->first_time) |
| 8336 | 8364 | menu->first_time = 0; |
| 8337 | 8365 | |
| 8338 | 8366 | /* required items = (total watchpoints + return + terminator) & (strings buf * total watchpoints [max chars = 32]) */ |
| 8339 | | request_strings(watchListLength + 2, watchListLength, 32, 0); |
| 8367 | request_strings(watch_list_length + 2, watch_list_length, 32, 0); |
| 8340 | 8368 | menuItem = menu_strings.main_list; |
| 8341 | 8369 | buf = menu_strings.main_strings; |
| 8342 | 8370 | |
| 8343 | 8371 | /********** MENU CONSTRUCTION **********/ |
| 8344 | | for(i = 0; i < watchListLength; i++) |
| 8372 | for(i = 0; i < watch_list_length; i++) |
| 8345 | 8373 | { |
| 8346 | | WatchInfo * traverse = &watchList[i]; |
| 8347 | | cpu_region_info *info = get_cpu_or_region_info(traverse->cpu); |
| 8374 | watch_info *traverse = &watch_list[i]; |
| 8375 | cpu_region_info *info = get_cpu_or_region_info(traverse->cpu); |
| 8348 | 8376 | |
| 8349 | 8377 | /* FORMAT : "CPU/Region : Address (Length : Bytes)" */ |
| 8350 | 8378 | if(!editActive || menu->sel != i) |
| r2821 | r2822 | |
| 8353 | 8381 | get_region_name(traverse->cpu), |
| 8354 | 8382 | info->address_chars_needed, |
| 8355 | 8383 | traverse->address, |
| 8356 | | traverse->numElements, |
| 8357 | | kByteSizeStringList[traverse->elementBytes]); |
| 8384 | traverse->num_elements, |
| 8385 | kByteSizeStringList[traverse->element_bytes]); |
| 8358 | 8386 | } |
| 8359 | 8387 | else |
| 8360 | 8388 | { |
| r2821 | r2822 | |
| 8379 | 8407 | stringsBuf += sprintf(stringsBuf, "%X", (traverse->address & kIncrementMaskTable[digits]) / kIncrementValueTable[digits]); |
| 8380 | 8408 | } |
| 8381 | 8409 | |
| 8382 | | stringsBuf += sprintf(stringsBuf, " (%d:%s)", traverse->numElements, kByteSizeStringList[traverse->elementBytes]); |
| 8410 | stringsBuf += sprintf(stringsBuf, " (%d:%s)", traverse->num_elements, kByteSizeStringList[traverse->element_bytes]); |
| 8383 | 8411 | } |
| 8384 | 8412 | break; |
| 8385 | 8413 | |
| r2821 | r2822 | |
| 8388 | 8416 | get_region_name(traverse->cpu), |
| 8389 | 8417 | info->address_chars_needed, |
| 8390 | 8418 | traverse->address, |
| 8391 | | traverse->numElements, |
| 8392 | | kByteSizeStringList[traverse->elementBytes]); |
| 8419 | traverse->num_elements, |
| 8420 | kByteSizeStringList[traverse->element_bytes]); |
| 8393 | 8421 | break; |
| 8394 | 8422 | |
| 8395 | 8423 | case 0: |
| r2821 | r2822 | |
| 8397 | 8425 | get_region_name(traverse->cpu), |
| 8398 | 8426 | info->address_chars_needed, |
| 8399 | 8427 | traverse->address, |
| 8400 | | traverse->numElements, |
| 8401 | | kByteSizeStringList[traverse->elementBytes]); |
| 8428 | traverse->num_elements, |
| 8429 | kByteSizeStringList[traverse->element_bytes]); |
| 8402 | 8430 | break; |
| 8403 | 8431 | } |
| 8404 | 8432 | } |
| r2821 | r2822 | |
| 8414 | 8442 | menuItem[total] = NULL; |
| 8415 | 8443 | |
| 8416 | 8444 | /* adjust current cursor position */ |
| 8417 | | ADJUST_CURSOR(menu->sel, total) |
| 8445 | ADJUST_CURSOR(menu->sel, total); |
| 8418 | 8446 | |
| 8419 | 8447 | /* draw it */ |
| 8420 | 8448 | old_style_menu(menuItem, NULL, NULL, menu->sel, 0); |
| 8421 | 8449 | |
| 8422 | | if(menu->sel < watchListLength) |
| 8423 | | watch = &watchList[menu->sel]; |
| 8450 | if(menu->sel < watch_list_length) |
| 8451 | watch = &watch_list[menu->sel]; |
| 8424 | 8452 | else |
| 8425 | 8453 | watch = NULL; |
| 8426 | 8454 | |
| r2821 | r2822 | |
| 8429 | 8457 | { |
| 8430 | 8458 | if(!editActive) |
| 8431 | 8459 | { |
| 8432 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 8460 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 8433 | 8461 | } |
| 8434 | 8462 | else |
| 8435 | 8463 | { |
| r2821 | r2822 | |
| 8440 | 8468 | break; |
| 8441 | 8469 | |
| 8442 | 8470 | case 1: |
| 8443 | | if(watch->numElements < 99) |
| 8444 | | watch->numElements++; |
| 8471 | if(watch->num_elements < 99) |
| 8472 | watch->num_elements++; |
| 8445 | 8473 | break; |
| 8446 | 8474 | |
| 8447 | 8475 | case 0: |
| 8448 | | watch->elementBytes = (watch->elementBytes + 1) & 0x03; |
| 8476 | watch->element_bytes = (watch->element_bytes + 1) & 0x03; |
| 8449 | 8477 | break; |
| 8450 | 8478 | } |
| 8451 | 8479 | } |
| r2821 | r2822 | |
| 8454 | 8482 | { |
| 8455 | 8483 | if(!editActive) |
| 8456 | 8484 | { |
| 8457 | | CURSOR_TO_NEXT(menu->sel, total) |
| 8485 | CURSOR_TO_NEXT(menu->sel, total); |
| 8458 | 8486 | } |
| 8459 | 8487 | else |
| 8460 | 8488 | { |
| r2821 | r2822 | |
| 8465 | 8493 | break; |
| 8466 | 8494 | |
| 8467 | 8495 | case 1: |
| 8468 | | if(watch->numElements > 0) |
| 8469 | | watch->numElements--; |
| 8496 | if(watch->num_elements > 0) |
| 8497 | watch->num_elements--; |
| 8470 | 8498 | break; |
| 8471 | 8499 | |
| 8472 | 8500 | case 0: |
| 8473 | | watch->elementBytes = (watch->elementBytes - 1) & 0x03; |
| 8501 | watch->element_bytes = (watch->element_bytes - 1) & 0x03; |
| 8474 | 8502 | break; |
| 8475 | 8503 | } |
| 8476 | 8504 | } |
| r2821 | r2822 | |
| 8478 | 8506 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 8479 | 8507 | { |
| 8480 | 8508 | if(!editActive) |
| 8481 | | CURSOR_PAGE_UP(menu->sel) |
| 8509 | CURSOR_PAGE_UP(menu->sel); |
| 8482 | 8510 | } |
| 8483 | 8511 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 8484 | 8512 | { |
| 8485 | 8513 | if(!editActive) |
| 8486 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 8514 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 8487 | 8515 | } |
| 8488 | 8516 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, kVerticalKeyRepeatRate)) |
| 8489 | 8517 | { |
| r2821 | r2822 | |
| 8522 | 8550 | if(!editActive && watch) |
| 8523 | 8551 | { |
| 8524 | 8552 | if(ShiftKeyPressed()) |
| 8525 | | AddCheatFromWatch(watch); |
| 8553 | add_cheat_from_watch(watch); |
| 8526 | 8554 | else if(ControlKeyPressed()) |
| 8527 | 8555 | { |
| 8528 | | CheatEntry * entry = GetNewCheat(); |
| 8556 | cheat_entry *entry = get_new_cheat(); |
| 8529 | 8557 | |
| 8530 | | DisposeCheat(entry); |
| 8531 | | SetupCheatFromWatchAsWatch(entry, watch); |
| 8558 | add_cheat_from_watch_as_watch(entry, watch); |
| 8532 | 8559 | |
| 8533 | 8560 | /* when fails to add, delete this entry because it causes the crash */ |
| 8534 | | if(messageType == kCheatMessage_FailedToAdd) |
| 8561 | if(message_type == kCheatMessage_FailedToAdd) |
| 8535 | 8562 | { |
| 8536 | | DeleteCheatAt(cheatListLength - 1); |
| 8537 | | messageType = kCheatMessage_FailedToAdd; |
| 8538 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 8563 | delete_cheat_at(cheat_list_length - 1); |
| 8564 | SET_MESSAGE(kCheatMessage_FailedToAdd); |
| 8539 | 8565 | } |
| 8540 | 8566 | } |
| 8541 | 8567 | else |
| 8542 | | AddWatchBefore(menu->sel); |
| 8568 | add_watch_before(menu->sel); |
| 8543 | 8569 | } |
| 8544 | 8570 | } |
| 8545 | 8571 | else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT)) |
| r2821 | r2822 | |
| 8548 | 8574 | { |
| 8549 | 8575 | if(ShiftKeyPressed()) |
| 8550 | 8576 | { |
| 8551 | | DeleteWatchAt(menu->sel); |
| 8577 | delete_watch_at(menu->sel); |
| 8552 | 8578 | } |
| 8553 | 8579 | else if(ControlKeyPressed()) |
| 8554 | 8580 | { |
| 8555 | | for(i = 0; i < watchListLength; i++) |
| 8556 | | watchList[i].numElements = 0; |
| 8581 | for(i = 0; i < watch_list_length; i++) |
| 8582 | watch_list[i].num_elements = 0; |
| 8557 | 8583 | } |
| 8558 | 8584 | else |
| 8559 | 8585 | { |
| 8560 | 8586 | if(watch) |
| 8561 | | watch->numElements = 0; |
| 8587 | watch->num_elements = 0; |
| 8562 | 8588 | } |
| 8563 | 8589 | } |
| 8564 | 8590 | else if(editActive) |
| r2821 | r2822 | |
| 8570 | 8596 | break; |
| 8571 | 8597 | |
| 8572 | 8598 | case 1: |
| 8573 | | watch->numElements = 0; |
| 8599 | watch->num_elements = 0; |
| 8574 | 8600 | break; |
| 8575 | 8601 | |
| 8576 | 8602 | case 0: |
| 8577 | | watch->elementBytes = 0; |
| 8603 | watch->element_bytes = 0; |
| 8578 | 8604 | } |
| 8579 | 8605 | } |
| 8580 | 8606 | } |
| r2821 | r2822 | |
| 8582 | 8608 | { |
| 8583 | 8609 | if(!editActive && watch) |
| 8584 | 8610 | { |
| 8585 | | CheatEntry entry; |
| 8611 | cheat_entry entry; |
| 8586 | 8612 | |
| 8587 | | memset(&entry, 0, sizeof(CheatEntry)); |
| 8613 | memset(&entry, 0, sizeof(cheat_entry)); |
| 8588 | 8614 | |
| 8589 | | SetupCheatFromWatchAsWatch(&entry, watch); |
| 8615 | add_cheat_from_watch_as_watch(&entry, watch); |
| 8590 | 8616 | SaveCheatCode(machine, &entry); |
| 8591 | | DisposeCheat(&entry); |
| 8617 | dispose_cheat(&entry); |
| 8592 | 8618 | } |
| 8593 | 8619 | } |
| 8594 | 8620 | else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT)) |
| r2821 | r2822 | |
| 8605 | 8631 | { |
| 8606 | 8632 | if(ShiftKeyPressed()) |
| 8607 | 8633 | { |
| 8608 | | if(watch) |
| 8609 | | ResetWatch(watch); |
| 8634 | reset_watch(watch); |
| 8610 | 8635 | } |
| 8611 | 8636 | else |
| 8612 | 8637 | { |
| 8613 | | for(i = 0; i < watchListLength; i++) |
| 8614 | | ResetWatch(&watchList[i]); |
| 8638 | for(i = 0; i < watch_list_length; i++) |
| 8639 | reset_watch(&watch_list[i]); |
| 8615 | 8640 | } |
| 8616 | 8641 | } |
| 8617 | 8642 | else |
| 8618 | 8643 | { |
| 8619 | 8644 | watch->address = 0; |
| 8620 | | watch->numElements = 0; |
| 8621 | | watch->elementBytes = 0; |
| 8645 | watch->num_elements = 0; |
| 8646 | watch->element_bytes = 0; |
| 8622 | 8647 | } |
| 8623 | 8648 | } |
| 8624 | 8649 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| r2821 | r2822 | |
| 8656 | 8681 | int i; |
| 8657 | 8682 | UINT8 total = 0; |
| 8658 | 8683 | ui_menu_item menuItem[kMenu_Max + 1]; |
| 8659 | | WatchInfo * entry = &watchList[menu->pre_sel]; |
| 8684 | watch_info *entry = &watch_list[menu->pre_sel]; |
| 8660 | 8685 | |
| 8661 | 8686 | /* first setting : NONE */ |
| 8662 | 8687 | if(menu->first_time) |
| r2821 | r2822 | |
| 8680 | 8705 | menuItem[total].text = NULL; |
| 8681 | 8706 | |
| 8682 | 8707 | /* adjust current cursor position */ |
| 8683 | | ADJUST_CURSOR(menu->sel, total) |
| 8708 | ADJUST_CURSOR(menu->sel, total); |
| 8684 | 8709 | |
| 8685 | 8710 | /* print it */ |
| 8686 | 8711 | ui_menu_draw(menuItem, total, menu->sel, NULL); |
| r2821 | r2822 | |
| 8688 | 8713 | /********** KEY HANDLING **********/ |
| 8689 | 8714 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 8690 | 8715 | { |
| 8691 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 8716 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 8692 | 8717 | } |
| 8693 | 8718 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 8694 | 8719 | { |
| 8695 | | CURSOR_TO_NEXT(menu->sel, total) |
| 8720 | CURSOR_TO_NEXT(menu->sel, total); |
| 8696 | 8721 | } |
| 8697 | 8722 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 8698 | 8723 | { |
| 8699 | | CURSOR_PAGE_UP(menu->sel) |
| 8724 | CURSOR_PAGE_UP(menu->sel); |
| 8700 | 8725 | } |
| 8701 | 8726 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 8702 | 8727 | { |
| 8703 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 8728 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 8704 | 8729 | } |
| 8705 | 8730 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 8706 | 8731 | { |
| r2821 | r2822 | |
| 8711 | 8736 | break; |
| 8712 | 8737 | |
| 8713 | 8738 | case kMenu_DisableWatch: |
| 8714 | | entry->numElements = 0; |
| 8739 | entry->num_elements = 0; |
| 8715 | 8740 | break; |
| 8716 | 8741 | |
| 8717 | 8742 | case kMenu_DisableAllWatch: |
| 8718 | | for(i = 0; i < watchListLength; i++) |
| 8719 | | watchList[i].numElements = 0; |
| 8743 | for(i = 0; i < watch_list_length; i++) |
| 8744 | watch_list[i].num_elements = 0; |
| 8720 | 8745 | break; |
| 8721 | 8746 | |
| 8722 | 8747 | case kMenu_ResetWatch: |
| 8723 | | ResetWatch(entry); |
| 8748 | reset_watch(entry); |
| 8724 | 8749 | break; |
| 8725 | 8750 | |
| 8726 | 8751 | case kMenu_ResetAllWatch: |
| 8727 | | for(i = 0; i < watchListLength; i++) |
| 8728 | | ResetWatch(&watchList[i]); |
| 8752 | for(i = 0; i < watch_list_length; i++) |
| 8753 | reset_watch(&watch_list[i]); |
| 8729 | 8754 | break; |
| 8730 | 8755 | |
| 8731 | 8756 | case kMenu_AddAsCheatCode: |
| 8732 | | AddCheatFromWatch(entry); |
| 8757 | add_cheat_from_watch(entry); |
| 8733 | 8758 | break; |
| 8734 | 8759 | |
| 8735 | 8760 | case kMenu_AddAsWatchCode: |
| 8736 | 8761 | { |
| 8737 | | CheatEntry * newEntry = GetNewCheat(); |
| 8762 | cheat_entry *new_entry = get_new_cheat(); |
| 8738 | 8763 | |
| 8739 | | DisposeCheat(newEntry); |
| 8740 | | SetupCheatFromWatchAsWatch(newEntry, entry); |
| 8764 | add_cheat_from_watch_as_watch(new_entry, entry); |
| 8741 | 8765 | |
| 8742 | 8766 | /* when fails to add, delete this entry because it causes the crash */ |
| 8743 | | if(messageType == kCheatMessage_FailedToAdd) |
| 8767 | if(message_type == kCheatMessage_FailedToAdd) |
| 8744 | 8768 | { |
| 8745 | | DeleteCheatAt(cheatListLength - 1); |
| 8746 | | messageType = kCheatMessage_FailedToAdd; |
| 8747 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 8769 | delete_cheat_at(cheat_list_length - 1); |
| 8770 | SET_MESSAGE(kCheatMessage_FailedToAdd); |
| 8748 | 8771 | } |
| 8749 | 8772 | } |
| 8750 | 8773 | break; |
| r2821 | r2822 | |
| 8755 | 8778 | |
| 8756 | 8779 | case kMenu_SaveAsWatchCode: |
| 8757 | 8780 | { |
| 8758 | | CheatEntry tempEntry; |
| 8781 | cheat_entry temp_entry; |
| 8759 | 8782 | |
| 8760 | | memset(&tempEntry, 0, sizeof(CheatEntry)); |
| 8783 | memset(&temp_entry, 0, sizeof(cheat_entry)); |
| 8761 | 8784 | |
| 8762 | | SetupCheatFromWatchAsWatch(&tempEntry, entry); |
| 8763 | | SaveCheatCode(machine, &tempEntry); |
| 8764 | | DisposeCheat(&tempEntry); |
| 8785 | add_cheat_from_watch_as_watch(&temp_entry, entry); |
| 8786 | SaveCheatCode(machine, &temp_entry); |
| 8787 | dispose_cheat(&temp_entry); |
| 8765 | 8788 | } |
| 8766 | 8789 | break; |
| 8767 | 8790 | |
| r2821 | r2822 | |
| 8771 | 8794 | } |
| 8772 | 8795 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 8773 | 8796 | { |
| 8774 | | ReloadCheatDatabase(machine); |
| 8797 | reload_cheat_database(machine); |
| 8775 | 8798 | } |
| 8776 | 8799 | else if(input_ui_pressed(machine, IPT_UI_CANCEL) || input_ui_pressed(machine, IPT_UI_LEFT) || input_ui_pressed(machine, IPT_UI_RIGHT)) |
| 8777 | 8800 | { |
| r2821 | r2822 | |
| 8813 | 8836 | const char ** menuSubItem; |
| 8814 | 8837 | char ** buf; |
| 8815 | 8838 | char * flagBuf; |
| 8816 | | WatchInfo * entry = &watchList[menu->pre_sel]; |
| 8817 | | cpu_region_info *info = get_cpu_or_region_info(entry->cpu); |
| 8839 | watch_info *entry = &watch_list[menu->pre_sel]; |
| 8840 | cpu_region_info *info = get_cpu_or_region_info(entry->cpu); |
| 8818 | 8841 | |
| 8819 | 8842 | /* first setting : NONE */ |
| 8820 | 8843 | if(menu->first_time) |
| r2821 | r2822 | |
| 8830 | 8853 | |
| 8831 | 8854 | /********** MENU CONSTRUCTION **********/ |
| 8832 | 8855 | /* ##### ADDRESS ##### */ |
| 8833 | | sprintf(buf[total], "%.*X", info->address_chars_needed, entry->address >> entry->addressShift); |
| 8856 | sprintf(buf[total], "%.*X", info->address_chars_needed, entry->address >> entry->address_shift); |
| 8834 | 8857 | menuItem[total] = "Address"; |
| 8835 | 8858 | menuSubItem[total] = buf[total]; |
| 8836 | 8859 | total++; |
| 8837 | 8860 | |
| 8838 | 8861 | /* ##### CPU/REGION ##### */ |
| 8839 | 8862 | sprintf(buf[total], "%s", get_region_name(entry->cpu)); |
| 8840 | | menuItem[total] = TEST_FIELD(entry->cpu, RegionFlag) ? "Region" : "CPU"; |
| 8863 | menuItem[total] = entry->cpu < REGION_INVALID ? "CPU" : "Region"; |
| 8841 | 8864 | menuSubItem[total] = buf[total]; |
| 8842 | 8865 | total++; |
| 8843 | 8866 | |
| 8844 | 8867 | /* ##### LENGTH ##### */ |
| 8845 | | sprintf(buf[total], "%d", entry->numElements); |
| 8868 | sprintf(buf[total], "%d", entry->num_elements); |
| 8846 | 8869 | menuItem[total] = "Length"; |
| 8847 | 8870 | menuSubItem[total] = buf[total]; |
| 8848 | 8871 | total++; |
| 8849 | 8872 | |
| 8850 | 8873 | /* ##### ELEMENT SIZE ##### */ |
| 8851 | 8874 | menuItem[total] = "Element Size"; |
| 8852 | | menuSubItem[total++] = kByteSizeStringList[entry->elementBytes]; |
| 8875 | menuSubItem[total++] = kByteSizeStringList[entry->element_bytes]; |
| 8853 | 8876 | |
| 8854 | 8877 | /* ##### LABEL TYPE ##### */ |
| 8855 | 8878 | menuItem[total] = "Label Type"; |
| 8856 | | menuSubItem[total++] = kWatchLabelStringList[entry->labelType]; |
| 8879 | menuSubItem[total++] = kWatchLabelStringList[entry->label_type]; |
| 8857 | 8880 | |
| 8858 | 8881 | /* ##### TEXT LABEL ##### */ |
| 8859 | 8882 | menuItem[total] = "Text Label"; |
| r2821 | r2822 | |
| 8864 | 8887 | |
| 8865 | 8888 | /* ##### DISPLAY TYPE ##### */ |
| 8866 | 8889 | menuItem[total] = "Display Type"; |
| 8867 | | menuSubItem[total++] = kWatchDisplayTypeStringList[entry->displayType]; |
| 8890 | menuSubItem[total++] = kWatchDisplayTypeStringList[entry->display_type]; |
| 8868 | 8891 | |
| 8869 | 8892 | /* ##### X POSITION ##### */ |
| 8870 | 8893 | sprintf(buf[total], "%f", entry->x); |
| r2821 | r2822 | |
| 8885 | 8908 | total++; |
| 8886 | 8909 | |
| 8887 | 8910 | /* ##### ELEMENTS PER LINE ##### */ |
| 8888 | | sprintf(buf[total], "%d", entry->elementsPerLine); |
| 8911 | sprintf(buf[total], "%d", entry->elements_per_line); |
| 8889 | 8912 | menuItem[total] = "Elements Per Line"; |
| 8890 | 8913 | menuSubItem[total] = buf[total]; |
| 8891 | 8914 | total++; |
| 8892 | 8915 | |
| 8893 | 8916 | /* ##### ADD VALUE ##### */ |
| 8894 | 8917 | menuItem[total] = "Add Value"; |
| 8895 | | if(entry->addValue < 0) |
| 8896 | | sprintf(buf[total], "-%.2X", -entry->addValue); |
| 8918 | if(entry->add_value < 0) |
| 8919 | sprintf(buf[total], "-%.2X", -entry->add_value); |
| 8897 | 8920 | else |
| 8898 | | sprintf(buf[total], "%.2X", entry->addValue); |
| 8921 | sprintf(buf[total], "%.2X", entry->add_value); |
| 8899 | 8922 | menuSubItem[total] = buf[total]; |
| 8900 | 8923 | total++; |
| 8901 | 8924 | |
| 8902 | 8925 | /* ##### ADDRESS SHIFT ##### */ |
| 8903 | | sprintf(buf[total], "%d", entry->addressShift); |
| 8926 | sprintf(buf[total], "%d", entry->address_shift); |
| 8904 | 8927 | menuItem[total] = "Address Shift"; |
| 8905 | 8928 | menuSubItem[total] = buf[total]; |
| 8906 | 8929 | total++; |
| 8907 | 8930 | |
| 8908 | 8931 | /* ##### DATA SHIFT ##### */ |
| 8909 | | sprintf(buf[total], "%d", entry->dataShift); |
| 8932 | sprintf(buf[total], "%d", entry->data_shift); |
| 8910 | 8933 | menuItem[total] = "Data Shift"; |
| 8911 | 8934 | menuSubItem[total] = buf[total]; |
| 8912 | 8935 | total++; |
| 8913 | 8936 | |
| 8914 | 8937 | /* ##### XOR ##### */ |
| 8915 | | sprintf(buf[total], "%.*X", kSearchByteDigitsTable[kWatchSizeConversionTable[entry->elementBytes]], entry->xor); |
| 8938 | sprintf(buf[total], "%.*X", kSearchByteDigitsTable[kWatchSizeConversionTable[entry->element_bytes]], entry->xor); |
| 8916 | 8939 | menuItem[total] = "XOR"; |
| 8917 | 8940 | menuSubItem[total] = buf[total]; |
| 8918 | 8941 | total++; |
| r2821 | r2822 | |
| 8926 | 8949 | menuSubItem[total] = NULL; |
| 8927 | 8950 | |
| 8928 | 8951 | /* adjust current cursor position */ |
| 8929 | | ADJUST_CURSOR(menu->sel, total) |
| 8952 | ADJUST_CURSOR(menu->sel, total); |
| 8930 | 8953 | |
| 8931 | 8954 | /* higlighted sub-item if edit mode */ |
| 8932 | 8955 | if(editActive) |
| r2821 | r2822 | |
| 8938 | 8961 | /********** KEY HANDLING **********/ |
| 8939 | 8962 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 8940 | 8963 | { |
| 8941 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 8964 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 8942 | 8965 | } |
| 8943 | 8966 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 8944 | 8967 | { |
| 8945 | | CURSOR_TO_NEXT(menu->sel, total) |
| 8968 | CURSOR_TO_NEXT(menu->sel, total); |
| 8946 | 8969 | } |
| 8947 | 8970 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 8948 | 8971 | { |
| 8949 | | CURSOR_PAGE_UP(menu->sel) |
| 8972 | CURSOR_PAGE_UP(menu->sel); |
| 8950 | 8973 | } |
| 8951 | 8974 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 8952 | 8975 | { |
| 8953 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 8976 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 8954 | 8977 | } |
| 8955 | 8978 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate)) |
| 8956 | 8979 | { |
| r2821 | r2822 | |
| 8963 | 8986 | switch(menu->sel) |
| 8964 | 8987 | { |
| 8965 | 8988 | case kMenu_Address: |
| 8966 | | entry->address = DoShift(entry->address, entry->addressShift); |
| 8989 | entry->address = DoShift(entry->address, entry->address_shift); |
| 8967 | 8990 | entry->address -= increment; |
| 8968 | | entry->address = DoShift(entry->address, -entry->addressShift); |
| 8991 | entry->address = DoShift(entry->address, -entry->address_shift); |
| 8969 | 8992 | |
| 8970 | | if(!TEST_FIELD(entry->cpu, RegionFlag)) |
| 8993 | if(entry->cpu < REGION_INVALID) |
| 8971 | 8994 | entry->address &= info->address_mask; |
| 8972 | 8995 | break; |
| 8973 | 8996 | |
| r2821 | r2822 | |
| 8981 | 9004 | break; |
| 8982 | 9005 | |
| 8983 | 9006 | case kMenu_NumElements: |
| 8984 | | if(entry->numElements > 0) |
| 8985 | | entry->numElements--; |
| 9007 | if(entry->num_elements > 0) |
| 9008 | entry->num_elements--; |
| 8986 | 9009 | else |
| 8987 | | entry->numElements = 0; |
| 9010 | entry->num_elements = 0; |
| 8988 | 9011 | break; |
| 8989 | 9012 | |
| 8990 | 9013 | case kMenu_ElementSize: |
| 8991 | | if(entry->elementBytes > 0) |
| 8992 | | entry->elementBytes--; |
| 9014 | if(entry->element_bytes > 0) |
| 9015 | entry->element_bytes--; |
| 8993 | 9016 | else |
| 8994 | | entry->elementBytes = 0; |
| 9017 | entry->element_bytes = 0; |
| 8995 | 9018 | |
| 8996 | | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]]; |
| 9019 | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->element_bytes]]; |
| 8997 | 9020 | break; |
| 8998 | 9021 | |
| 8999 | 9022 | case kMenu_LabelType: |
| 9000 | | if(entry->labelType > 0) |
| 9001 | | entry->labelType--; |
| 9023 | if(entry->label_type > 0) |
| 9024 | entry->label_type--; |
| 9002 | 9025 | else |
| 9003 | | entry->labelType = 0; |
| 9026 | entry->label_type = 0; |
| 9004 | 9027 | break; |
| 9005 | 9028 | |
| 9006 | 9029 | case kMenu_TextLabel: |
| 9007 | 9030 | break; |
| 9008 | 9031 | |
| 9009 | 9032 | case kMenu_DisplayType: |
| 9010 | | if(entry->displayType > 0) |
| 9011 | | entry->displayType--; |
| 9033 | if(entry->display_type > 0) |
| 9034 | entry->display_type--; |
| 9012 | 9035 | else |
| 9013 | | entry->displayType = 0; |
| 9036 | entry->display_type = 0; |
| 9014 | 9037 | break; |
| 9015 | 9038 | |
| 9016 | 9039 | case kMenu_XPosition: |
| r2821 | r2822 | |
| 9027 | 9050 | break; |
| 9028 | 9051 | |
| 9029 | 9052 | case kMenu_ElementsPerLine: |
| 9030 | | if(entry->elementsPerLine > 0) |
| 9031 | | entry->elementsPerLine--; |
| 9053 | if(entry->elements_per_line > 0) |
| 9054 | entry->elements_per_line--; |
| 9032 | 9055 | break; |
| 9033 | 9056 | |
| 9034 | 9057 | case kMenu_AddValue: |
| 9035 | | entry->addValue = (entry->addValue - 1) & 0xFF; |
| 9058 | entry->add_value = (entry->add_value - 1) & 0xFF; |
| 9036 | 9059 | break; |
| 9037 | 9060 | |
| 9038 | 9061 | case kMenu_AddressShift: |
| 9039 | | if(entry->addressShift > -31) |
| 9040 | | entry->addressShift--; |
| 9062 | if(entry->address_shift > -31) |
| 9063 | entry->address_shift--; |
| 9041 | 9064 | else |
| 9042 | | entry->addressShift = 31; |
| 9065 | entry->address_shift = 31; |
| 9043 | 9066 | break; |
| 9044 | 9067 | |
| 9045 | 9068 | case kMenu_DataShift: |
| 9046 | | if(entry->dataShift > -31) |
| 9047 | | entry->dataShift--; |
| 9069 | if(entry->data_shift > -31) |
| 9070 | entry->data_shift--; |
| 9048 | 9071 | else |
| 9049 | | entry->dataShift = 31; |
| 9072 | entry->data_shift = 31; |
| 9050 | 9073 | break; |
| 9051 | 9074 | |
| 9052 | 9075 | case kMenu_XOR: |
| 9053 | 9076 | entry->xor -= increment; |
| 9054 | | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]]; |
| 9077 | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->element_bytes]]; |
| 9055 | 9078 | } |
| 9056 | 9079 | } |
| 9057 | 9080 | } |
| r2821 | r2822 | |
| 9066 | 9089 | switch(menu->sel) |
| 9067 | 9090 | { |
| 9068 | 9091 | case kMenu_Address: |
| 9069 | | entry->address = DoShift(entry->address, entry->addressShift); |
| 9092 | entry->address = DoShift(entry->address, entry->address_shift); |
| 9070 | 9093 | entry->address += increment; |
| 9071 | | entry->address = DoShift(entry->address, -entry->addressShift); |
| 9094 | entry->address = DoShift(entry->address, -entry->address_shift); |
| 9072 | 9095 | |
| 9073 | | if(!TEST_FIELD(entry->cpu, RegionFlag)) |
| 9096 | if(entry->cpu < REGION_INVALID) |
| 9074 | 9097 | entry->address &= info->address_mask; |
| 9075 | 9098 | break; |
| 9076 | 9099 | |
| r2821 | r2822 | |
| 9084 | 9107 | break; |
| 9085 | 9108 | |
| 9086 | 9109 | case kMenu_NumElements: |
| 9087 | | entry->numElements++; |
| 9110 | entry->num_elements++; |
| 9088 | 9111 | break; |
| 9089 | 9112 | |
| 9090 | 9113 | case kMenu_ElementSize: |
| 9091 | | if(entry->elementBytes < kSearchSize_32Bit) |
| 9092 | | entry->elementBytes++; |
| 9114 | if(entry->element_bytes < kSearchSize_32Bit) |
| 9115 | entry->element_bytes++; |
| 9093 | 9116 | else |
| 9094 | | entry->elementBytes = kSearchSize_32Bit; |
| 9117 | entry->element_bytes = kSearchSize_32Bit; |
| 9095 | 9118 | |
| 9096 | | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]]; |
| 9119 | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->element_bytes]]; |
| 9097 | 9120 | break; |
| 9098 | 9121 | |
| 9099 | 9122 | case kMenu_LabelType: |
| 9100 | | if(entry->labelType < kWatchLabel_MaxPlusOne - 1) |
| 9101 | | entry->labelType++; |
| 9123 | if(entry->label_type < kWatchLabel_MaxPlusOne - 1) |
| 9124 | entry->label_type++; |
| 9102 | 9125 | else |
| 9103 | | entry->labelType = kWatchLabel_MaxPlusOne - 1; |
| 9126 | entry->label_type = kWatchLabel_MaxPlusOne - 1; |
| 9104 | 9127 | break; |
| 9105 | 9128 | |
| 9106 | 9129 | case kMenu_TextLabel: |
| 9107 | 9130 | break; |
| 9108 | 9131 | |
| 9109 | 9132 | case kMenu_DisplayType: |
| 9110 | | if(entry->displayType < kWatchDisplayType_MaxPlusOne - 1) |
| 9111 | | entry->displayType++; |
| 9133 | if(entry->display_type < kWatchDisplayType_MaxPlusOne - 1) |
| 9134 | entry->display_type++; |
| 9112 | 9135 | else |
| 9113 | | entry->displayType = kWatchDisplayType_MaxPlusOne - 1; |
| 9136 | entry->display_type = kWatchDisplayType_MaxPlusOne - 1; |
| 9114 | 9137 | break; |
| 9115 | 9138 | |
| 9116 | 9139 | case kMenu_XPosition: |
| r2821 | r2822 | |
| 9126 | 9149 | break; |
| 9127 | 9150 | |
| 9128 | 9151 | case kMenu_ElementsPerLine: |
| 9129 | | entry->elementsPerLine++; |
| 9152 | entry->elements_per_line++; |
| 9130 | 9153 | break; |
| 9131 | 9154 | |
| 9132 | 9155 | case kMenu_AddValue: |
| 9133 | | entry->addValue = (entry->addValue + 1) & 0xFF; |
| 9156 | entry->add_value = (entry->add_value + 1) & 0xFF; |
| 9134 | 9157 | break; |
| 9135 | 9158 | |
| 9136 | 9159 | case kMenu_AddressShift: |
| 9137 | | if(entry->addressShift < 31) |
| 9138 | | entry->addressShift++; |
| 9160 | if(entry->address_shift < 31) |
| 9161 | entry->address_shift++; |
| 9139 | 9162 | else |
| 9140 | | entry->addressShift = -31; |
| 9163 | entry->address_shift = -31; |
| 9141 | 9164 | break; |
| 9142 | 9165 | |
| 9143 | 9166 | case kMenu_DataShift: |
| 9144 | | if(entry->dataShift < 31) |
| 9145 | | entry->dataShift++; |
| 9167 | if(entry->data_shift < 31) |
| 9168 | entry->data_shift++; |
| 9146 | 9169 | else |
| 9147 | | entry->dataShift = -31; |
| 9170 | entry->data_shift = -31; |
| 9148 | 9171 | break; |
| 9149 | 9172 | |
| 9150 | 9173 | case kMenu_XOR: |
| 9151 | 9174 | entry->xor += increment; |
| 9152 | | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]]; |
| 9175 | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->element_bytes]]; |
| 9153 | 9176 | } |
| 9154 | 9177 | } |
| 9155 | 9178 | } |
| r2821 | r2822 | |
| 9182 | 9205 | } |
| 9183 | 9206 | else if(input_ui_pressed(machine, IPT_UI_CLEAR)) |
| 9184 | 9207 | { |
| 9185 | | ResetWatch(entry); |
| 9208 | reset_watch(entry); |
| 9186 | 9209 | } |
| 9187 | 9210 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 9188 | 9211 | { |
| r2821 | r2822 | |
| 9197 | 9220 | switch(menu->sel) |
| 9198 | 9221 | { |
| 9199 | 9222 | case kMenu_Address: |
| 9200 | | entry->address = DoShift(entry->address, entry->addressShift); |
| 9223 | entry->address = DoShift(entry->address, entry->address_shift); |
| 9201 | 9224 | entry->address = do_edit_hex_field(machine, entry->address); |
| 9202 | | entry->address = DoShift(entry->address, -entry->addressShift); |
| 9225 | entry->address = DoShift(entry->address, -entry->address_shift); |
| 9203 | 9226 | entry->address &= info->address_mask; |
| 9204 | 9227 | break; |
| 9205 | 9228 | |
| r2821 | r2822 | |
| 9209 | 9232 | break; |
| 9210 | 9233 | |
| 9211 | 9234 | case kMenu_NumElements: |
| 9212 | | entry->numElements = DoEditDecField(entry->numElements, 0, 99); |
| 9235 | entry->num_elements = DoEditDecField(entry->num_elements, 0, 99); |
| 9213 | 9236 | break; |
| 9214 | 9237 | |
| 9215 | 9238 | case kMenu_TextLabel: |
| r2821 | r2822 | |
| 9225 | 9248 | break; |
| 9226 | 9249 | |
| 9227 | 9250 | case kMenu_AddValue: |
| 9228 | | entry->addValue = DoEditHexFieldSigned(entry->addValue, 0xFFFFFF80) & 0xFF; |
| 9251 | entry->add_value = DoEditHexFieldSigned(entry->add_value, 0xFFFFFF80) & 0xFF; |
| 9229 | 9252 | break; |
| 9230 | 9253 | |
| 9231 | 9254 | case kMenu_AddressShift: |
| 9232 | | entry->addressShift = DoEditDecField(entry->addressShift, -31, 31); |
| 9255 | entry->address_shift = DoEditDecField(entry->address_shift, -31, 31); |
| 9233 | 9256 | break; |
| 9234 | 9257 | |
| 9235 | 9258 | case kMenu_DataShift: |
| 9236 | | entry->dataShift = DoEditDecField(entry->dataShift, -31, 31); |
| 9259 | entry->data_shift = DoEditDecField(entry->data_shift, -31, 31); |
| 9237 | 9260 | break; |
| 9238 | 9261 | |
| 9239 | 9262 | case kMenu_XOR: |
| 9240 | 9263 | entry->xor = do_edit_hex_field(machine, entry->xor); |
| 9241 | | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->elementBytes]]; |
| 9264 | entry->xor &= kSearchByteMaskTable[kWatchSizeConversionTable[entry->element_bytes]]; |
| 9242 | 9265 | break; |
| 9243 | 9266 | } |
| 9244 | 9267 | } |
| 9245 | 9268 | else |
| 9246 | 9269 | { |
| 9247 | 9270 | if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT)) |
| 9248 | | AddCheatFromWatch(entry); |
| 9271 | add_cheat_from_watch(entry); |
| 9249 | 9272 | |
| 9250 | 9273 | if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT)) |
| 9251 | | entry->numElements = 0; |
| 9274 | entry->num_elements = 0; |
| 9252 | 9275 | |
| 9253 | 9276 | if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT)) |
| 9254 | 9277 | { |
| 9255 | | CheatEntry tempEntry; |
| 9278 | cheat_entry temp_entry; |
| 9256 | 9279 | |
| 9257 | | memset(&tempEntry, 0, sizeof(CheatEntry)); |
| 9280 | memset(&temp_entry, 0, sizeof(cheat_entry)); |
| 9258 | 9281 | |
| 9259 | | SetupCheatFromWatchAsWatch(&tempEntry, entry); |
| 9260 | | SaveCheatCode(machine, &tempEntry); |
| 9261 | | DisposeCheat(&tempEntry); |
| 9282 | add_cheat_from_watch_as_watch(&temp_entry, entry); |
| 9283 | SaveCheatCode(machine, &temp_entry); |
| 9284 | dispose_cheat(&temp_entry); |
| 9262 | 9285 | } |
| 9263 | 9286 | } |
| 9264 | 9287 | |
| r2821 | r2822 | |
| 9273 | 9296 | { |
| 9274 | 9297 | enum{ |
| 9275 | 9298 | kMenu_SelectSearch = 0, |
| 9276 | | kMenu_LoadCheatOptions, |
| 9277 | | kMenu_SaveCheatOptions, |
| 9278 | | kMenu_ResetCheatOptions, |
| 9299 | kMenu_Loadcheat_options, |
| 9300 | kMenu_Savecheat_options, |
| 9301 | kMenu_Resetcheat_options, |
| 9279 | 9302 | kMenu_Separator, |
| 9280 | 9303 | kMenu_SearchDialogStyle, |
| 9281 | 9304 | kMenu_ShowSearchLabels, |
| r2821 | r2822 | |
| 9315 | 9338 | |
| 9316 | 9339 | /* ##### SEARCH MENU ##### */ |
| 9317 | 9340 | menu_item[total] = "Search Dialog Style"; |
| 9318 | | switch(EXTRACT_FIELD(cheatOptions, SearchBox)) |
| 9341 | switch(EXTRACT_FIELD(cheat_options, SearchBox)) |
| 9319 | 9342 | { |
| 9320 | 9343 | case kSearchBox_Minimum: |
| 9321 | 9344 | menu_sub_item[total++] = "Minimum"; |
| r2821 | r2822 | |
| 9335 | 9358 | } |
| 9336 | 9359 | |
| 9337 | 9360 | /* ##### SEARCH LABEL ##### */ |
| 9338 | | ADD_MENU_2_ITEMS("Show Search Labels", TEST_FIELD(cheatOptions, DontPrintNewLabels) ? "Off" : "On"); |
| 9361 | ADD_MENU_2_ITEMS("Show Search Labels", TEST_FIELD(cheat_options, DontPrintNewLabels) ? "Off" : "On"); |
| 9339 | 9362 | |
| 9340 | 9363 | /* ##### AUTO SAVE ##### */ |
| 9341 | | ADD_MENU_2_ITEMS("Auto Save Cheats", TEST_FIELD(cheatOptions, AutoSaveEnabled) ? "On" : "Off"); |
| 9364 | ADD_MENU_2_ITEMS("Auto Save Cheats", TEST_FIELD(cheat_options, AutoSaveEnabled) ? "On" : "Off"); |
| 9342 | 9365 | |
| 9343 | 9366 | /* ##### ACTIVATION KEY MESSAGE ##### */ |
| 9344 | | ADD_MENU_2_ITEMS("Show Activation Key Message", TEST_FIELD(cheatOptions, ActivationKeyMessage) ? "On" : "Off"); |
| 9367 | ADD_MENU_2_ITEMS("Show Activation Key Message", TEST_FIELD(cheat_options, ActivationKeyMessage) ? "On" : "Off"); |
| 9345 | 9368 | |
| 9346 | 9369 | /* ##### OLD FORMAT LOADING ##### */ |
| 9347 | | ADD_MENU_2_ITEMS("Load Old Format Code", TEST_FIELD(cheatOptions, LoadOldFormat) ? "On" : "Off"); |
| 9370 | ADD_MENU_2_ITEMS("Load Old Format Code", TEST_FIELD(cheat_options, LoadOldFormat) ? "On" : "Off"); |
| 9348 | 9371 | |
| 9349 | 9372 | #ifdef MESS |
| 9350 | 9373 | /* ##### SHARED CODE ##### */ |
| 9351 | | ADD_MENU_2_ITEMS("Shared Code", TEST_FIELD(cheatOptions, SharedCode) ? "On" : "Off"); |
| 9374 | ADD_MENU_2_ITEMS("Shared Code", TEST_FIELD(cheat_options, SharedCode) ? "On" : "Off"); |
| 9352 | 9375 | #endif |
| 9353 | 9376 | |
| 9354 | 9377 | /* ##### RETURN ##### */ |
| r2821 | r2822 | |
| 9363 | 9386 | /********** KEY HANDLING **********/ |
| 9364 | 9387 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 9365 | 9388 | { |
| 9366 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 9389 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 9367 | 9390 | |
| 9368 | 9391 | if(menu->sel == kMenu_Separator) |
| 9369 | 9392 | menu->sel--; |
| 9370 | 9393 | } |
| 9371 | 9394 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 9372 | 9395 | { |
| 9373 | | CURSOR_TO_NEXT(menu->sel, total) |
| 9396 | CURSOR_TO_NEXT(menu->sel, total); |
| 9374 | 9397 | |
| 9375 | 9398 | if(menu->sel == kMenu_Separator) |
| 9376 | 9399 | menu->sel++; |
| 9377 | 9400 | } |
| 9378 | 9401 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 9379 | 9402 | { |
| 9380 | | CURSOR_PAGE_UP(menu->sel) |
| 9403 | CURSOR_PAGE_UP(menu->sel); |
| 9381 | 9404 | } |
| 9382 | 9405 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 9383 | 9406 | { |
| 9384 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 9407 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 9385 | 9408 | } |
| 9386 | 9409 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate)) |
| 9387 | 9410 | { |
| r2821 | r2822 | |
| 9389 | 9412 | { |
| 9390 | 9413 | case kMenu_SearchDialogStyle: |
| 9391 | 9414 | { |
| 9392 | | UINT8 length = (EXTRACT_FIELD(cheatOptions, SearchBox) - 1) & 3; |
| 9415 | UINT8 length = (EXTRACT_FIELD(cheat_options, SearchBox) - 1) & 3; |
| 9393 | 9416 | |
| 9394 | 9417 | if(length > kSearchBox_Advanced) |
| 9395 | 9418 | length = kSearchBox_Advanced; |
| 9396 | 9419 | |
| 9397 | | SET_FIELD(cheatOptions, SearchBox, length); |
| 9420 | SET_FIELD(cheat_options, SearchBox, length); |
| 9398 | 9421 | } |
| 9399 | 9422 | break; |
| 9400 | 9423 | |
| 9401 | 9424 | case kMenu_ShowSearchLabels: |
| 9402 | | TOGGLE_MASK_FIELD(cheatOptions, DontPrintNewLabels); |
| 9425 | TOGGLE_MASK_FIELD(cheat_options, DontPrintNewLabels); |
| 9403 | 9426 | break; |
| 9404 | 9427 | |
| 9405 | 9428 | case kMenu_AutoSaveCheats: |
| 9406 | | TOGGLE_MASK_FIELD(cheatOptions, AutoSaveEnabled); |
| 9429 | TOGGLE_MASK_FIELD(cheat_options, AutoSaveEnabled); |
| 9407 | 9430 | break; |
| 9408 | 9431 | |
| 9409 | 9432 | case kMenu_ShowActivationKeyMessage: |
| 9410 | | TOGGLE_MASK_FIELD(cheatOptions, ActivationKeyMessage); |
| 9433 | TOGGLE_MASK_FIELD(cheat_options, ActivationKeyMessage); |
| 9411 | 9434 | break; |
| 9412 | 9435 | |
| 9413 | 9436 | case kMenu_LoadOldFormat: |
| 9414 | | TOGGLE_MASK_FIELD(cheatOptions, LoadOldFormat); |
| 9437 | TOGGLE_MASK_FIELD(cheat_options, LoadOldFormat); |
| 9415 | 9438 | break; |
| 9416 | 9439 | #ifdef MESS |
| 9417 | 9440 | case kMenu_SharedCode: |
| 9418 | | TOGGLE_MASK_FIELD(cheatOptions, SharedCode); |
| 9441 | TOGGLE_MASK_FIELD(cheat_options, SharedCode); |
| 9419 | 9442 | #endif |
| 9420 | 9443 | } |
| 9421 | 9444 | } |
| r2821 | r2822 | |
| 9425 | 9448 | { |
| 9426 | 9449 | case kMenu_SearchDialogStyle: |
| 9427 | 9450 | { |
| 9428 | | UINT8 length = (EXTRACT_FIELD(cheatOptions, SearchBox) + 1) & 3; |
| 9451 | UINT8 length = (EXTRACT_FIELD(cheat_options, SearchBox) + 1) & 3; |
| 9429 | 9452 | |
| 9430 | 9453 | if(length > kSearchBox_Advanced) |
| 9431 | 9454 | length = kSearchBox_Minimum; |
| 9432 | 9455 | |
| 9433 | | SET_FIELD(cheatOptions, SearchBox, length); |
| 9456 | SET_FIELD(cheat_options, SearchBox, length); |
| 9434 | 9457 | } |
| 9435 | 9458 | break; |
| 9436 | 9459 | |
| 9437 | 9460 | case kMenu_ShowSearchLabels: |
| 9438 | | TOGGLE_MASK_FIELD(cheatOptions, DontPrintNewLabels); |
| 9461 | TOGGLE_MASK_FIELD(cheat_options, DontPrintNewLabels); |
| 9439 | 9462 | break; |
| 9440 | 9463 | |
| 9441 | 9464 | case kMenu_AutoSaveCheats: |
| 9442 | | TOGGLE_MASK_FIELD(cheatOptions, AutoSaveEnabled); |
| 9465 | TOGGLE_MASK_FIELD(cheat_options, AutoSaveEnabled); |
| 9443 | 9466 | break; |
| 9444 | 9467 | |
| 9445 | 9468 | case kMenu_ShowActivationKeyMessage: |
| 9446 | | TOGGLE_MASK_FIELD(cheatOptions, ActivationKeyMessage); |
| 9469 | TOGGLE_MASK_FIELD(cheat_options, ActivationKeyMessage); |
| 9447 | 9470 | break; |
| 9448 | 9471 | |
| 9449 | 9472 | case kMenu_LoadOldFormat: |
| 9450 | | TOGGLE_MASK_FIELD(cheatOptions, LoadOldFormat); |
| 9473 | TOGGLE_MASK_FIELD(cheat_options, LoadOldFormat); |
| 9451 | 9474 | |
| 9452 | 9475 | #ifdef MESS |
| 9453 | 9476 | case kMenu_SharedCode: |
| 9454 | | TOGGLE_MASK_FIELD(cheatOptions, SharedCode); |
| 9477 | TOGGLE_MASK_FIELD(cheat_options, SharedCode); |
| 9455 | 9478 | #endif |
| 9456 | 9479 | } |
| 9457 | 9480 | } |
| r2821 | r2822 | |
| 9463 | 9486 | cheat_menu_stack_push(select_search_menu, menu->handler, menu->sel); |
| 9464 | 9487 | break; |
| 9465 | 9488 | |
| 9466 | | case kMenu_LoadCheatOptions: |
| 9467 | | LoadCheatDatabase(machine, kLoadFlag_CheatOption); |
| 9489 | case kMenu_Loadcheat_options: |
| 9490 | load_cheat_database(machine, kLoadFlag_CheatOption); |
| 9468 | 9491 | break; |
| 9469 | 9492 | |
| 9470 | | case kMenu_SaveCheatOptions: |
| 9471 | | SaveCheatOptions(); |
| 9493 | case kMenu_Savecheat_options: |
| 9494 | Savecheat_options(); |
| 9472 | 9495 | break; |
| 9473 | 9496 | |
| 9474 | | case kMenu_ResetCheatOptions: |
| 9475 | | cheatOptions = DEFAULT_CHEAT_OPTIONS; |
| 9497 | case kMenu_Resetcheat_options: |
| 9498 | cheat_options = DEFAULT_CHEAT_OPTIONS; |
| 9476 | 9499 | break; |
| 9477 | 9500 | |
| 9478 | 9501 | case kMenu_Return: |
| r2821 | r2822 | |
| 9481 | 9504 | } |
| 9482 | 9505 | else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT)) |
| 9483 | 9506 | { |
| 9484 | | SaveCheatOptions(); |
| 9507 | Savecheat_options(); |
| 9485 | 9508 | } |
| 9486 | 9509 | else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT)) |
| 9487 | 9510 | { |
| 9488 | | LoadCheatDatabase(machine, kLoadFlag_CheatOption); |
| 9511 | load_cheat_database(machine, kLoadFlag_CheatOption); |
| 9489 | 9512 | } |
| 9490 | 9513 | else if(input_ui_pressed(machine, IPT_UI_CANCEL)) |
| 9491 | 9514 | { |
| r2821 | r2822 | |
| 9769 | 9792 | old_style_menu(menuItem, menuSubItem, NULL, menu->sel, 0); |
| 9770 | 9793 | |
| 9771 | 9794 | /* adjust current cursor position */ |
| 9772 | | ADJUST_CURSOR(menu->sel, total) |
| 9795 | ADJUST_CURSOR(menu->sel, total); |
| 9773 | 9796 | |
| 9774 | 9797 | /********** KEY HANDLING **********/ |
| 9775 | 9798 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 9776 | 9799 | { |
| 9777 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 9800 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 9778 | 9801 | } |
| 9779 | 9802 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 9780 | 9803 | { |
| 9781 | | CURSOR_TO_NEXT(menu->sel, total) |
| 9804 | CURSOR_TO_NEXT(menu->sel, total); |
| 9782 | 9805 | } |
| 9783 | 9806 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 9784 | 9807 | { |
| 9785 | | CURSOR_PAGE_UP(menu->sel) |
| 9808 | CURSOR_PAGE_UP(menu->sel); |
| 9786 | 9809 | } |
| 9787 | 9810 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 9788 | 9811 | { |
| 9789 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 9812 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 9790 | 9813 | } |
| 9791 | 9814 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate)) |
| 9792 | 9815 | { |
| r2821 | r2822 | |
| 9858 | 9881 | kMenu_CRC, |
| 9859 | 9882 | #endif |
| 9860 | 9883 | kMenu_FullMenuPageHeight, |
| 9861 | | kMenu_CheatListLength, |
| 9884 | kMenu_cheat_list_length, |
| 9862 | 9885 | kMenu_Separator, |
| 9863 | 9886 | kMenu_CPURegionInfo, |
| 9864 | 9887 | kMenu_KeyCodeChecker, |
| r2821 | r2822 | |
| 9923 | 9946 | |
| 9924 | 9947 | /* ##### CHEAT LIST LENGTH ##### */ |
| 9925 | 9948 | menuItem[total] = "Total Code Entries"; |
| 9926 | | sprintf(numCodeBuf, "%d", cheatListLength); |
| 9949 | sprintf(numCodeBuf, "%d", cheat_list_length); |
| 9927 | 9950 | menuSubItem[total++] = numCodeBuf; |
| 9928 | 9951 | |
| 9929 | 9952 | /* ##### SEPARATOR ##### */ |
| r2821 | r2822 | |
| 9947 | 9970 | menuSubItem[total] = NULL; |
| 9948 | 9971 | |
| 9949 | 9972 | /* adjust cursor position */ |
| 9950 | | ADJUST_CURSOR(menu->sel, total) |
| 9973 | ADJUST_CURSOR(menu->sel, total); |
| 9951 | 9974 | |
| 9952 | 9975 | /* draw it */ |
| 9953 | 9976 | old_style_menu(menuItem, menuSubItem, NULL, menu->sel, 0); |
| r2821 | r2822 | |
| 9955 | 9978 | /********** KEY HANDLING **********/ |
| 9956 | 9979 | if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, kVerticalKeyRepeatRate)) |
| 9957 | 9980 | { |
| 9958 | | CURSOR_TO_PREVIOUS(menu->sel, total) |
| 9981 | CURSOR_TO_PREVIOUS(menu->sel, total); |
| 9959 | 9982 | |
| 9960 | 9983 | if(menu->sel == kMenu_Separator) |
| 9961 | 9984 | menu->sel--; |
| 9962 | 9985 | } |
| 9963 | 9986 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, kVerticalKeyRepeatRate)) |
| 9964 | 9987 | { |
| 9965 | | CURSOR_TO_NEXT(menu->sel, total) |
| 9988 | CURSOR_TO_NEXT(menu->sel, total); |
| 9966 | 9989 | |
| 9967 | 9990 | if(menu->sel == kMenu_Separator) |
| 9968 | 9991 | menu->sel++; |
| 9969 | 9992 | } |
| 9970 | 9993 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, kVerticalKeyRepeatRate)) |
| 9971 | 9994 | { |
| 9972 | | CURSOR_PAGE_UP(menu->sel) |
| 9995 | CURSOR_PAGE_UP(menu->sel); |
| 9973 | 9996 | } |
| 9974 | 9997 | else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, kVerticalKeyRepeatRate)) |
| 9975 | 9998 | { |
| 9976 | | CURSOR_PAGE_DOWN(menu->sel, total) |
| 9999 | CURSOR_PAGE_DOWN(menu->sel, total); |
| 9977 | 10000 | } |
| 9978 | 10001 | else if(input_ui_pressed(machine, IPT_UI_SELECT)) |
| 9979 | 10002 | { |
| r2821 | r2822 | |
| 10024 | 10047 | |
| 10025 | 10048 | if(cheatsDisabled) |
| 10026 | 10049 | { |
| 10027 | | for(i = 0; i < cheatListLength; i++) |
| 10028 | | TempDeactivateCheat(&cheatList[i]); |
| 10050 | for(i = 0; i < cheat_list_length; i++) |
| 10051 | TempDeactivateCheat(&cheat_list[i]); |
| 10029 | 10052 | } |
| 10030 | 10053 | } |
| 10031 | 10054 | } |
| r2821 | r2822 | |
| 10033 | 10056 | if(cheatsDisabled) |
| 10034 | 10057 | return; |
| 10035 | 10058 | |
| 10036 | | for(i = 0; i < cheatListLength; i++) |
| 10037 | | cheat_periodicEntry(machine, &cheatList[i]); |
| 10059 | for(i = 0; i < cheat_list_length; i++) |
| 10060 | cheat_periodicEntry(machine, &cheat_list[i]); |
| 10038 | 10061 | |
| 10039 | | if(EXTRACT_FIELD(cheatOptions, SearchBox) == kSearchBox_Minimum) |
| 10040 | | SET_FIELD(cheatOptions, SearchBox, kSearchBox_Standard); |
| 10062 | if(EXTRACT_FIELD(cheat_options, SearchBox) == kSearchBox_Minimum) |
| 10063 | SET_FIELD(cheat_options, SearchBox, kSearchBox_Standard); |
| 10041 | 10064 | } |
| 10042 | 10065 | |
| 10043 | 10066 | /*-------------- |
| r2821 | r2822 | |
| 10118 | 10141 | if(watchesDisabled) |
| 10119 | 10142 | return; |
| 10120 | 10143 | |
| 10121 | | for(i = 0; i < watchListLength; i++) |
| 10144 | for(i = 0; i < watch_list_length; i++) |
| 10122 | 10145 | { |
| 10123 | | WatchInfo * info = &watchList[i]; |
| 10146 | watch_info *info = &watch_list[i]; |
| 10124 | 10147 | |
| 10125 | 10148 | int j; |
| 10126 | 10149 | int numChars; |
| r2821 | r2822 | |
| 10131 | 10154 | |
| 10132 | 10155 | char buf[1024]; |
| 10133 | 10156 | |
| 10134 | | if(info->numElements) |
| 10157 | if(info->num_elements) |
| 10135 | 10158 | { |
| 10136 | 10159 | /* ##### LABEL ##### */ |
| 10137 | | switch(info->labelType) |
| 10160 | switch(info->label_type) |
| 10138 | 10161 | { |
| 10139 | 10162 | case kWatchLabel_Address: |
| 10140 | 10163 | numChars = sprintf(buf, "%.8X: ", info->address); |
| r2821 | r2822 | |
| 10152 | 10175 | } |
| 10153 | 10176 | |
| 10154 | 10177 | /* ##### VALUE ##### */ |
| 10155 | | for(j = 0; j < info->numElements; j++) |
| 10178 | for(j = 0; j < info->num_elements; j++) |
| 10156 | 10179 | { |
| 10157 | 10180 | UINT32 data = 0; |
| 10158 | 10181 | |
| 10159 | | if(!TEST_FIELD(info->cpu, RegionFlag)) |
| 10182 | if(info->cpu < REGION_INVALID) |
| 10160 | 10183 | { |
| 10161 | 10184 | UINT8 cpu = EXTRACT_FIELD(info->cpu, CPUIndex); |
| 10162 | 10185 | |
| 10163 | 10186 | switch(EXTRACT_FIELD(info->cpu, AddressSpace)) |
| 10164 | 10187 | { |
| 10165 | 10188 | case kAddressSpace_Program: |
| 10166 | | data = (DoCPURead(cpu, address, kSearchByteIncrementTable[info->elementBytes], cpu_needs_swap(cpu)) + info->addValue) & kSearchByteMaskTable[info->elementBytes]; |
| 10189 | data = (DoCPURead(cpu, address, kSearchByteIncrementTable[info->element_bytes], cpu_needs_swap(cpu)) + info->add_value) & kSearchByteMaskTable[info->element_bytes]; |
| 10167 | 10190 | break; |
| 10168 | 10191 | |
| 10169 | 10192 | case kAddressSpace_DataSpace: |
| r2821 | r2822 | |
| 10173 | 10196 | UINT8 * buf = (UINT8 *) GetMemoryRegionBasePointer(cpu, EXTRACT_FIELD(info->cpu, AddressSpace), address); |
| 10174 | 10197 | |
| 10175 | 10198 | if(buf) |
| 10176 | | data = DoMemoryRead(buf, address, kSearchByteIncrementTable[info->elementBytes], cpu_needs_swap(cpu) + info->addValue, get_cpu_info(cpu)) & |
| 10177 | | kSearchByteMaskTable[info->elementBytes]; |
| 10199 | data = DoMemoryRead(buf, address, kSearchByteIncrementTable[info->element_bytes], cpu_needs_swap(cpu) + info->add_value, get_cpu_info(cpu)) & |
| 10200 | kSearchByteMaskTable[info->element_bytes]; |
| 10178 | 10201 | } |
| 10179 | 10202 | break; |
| 10180 | 10203 | |
| r2821 | r2822 | |
| 10187 | 10210 | UINT8 * buf = memory_region(info->cpu); |
| 10188 | 10211 | |
| 10189 | 10212 | if(buf) |
| 10190 | | data = DoMemoryRead(buf, address, kSearchByteIncrementTable[info->elementBytes], |
| 10191 | | region_needs_swap(info->cpu) + info->addValue, |
| 10192 | | get_region_info(info->cpu)) & kSearchByteMaskTable[info->elementBytes]; |
| 10213 | data = DoMemoryRead(buf, address, kSearchByteIncrementTable[info->element_bytes], |
| 10214 | region_needs_swap(info->cpu) + info->add_value, |
| 10215 | get_region_info(info->cpu)) & kSearchByteMaskTable[info->element_bytes]; |
| 10193 | 10216 | } |
| 10194 | 10217 | |
| 10195 | | data = DoShift(data, info->dataShift); |
| 10218 | data = DoShift(data, info->data_shift); |
| 10196 | 10219 | data ^= info->xor; |
| 10197 | 10220 | |
| 10198 | | if( (lineElements >= info->elementsPerLine) && info->elementsPerLine) |
| 10221 | if( (lineElements >= info->elements_per_line) && info->elements_per_line) |
| 10199 | 10222 | { |
| 10200 | 10223 | lineElements = 0; |
| 10201 | 10224 | xOffset = 0; |
| 10202 | 10225 | yOffset++; |
| 10203 | 10226 | } |
| 10204 | 10227 | |
| 10205 | | switch(info->displayType) |
| 10228 | switch(info->display_type) |
| 10206 | 10229 | { |
| 10207 | 10230 | case kWatchDisplayType_Hex: |
| 10208 | | numChars = sprintf(buf, "%.*X", kSearchByteDigitsTable[info->elementBytes], data); |
| 10231 | numChars = sprintf(buf, "%.*X", kSearchByteDigitsTable[info->element_bytes], data); |
| 10209 | 10232 | |
| 10210 | 10233 | ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y); |
| 10211 | 10234 | xOffset += numChars; |
| r2821 | r2822 | |
| 10213 | 10236 | break; |
| 10214 | 10237 | |
| 10215 | 10238 | case kWatchDisplayType_Decimal: |
| 10216 | | numChars = sprintf(buf, "%.*d", kSearchByteDecDigitsTable[info->elementBytes], data); |
| 10239 | numChars = sprintf(buf, "%.*d", kSearchByteDecDigitsTable[info->element_bytes], data); |
| 10217 | 10240 | |
| 10218 | 10241 | ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y); |
| 10219 | 10242 | xOffset += numChars; |
| r2821 | r2822 | |
| 10221 | 10244 | break; |
| 10222 | 10245 | |
| 10223 | 10246 | case kWatchDisplayType_Binary: |
| 10224 | | numChars = PrintBinary(buf, data, kSearchByteMaskTable[info->elementBytes]); |
| 10247 | numChars = PrintBinary(buf, data, kSearchByteMaskTable[info->element_bytes]); |
| 10225 | 10248 | |
| 10226 | 10249 | ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y); |
| 10227 | 10250 | xOffset += numChars; |
| r2821 | r2822 | |
| 10229 | 10252 | break; |
| 10230 | 10253 | |
| 10231 | 10254 | case kWatchDisplayType_ASCII: |
| 10232 | | numChars = PrintASCII(buf, data, info->elementBytes); |
| 10255 | numChars = PrintASCII(buf, data, info->element_bytes); |
| 10233 | 10256 | |
| 10234 | 10257 | ui_draw_text(buf, xOffset * ui_get_char_width('0') + info->x, yOffset * ui_get_line_height() + info->y); |
| 10235 | 10258 | xOffset += numChars; |
| 10236 | 10259 | break; |
| 10237 | 10260 | } |
| 10238 | 10261 | |
| 10239 | | address += kSearchByteIncrementTable[info->elementBytes] + info->skip; |
| 10262 | address += kSearchByteIncrementTable[info->element_bytes] + info->skip; |
| 10240 | 10263 | lineElements++; |
| 10241 | 10264 | } |
| 10242 | 10265 | } |
| 10243 | 10266 | } |
| 10244 | 10267 | } |
| 10245 | 10268 | |
| 10246 | | /*------------------ |
| 10247 | | ResizeCheatList |
| 10248 | | ------------------*/ |
| 10269 | /*-------------------------------------------------------- |
| 10270 | resize_cheat_list - memory allocation for cheat entry |
| 10271 | --------------------------------------------------------*/ |
| 10249 | 10272 | |
| 10250 | | static void ResizeCheatList(UINT32 newLength) |
| 10273 | static void resize_cheat_list(UINT32 new_length, UINT8 dispose) |
| 10251 | 10274 | { |
| 10252 | | if(newLength != cheatListLength) |
| 10275 | if(new_length != cheat_list_length) |
| 10253 | 10276 | { |
| 10254 | | if(newLength < cheatListLength) |
| 10277 | /* ??? REQUEST_DISPOSE is only when INSERT right now so that it's meaningless ??? */ |
| 10278 | if(dispose == REQUEST_DISPOSE) |
| 10255 | 10279 | { |
| 10256 | | int i; |
| 10280 | /* free cheat entry if delete */ |
| 10281 | if(new_length < cheat_list_length) |
| 10282 | { |
| 10283 | int i; |
| 10257 | 10284 | |
| 10258 | | for(i = newLength; i < cheatListLength; i++) |
| 10259 | | DisposeCheat(&cheatList[i]); |
| 10285 | for(i = new_length; i < cheat_list_length; i++) |
| 10286 | dispose_cheat(&cheat_list[i]); |
| 10287 | } |
| 10260 | 10288 | } |
| 10261 | 10289 | |
| 10262 | | cheatList = realloc(cheatList, newLength * sizeof(CheatEntry)); |
| 10290 | /* reallocate cheat entry */ |
| 10291 | cheat_list = realloc(cheat_list, new_length * sizeof(cheat_entry)); |
| 10263 | 10292 | |
| 10264 | | if(!cheatList && (newLength != 0)) |
| 10293 | if(cheat_list == NULL && new_length != 0) |
| 10265 | 10294 | { |
| 10266 | | logerror("ResizeCheatList: out of memory resizing cheat list\n"); |
| 10267 | | ui_popup_time(2, "out of memory while loading cheat database"); |
| 10268 | | |
| 10269 | | cheatListLength = 0; |
| 10270 | | |
| 10271 | | return; |
| 10295 | fatalerror("cheat: [cheat entry] memory allocation error\n" |
| 10296 | " length = %.8X\n" |
| 10297 | " new_length = %.8X\n" |
| 10298 | " cheat_list = %p\n", |
| 10299 | cheat_list_length, new_length, cheat_list); |
| 10272 | 10300 | } |
| 10273 | 10301 | |
| 10274 | | if(newLength > cheatListLength) |
| 10302 | /* add new entry if insert */ |
| 10303 | if(new_length > cheat_list_length) |
| 10275 | 10304 | { |
| 10276 | | int i; |
| 10305 | int i; |
| 10277 | 10306 | |
| 10278 | | memset(&cheatList[cheatListLength], 0, (newLength - cheatListLength) * sizeof(CheatEntry)); |
| 10307 | memset(&cheat_list[cheat_list_length], 0, (new_length - cheat_list_length) * sizeof(cheat_entry)); |
| 10279 | 10308 | |
| 10280 | | for(i = cheatListLength; i < newLength; i++) |
| 10281 | | cheatList[i].flags |= kCheatFlag_Dirty; |
| 10309 | /* set dirty flag to inserted entry */ |
| 10310 | for(i = cheat_list_length; i < new_length; i++) |
| 10311 | cheat_list[i].flags |= kCheatFlag_Dirty; |
| 10282 | 10312 | } |
| 10283 | 10313 | |
| 10284 | | cheatListLength = newLength; |
| 10314 | cheat_list_length = new_length; |
| 10285 | 10315 | } |
| 10286 | 10316 | } |
| 10287 | 10317 | |
| 10288 | | /*--------------------------- |
| 10289 | | ResizeCheatListNoDispose |
| 10290 | | ---------------------------*/ |
| 10318 | /*----------------------------------------------------------------- |
| 10319 | add_cheat_before - insert new cheat entry before selected code |
| 10320 | -----------------------------------------------------------------*/ |
| 10291 | 10321 | |
| 10292 | | static void ResizeCheatListNoDispose(UINT32 newLength) |
| 10322 | static void add_cheat_before(UINT32 idx) |
| 10293 | 10323 | { |
| 10294 | | if(newLength != cheatListLength) |
| 10295 | | { |
| 10296 | | cheatList = realloc(cheatList, newLength * sizeof(CheatEntry)); |
| 10324 | /* insert new cheat entry */ |
| 10325 | resize_cheat_list(cheat_list_length + 1, REQUEST_DISPOSE); |
| 10297 | 10326 | |
| 10298 | | if(!cheatList && (newLength != 0)) |
| 10299 | | { |
| 10300 | | logerror("ResizeCheatListNoDispose: out of memory resizing cheat list\n"); |
| 10301 | | ui_popup_time(2, "out of memory while loading cheat database"); |
| 10327 | /* pack later entry if inserting point is not last */ |
| 10328 | if(idx < cheat_list_length - 1) |
| 10329 | memmove(&cheat_list[idx + 1], &cheat_list[idx], sizeof(cheat_entry) * (cheat_list_length - 1 - idx)); |
| 10302 | 10330 | |
| 10303 | | cheatListLength = 0; |
| 10331 | if(idx >= cheat_list_length) |
| 10332 | idx = cheat_list_length - 1; |
| 10304 | 10333 | |
| 10305 | | return; |
| 10306 | | } |
| 10334 | /* initialize inserted entry */ |
| 10335 | memset(&cheat_list[idx], 0, sizeof(cheat_entry)); |
| 10307 | 10336 | |
| 10308 | | if(newLength > cheatListLength) |
| 10309 | | { |
| 10310 | | int i; |
| 10337 | /* set dirty flag (meaningelss?) */ |
| 10338 | cheat_list[idx].flags |= kCheatFlag_Dirty; |
| 10311 | 10339 | |
| 10312 | | memset(&cheatList[cheatListLength], 0, (newLength - cheatListLength) * sizeof(CheatEntry)); |
| 10340 | /* insert new cheat action together */ |
| 10341 | resize_cheat_action_list(&cheat_list[idx], 1, REQUEST_DISPOSE); |
| 10313 | 10342 | |
| 10314 | | for(i = cheatListLength; i < newLength; i++) |
| 10315 | | cheatList[i].flags |= kCheatFlag_Dirty; |
| 10316 | | } |
| 10343 | cheat_list[idx].action_list[0].extend_data = ~0; |
| 10344 | cheat_list[idx].action_list[0].last_value = NULL; |
| 10317 | 10345 | |
| 10318 | | cheatListLength = newLength; |
| 10319 | | } |
| 10346 | SET_MESSAGE(kCheatMessage_SucceededToAdd); |
| 10320 | 10347 | } |
| 10321 | 10348 | |
| 10322 | | /*--------------------------------------------------------------- |
| 10323 | | AddCheatBefore - insert new cheat entry before selected code |
| 10324 | | ---------------------------------------------------------------*/ |
| 10349 | /*------------------------------------------------ |
| 10350 | delete_cheat_at - delete selected cheat entry |
| 10351 | ------------------------------------------------*/ |
| 10325 | 10352 | |
| 10326 | | static void AddCheatBefore(UINT32 idx) |
| 10353 | static void delete_cheat_at(UINT32 idx) |
| 10327 | 10354 | { |
| 10328 | | ResizeCheatList(cheatListLength + 1); |
| 10329 | | |
| 10330 | | if(idx < (cheatListLength - 1)) |
| 10331 | | memmove(&cheatList[idx + 1], &cheatList[idx], sizeof(CheatEntry) * (cheatListLength - 1 - idx)); |
| 10332 | | |
| 10333 | | if(idx >= cheatListLength) |
| 10334 | | idx = cheatListLength - 1; |
| 10335 | | |
| 10336 | | memset(&cheatList[idx], 0, sizeof(CheatEntry)); |
| 10337 | | |
| 10338 | | cheatList[idx].flags |= kCheatFlag_Dirty; |
| 10339 | | |
| 10340 | | ResizeCheatActionList(&cheatList[idx], 1); |
| 10341 | | |
| 10342 | | cheatList[idx].actionList[0].extendData = ~0; |
| 10343 | | cheatList[idx].actionList[0].lastValue = NULL; |
| 10344 | | |
| 10345 | | messageType = kCheatMessage_SucceededToAdd; |
| 10346 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10347 | | } |
| 10348 | | |
| 10349 | | /*---------------- |
| 10350 | | DeleteCheatAt |
| 10351 | | ----------------*/ |
| 10352 | | |
| 10353 | | static void DeleteCheatAt(UINT32 idx) |
| 10354 | | { |
| 10355 | | if(idx >= cheatListLength) |
| 10355 | /* if selected point is not cheat entry, no action */ |
| 10356 | if(idx >= cheat_list_length) |
| 10356 | 10357 | { |
| 10357 | | messageType = kCheatMessage_FailedToDelete; |
| 10358 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10358 | SET_MESSAGE(kCheatMessage_FailedToDelete); |
| 10359 | 10359 | return; |
| 10360 | 10360 | } |
| 10361 | 10361 | |
| 10362 | | DisposeCheat(&cheatList[idx]); |
| 10362 | /* free selected cheat entry */ |
| 10363 | dispose_cheat(&cheat_list[idx]); |
| 10363 | 10364 | |
| 10364 | | if(idx < (cheatListLength - 1)) |
| 10365 | /* pack later cheat entry if selected point is not last */ |
| 10366 | if(idx < cheat_list_length - 1) |
| 10365 | 10367 | { |
| 10366 | | memmove(&cheatList[idx], &cheatList[idx + 1], sizeof(CheatEntry) * (cheatListLength - 1 - idx)); |
| 10368 | memmove(&cheat_list[idx], &cheat_list[idx + 1], sizeof(cheat_entry) * (cheat_list_length - 1 - idx)); |
| 10367 | 10369 | } |
| 10368 | 10370 | |
| 10369 | | ResizeCheatListNoDispose(cheatListLength - 1); |
| 10371 | /* realloc cheat entry */ |
| 10372 | resize_cheat_list(cheat_list_length - 1, NO_DISPOSE); |
| 10370 | 10373 | |
| 10371 | | messageType = kCheatMessage_SucceededToDelete; |
| 10372 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10374 | SET_MESSAGE(kCheatMessage_SucceededToDelete); |
| 10373 | 10375 | } |
| 10374 | 10376 | |
| 10375 | | /*------------------------------------------------ |
| 10376 | | DisposeCheat - free memory for selected entry |
| 10377 | | ------------------------------------------------*/ |
| 10377 | /*-------------------------------------------------------------------------------- |
| 10378 | dispose_cheat - free selected cheat entry and all cheat actions in this entry |
| 10379 | --------------------------------------------------------------------------------*/ |
| 10378 | 10380 | |
| 10379 | | static void DisposeCheat(CheatEntry * entry) |
| 10381 | static void dispose_cheat(cheat_entry *entry) |
| 10380 | 10382 | { |
| 10381 | 10383 | if(entry) |
| 10382 | 10384 | { |
| 10383 | | int i; |
| 10385 | int i; |
| 10384 | 10386 | |
| 10385 | 10387 | free(entry->name); |
| 10386 | 10388 | free(entry->comment); |
| 10387 | | free(entry->labelIndex); |
| 10389 | free(entry->label_index); |
| 10388 | 10390 | |
| 10389 | | for(i = 0; i < entry->actionListLength; i++) |
| 10390 | | { |
| 10391 | | CheatAction * action = &entry->actionList[i]; |
| 10391 | /* free all cheat actions in selected entry */ |
| 10392 | for(i = 0; i < entry->action_list_length; i++) |
| 10393 | dispose_action(&entry->action_list[i]); |
| 10392 | 10394 | |
| 10393 | | DisposeAction(action); |
| 10394 | | } |
| 10395 | free(entry->action_list); |
| 10395 | 10396 | |
| 10396 | | free(entry->actionList); |
| 10397 | | |
| 10398 | | memset(entry, 0, sizeof(CheatEntry)); |
| 10397 | memset(entry, 0, sizeof(cheat_entry)); |
| 10399 | 10398 | } |
| 10400 | 10399 | } |
| 10401 | 10400 | |
| 10402 | | /*----------------------------------------------------- |
| 10403 | | GetNewCheat - insert new cheat entry and return it |
| 10404 | | -----------------------------------------------------*/ |
| 10401 | /*------------------------------------------------------------------------------- |
| 10402 | get_new_cheat - return pointer to new cheat entry inserted at last position |
| 10403 | -------------------------------------------------------------------------------*/ |
| 10405 | 10404 | |
| 10406 | | static CheatEntry * GetNewCheat(void) |
| 10405 | static cheat_entry *get_new_cheat(void) |
| 10407 | 10406 | { |
| 10408 | | AddCheatBefore(cheatListLength); |
| 10407 | /* insert new cheat entry at last position */ |
| 10408 | add_cheat_before(cheat_list_length); |
| 10409 | 10409 | |
| 10410 | | return &cheatList[cheatListLength - 1]; |
| 10410 | return &cheat_list[cheat_list_length - 1]; |
| 10411 | 10411 | } |
| 10412 | 10412 | |
| 10413 | | /*------------------------ |
| 10414 | | ResizeCheatActionList |
| 10415 | | ------------------------*/ |
| 10413 | /*----------------------------------------------------------------------- |
| 10414 | resize_cheat_action_list - reallocate cheat action in selected entry |
| 10415 | -----------------------------------------------------------------------*/ |
| 10416 | 10416 | |
| 10417 | | static void ResizeCheatActionList(CheatEntry * entry, UINT32 newLength) |
| 10417 | static void resize_cheat_action_list(cheat_entry *entry, UINT32 new_length, UINT8 dispose) |
| 10418 | 10418 | { |
| 10419 | | if(newLength != entry->actionListLength) |
| 10419 | if(new_length != entry->action_list_length) |
| 10420 | 10420 | { |
| 10421 | | if(newLength < entry->actionListLength) |
| 10421 | if(dispose == REQUEST_DISPOSE) |
| 10422 | 10422 | { |
| 10423 | | int i; |
| 10423 | /* free cheat action if delete */ |
| 10424 | if(new_length < entry->action_list_length) |
| 10425 | { |
| 10426 | int i; |
| 10424 | 10427 | |
| 10425 | | for(i = newLength; i < entry->actionListLength; i++) |
| 10426 | | DisposeAction(&entry->actionList[i]); |
| 10428 | for(i = new_length; i < entry->action_list_length; i++) |
| 10429 | dispose_action(&entry->action_list[i]); |
| 10430 | } |
| 10427 | 10431 | } |
| 10428 | 10432 | |
| 10429 | | entry->actionList = realloc(entry->actionList, newLength * sizeof(CheatAction)); |
| 10430 | | if(!entry->actionList && (newLength != 0)) |
| 10431 | | { |
| 10432 | | logerror("ResizeCheatActionList: out of memory resizing cheat action list\n"); |
| 10433 | | ui_popup_time(2, "out of memory while loading cheat database"); |
| 10433 | /* reallocate cheat action */ |
| 10434 | entry->action_list = realloc(entry->action_list, new_length * sizeof(cheat_action)); |
| 10434 | 10435 | |
| 10435 | | entry->actionListLength = 0; |
| 10436 | | |
| 10437 | | return; |
| 10438 | | } |
| 10439 | | |
| 10440 | | if(newLength > entry->actionListLength) |
| 10436 | if(entry->action_list == NULL && new_length != 0) |
| 10441 | 10437 | { |
| 10442 | | memset(&entry->actionList[entry->actionListLength], 0, (newLength - entry->actionListLength) * sizeof(CheatAction)); |
| 10438 | fatalerror("cheat: [cheat action] memory allocation error\n" |
| 10439 | " length = %.8X\n" |
| 10440 | " new_length = %.8X\n" |
| 10441 | " action_list = %p\n", |
| 10442 | entry->action_list_length, new_length, entry->action_list); |
| 10443 | 10443 | } |
| 10444 | 10444 | |
| 10445 | | entry->actionListLength = newLength; |
| 10446 | | } |
| 10447 | | } |
| 10448 | | |
| 10449 | | /*--------------------------------- |
| 10450 | | ResizeCheatActionListNoDispose |
| 10451 | | ---------------------------------*/ |
| 10452 | | #if 0 |
| 10453 | | static void ResizeCheatActionListNoDispose(CheatEntry * entry, UINT32 newLength) |
| 10454 | | { |
| 10455 | | if(newLength != entry->actionListLength) |
| 10456 | | { |
| 10457 | | entry->actionList = realloc(entry->actionList, newLength * sizeof(CheatAction)); |
| 10458 | | if(!entry->actionList && (newLength != 0)) |
| 10445 | /* add new action if insert */ |
| 10446 | if(new_length > entry->action_list_length) |
| 10459 | 10447 | { |
| 10460 | | logerror("ResizeCheatActionList: out of memory resizing cheat action list\n"); |
| 10461 | | ui_popup_time(2, "out of memory while loading cheat database"); |
| 10462 | | |
| 10463 | | entry->actionListLength = 0; |
| 10464 | | |
| 10465 | | return; |
| 10448 | memset(&entry->action_list[entry->action_list_length], 0, (new_length - entry->action_list_length) * sizeof(cheat_action)); |
| 10466 | 10449 | } |
| 10467 | 10450 | |
| 10468 | | if(newLength > entry->actionListLength) |
| 10469 | | { |
| 10470 | | memset(&entry->actionList[entry->actionListLength], 0, (newLength - entry->actionListLength) * sizeof(CheatAction)); |
| 10471 | | } |
| 10472 | | |
| 10473 | | entry->actionListLength = newLength; |
| 10451 | entry->action_list_length = new_length; |
| 10474 | 10452 | } |
| 10475 | 10453 | } |
| 10476 | 10454 | |
| 10455 | #if 0 |
| 10477 | 10456 | /*---------------------------------------------------------------- |
| 10478 | 10457 | AddActionBefore - Insert empty Action |
| 10479 | 10458 | This function is only called in EditCheat() |
| r2821 | r2822 | |
| 10491 | 10470 | |
| 10492 | 10471 | memset(&entry->actionList[idx], 0, sizeof(CheatAction)); |
| 10493 | 10472 | |
| 10494 | | cheatList[idx].actionList[0].extendData = ~0; |
| 10495 | | cheatList[idx].actionList[0].lastValue = NULL; |
| 10473 | cheat_list[idx].actionList[0].extendData = ~0; |
| 10474 | cheat_list[idx].actionList[0].lastValue = NULL; |
| 10496 | 10475 | } |
| 10497 | 10476 | |
| 10498 | 10477 | /*----------------- |
| r2821 | r2822 | |
| 10503 | 10482 | { |
| 10504 | 10483 | if(idx >= entry->actionListLength) |
| 10505 | 10484 | { |
| 10506 | | messageType = kCheatMessage_FailedToDelete; |
| 10507 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10485 | SET_MESSAGE(kCheatMessage_FailedToDelete); |
| 10508 | 10486 | return; |
| 10509 | 10487 | } |
| 10510 | 10488 | |
| r2821 | r2822 | |
| 10515 | 10493 | |
| 10516 | 10494 | ResizeCheatActionListNoDispose(entry, entry->actionListLength - 1); |
| 10517 | 10495 | |
| 10518 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10519 | | messageType = kCheatMessage_SucceededToDelete; |
| 10496 | SET_MESSAGE(kCheatMessage_SucceededToDelete); |
| 10520 | 10497 | } |
| 10521 | 10498 | #endif |
| 10522 | | /*---------------- |
| 10523 | | DisposeAction |
| 10524 | | ----------------*/ |
| 10499 | /*---------------------------------------------- |
| 10500 | dispose_action - free selected cheat action |
| 10501 | ----------------------------------------------*/ |
| 10525 | 10502 | |
| 10526 | | static void DisposeAction(CheatAction * action) |
| 10503 | static void dispose_action(cheat_action *action) |
| 10527 | 10504 | { |
| 10528 | | if(action) |
| 10505 | if(action != NULL) |
| 10529 | 10506 | { |
| 10530 | | free(action->optionalName); |
| 10507 | free(action->optional_name); |
| 10531 | 10508 | |
| 10532 | | if(action->lastValue) |
| 10533 | | free(action->lastValue); |
| 10509 | if(action->last_value) |
| 10510 | free(action->last_value); |
| 10534 | 10511 | |
| 10535 | | memset(action, 0, sizeof(CheatAction)); |
| 10512 | memset(action, 0, sizeof(cheat_action)); |
| 10536 | 10513 | } |
| 10537 | 10514 | } |
| 10538 | 10515 | |
| 10539 | | /*------------------------------------------------ |
| 10540 | | InitWatch - initialize a value for watchpoint |
| 10541 | | ------------------------------------------------*/ |
| 10516 | /*------------------------------------------------- |
| 10517 | init_watch - initialize a value for watchpoint |
| 10518 | -------------------------------------------------*/ |
| 10542 | 10519 | |
| 10543 | | static void InitWatch(WatchInfo * info, UINT32 idx) |
| 10520 | static void init_watch(watch_info *info, UINT32 idx) |
| 10544 | 10521 | { |
| 10545 | 10522 | /* NOTE : 1st watchpoint should be always Y = 0 */ |
| 10546 | 10523 | if(idx > 0) |
| 10547 | | info->y = watchList[idx - 1].y + ui_get_line_height(); |
| 10524 | info->y = watch_list[idx - 1].y + ui_get_line_height(); |
| 10548 | 10525 | else |
| 10549 | 10526 | info->y = 0; |
| 10550 | 10527 | } |
| 10551 | 10528 | |
| 10552 | | /*------------------ |
| 10553 | | ResizeWatchList |
| 10554 | | ------------------*/ |
| 10529 | /*-------------------------------------------------------------- |
| 10530 | resize_watch_list - reallocate watch list if different size |
| 10531 | --------------------------------------------------------------*/ |
| 10555 | 10532 | |
| 10556 | | static void ResizeWatchList(UINT32 newLength) |
| 10533 | static void resize_watch_list(UINT32 new_length, UINT8 dispose) |
| 10557 | 10534 | { |
| 10558 | | if(newLength != watchListLength) |
| 10535 | if(new_length != watch_list_length) |
| 10559 | 10536 | { |
| 10560 | | if(newLength < watchListLength) |
| 10537 | /* NOTE : dispose flag is only set when called from delete_watch_at() */ |
| 10538 | if(dispose) |
| 10561 | 10539 | { |
| 10562 | | int i; |
| 10540 | /* if delete, free deleted or later watch list */ |
| 10541 | if(new_length < watch_list_length) |
| 10542 | { |
| 10543 | int i; |
| 10563 | 10544 | |
| 10564 | | for(i = newLength; i < watchListLength; i++) |
| 10565 | | DisposeWatch(&watchList[i]); |
| 10545 | for(i = new_length; i < watch_list_length; i++) |
| 10546 | dispose_watch(&watch_list[i]); |
| 10547 | } |
| 10566 | 10548 | } |
| 10567 | 10549 | |
| 10568 | | watchList = realloc(watchList, newLength * sizeof(WatchInfo)); |
| 10569 | | if(!watchList && (newLength != 0)) |
| 10570 | | { |
| 10571 | | logerror("ResizeWatchList: out of memory resizing watch list\n"); |
| 10572 | | ui_popup_time(2, "out of memory while adding watch"); |
| 10550 | /* reallocate watch list */ |
| 10551 | watch_list = realloc(watch_list, new_length * sizeof(watch_info)); |
| 10573 | 10552 | |
| 10574 | | watchListLength = 0; |
| 10575 | | |
| 10576 | | return; |
| 10577 | | } |
| 10578 | | |
| 10579 | | if(newLength > watchListLength) |
| 10553 | if(watch_list == NULL && new_length != 0) |
| 10580 | 10554 | { |
| 10581 | | int i; |
| 10582 | | |
| 10583 | | memset(&watchList[watchListLength], 0, (newLength - watchListLength) * sizeof(WatchInfo)); |
| 10584 | | |
| 10585 | | for(i = watchListLength; i < newLength; i++) |
| 10586 | | InitWatch(&watchList[i], i); |
| 10555 | /* memory allocation error */ |
| 10556 | fatalerror( "cheat : [watch list] memory allocation error\n" |
| 10557 | " length = %.8X\n" |
| 10558 | " new_length = %.8X\n" |
| 10559 | " watch_list = %p\n", |
| 10560 | watch_list_length, new_length, watch_list); |
| 10587 | 10561 | } |
| 10588 | 10562 | |
| 10589 | | watchListLength = newLength; |
| 10590 | | } |
| 10591 | | } |
| 10592 | | |
| 10593 | | /*--------------------------- |
| 10594 | | ResizeWatchListNoDispose |
| 10595 | | ---------------------------*/ |
| 10596 | | |
| 10597 | | static void ResizeWatchListNoDispose(UINT32 newLength) |
| 10598 | | { |
| 10599 | | if(newLength != watchListLength) |
| 10600 | | { |
| 10601 | | watchList = realloc(watchList, newLength * sizeof(WatchInfo)); |
| 10602 | | if(!watchList && (newLength != 0)) |
| 10563 | /* if insert, move later watch list */ |
| 10564 | if(new_length > watch_list_length) |
| 10603 | 10565 | { |
| 10604 | | logerror("ResizeWatchList: out of memory resizing watch list\n"); |
| 10605 | | ui_popup_time(2, "out of memory while adding watch"); |
| 10566 | int i; |
| 10606 | 10567 | |
| 10607 | | watchListLength = 0; |
| 10568 | memset(&watch_list[watch_list_length], 0, (new_length - watch_list_length) * sizeof(watch_info)); |
| 10608 | 10569 | |
| 10609 | | return; |
| 10570 | for(i = watch_list_length; i < new_length; i++) |
| 10571 | init_watch(&watch_list[i], i); |
| 10610 | 10572 | } |
| 10611 | 10573 | |
| 10612 | | if(newLength > watchListLength) |
| 10613 | | { |
| 10614 | | int i; |
| 10615 | | |
| 10616 | | memset(&watchList[watchListLength], 0, (newLength - watchListLength) * sizeof(WatchInfo)); |
| 10617 | | |
| 10618 | | for(i = watchListLength; i < newLength; i++) |
| 10619 | | InitWatch(&watchList[i], i); |
| 10620 | | } |
| 10621 | | |
| 10622 | | watchListLength = newLength; |
| 10574 | watch_list_length = new_length; |
| 10623 | 10575 | } |
| 10624 | 10576 | } |
| 10625 | 10577 | |
| 10626 | | /*----------------- |
| 10627 | | AddWatchBefore |
| 10628 | | -----------------*/ |
| 10578 | /*------------------------------------------- |
| 10579 | add_watch_before - insert new watch list |
| 10580 | -------------------------------------------*/ |
| 10629 | 10581 | |
| 10630 | | static void AddWatchBefore(UINT32 idx) |
| 10582 | static void add_watch_before(UINT32 idx) |
| 10631 | 10583 | { |
| 10632 | | ResizeWatchList(watchListLength + 1); |
| 10584 | /* reallocate watch list */ |
| 10585 | resize_watch_list(watch_list_length + 1, 0); |
| 10633 | 10586 | |
| 10634 | | if(idx < (watchListLength - 1)) |
| 10635 | | memmove(&watchList[idx + 1], &watchList[idx], sizeof(WatchInfo) * (watchListLength - 1 - idx)); |
| 10587 | /* if insert position is not last, move later watch list */ |
| 10588 | if(idx < watch_list_length - 1) |
| 10589 | memmove(&watch_list[idx + 1], &watch_list[idx], sizeof(watch_info) * (watch_list_length - 1 - idx)); |
| 10590 | else |
| 10591 | idx = watch_list_length - 1; |
| 10636 | 10592 | |
| 10637 | | if(idx >= watchListLength) |
| 10638 | | idx = watchListLength - 1; |
| 10593 | /* memory initialize */ |
| 10594 | memset(&watch_list[idx], 0, sizeof(watch_info)); |
| 10639 | 10595 | |
| 10640 | | memset(&watchList[idx], 0, sizeof(WatchInfo)); |
| 10641 | | |
| 10642 | | InitWatch(&watchList[idx], idx); |
| 10596 | init_watch(&watch_list[idx], idx); |
| 10643 | 10597 | } |
| 10644 | 10598 | |
| 10645 | | /*---------------- |
| 10646 | | DeleteWatchAt |
| 10647 | | ----------------*/ |
| 10599 | /*------------------------------------------------ |
| 10600 | delete_watch_at - delete selected watch point |
| 10601 | ------------------------------------------------*/ |
| 10648 | 10602 | |
| 10649 | | static void DeleteWatchAt(UINT32 idx) |
| 10603 | static void delete_watch_at(UINT32 idx) |
| 10650 | 10604 | { |
| 10651 | | if(idx >= watchListLength) |
| 10605 | /* if selected item is not watchpoint, no delete */ |
| 10606 | if(idx >= watch_list_length) |
| 10607 | { |
| 10608 | SET_MESSAGE(kCheatMessage_FailedToDelete); |
| 10652 | 10609 | return; |
| 10610 | } |
| 10653 | 10611 | |
| 10654 | | DisposeWatch(&watchList[idx]); |
| 10612 | /* free selected watch list */ |
| 10613 | dispose_watch(&watch_list[idx]); |
| 10655 | 10614 | |
| 10656 | | if(idx < (watchListLength - 1)) |
| 10657 | | memmove(&watchList[idx], &watchList[idx + 1], sizeof(WatchInfo) * (watchListLength - 1 - idx)); |
| 10615 | /* move later watch list */ |
| 10616 | memmove(&watch_list[idx], &watch_list[idx + 1], sizeof(watch_info) * (watch_list_length - 1 - idx)); |
| 10658 | 10617 | |
| 10659 | | ResizeWatchListNoDispose(watchListLength - 1); |
| 10618 | /* reallocate watch list */ |
| 10619 | resize_watch_list(watch_list_length - 1, 1); |
| 10660 | 10620 | } |
| 10661 | 10621 | |
| 10662 | | /*--------------- |
| 10663 | | DisposeWatch |
| 10664 | | ---------------*/ |
| 10622 | /*------------------------------------------------- |
| 10623 | dispose_watch - initialize selected watch list |
| 10624 | -------------------------------------------------*/ |
| 10665 | 10625 | |
| 10666 | | static void DisposeWatch(WatchInfo * watch) |
| 10626 | static void dispose_watch(watch_info *watch) |
| 10667 | 10627 | { |
| 10668 | | if(watch) |
| 10669 | | memset(watch, 0, sizeof(WatchInfo)); |
| 10628 | memset(watch, 0, sizeof(watch_info)); |
| 10670 | 10629 | } |
| 10671 | 10630 | |
| 10672 | | /*---------------------------------------------------------- |
| 10673 | | GetUnusedWatch - search unused watchpoint and return it |
| 10674 | | ----------------------------------------------------------*/ |
| 10631 | /*-------------------------------------------- |
| 10632 | get_unused_watch - find unused watchpoint |
| 10633 | --------------------------------------------*/ |
| 10675 | 10634 | |
| 10676 | | static WatchInfo * GetUnusedWatch(void) |
| 10635 | static watch_info *get_unused_watch(void) |
| 10677 | 10636 | { |
| 10678 | 10637 | int i; |
| 10679 | | WatchInfo * info; |
| 10680 | | WatchInfo * theWatch = NULL; |
| 10638 | watch_info *info; |
| 10639 | watch_info *the_watch = NULL; |
| 10681 | 10640 | |
| 10682 | 10641 | /* search unused watchpoint */ |
| 10683 | | for(i = 0; i < watchListLength; i++) |
| 10642 | for(i = 0; i < watch_list_length; i++) |
| 10684 | 10643 | { |
| 10685 | | info = &watchList[i]; |
| 10644 | info = &watch_list[i]; |
| 10686 | 10645 | |
| 10687 | | if(info->numElements == 0) |
| 10646 | /* NOTE : "unused" means "undisplayed" */ |
| 10647 | if(info->num_elements == 0) |
| 10688 | 10648 | { |
| 10689 | | theWatch = info; |
| 10649 | the_watch = info; |
| 10690 | 10650 | break; |
| 10691 | 10651 | } |
| 10692 | 10652 | } |
| 10693 | 10653 | |
| 10694 | | /* if unused watchpoint is not found, insert new watchpoint */ |
| 10695 | | if(!theWatch) |
| 10654 | /* if all watchpoints are used, insert new watchpoint */ |
| 10655 | if(the_watch == NULL) |
| 10696 | 10656 | { |
| 10697 | | AddWatchBefore(watchListLength); |
| 10657 | add_watch_before(watch_list_length); |
| 10698 | 10658 | |
| 10699 | | theWatch = &watchList[watchListLength - 1]; |
| 10659 | the_watch = &watch_list[watch_list_length - 1]; |
| 10700 | 10660 | } |
| 10701 | 10661 | |
| 10702 | | return theWatch; |
| 10662 | return the_watch; |
| 10703 | 10663 | } |
| 10704 | 10664 | |
| 10705 | | /*---------------------------------------------------------------------------- |
| 10706 | | AddCheatFromWatch - add new cheat code from watchpoint list to cheat list |
| 10707 | | ----------------------------------------------------------------------------*/ |
| 10665 | /*------------------------------------------------------------ |
| 10666 | add_cheat_from_watch - add new cheat code from watchpoint |
| 10667 | ------------------------------------------------------------*/ |
| 10708 | 10668 | |
| 10709 | | static void AddCheatFromWatch(WatchInfo * watch) |
| 10669 | static void add_cheat_from_watch(watch_info *watch) |
| 10710 | 10670 | { |
| 10711 | 10671 | if(watch) |
| 10712 | 10672 | { |
| 10713 | | int tempStringLength; |
| 10714 | | char tempString[1024]; |
| 10715 | | CheatEntry * entry = GetNewCheat(); |
| 10716 | | CheatAction * action = &entry->actionList[0]; |
| 10673 | int temp_string_length; |
| 10674 | char temp_string[1024]; |
| 10675 | cheat_entry *entry = get_new_cheat(); |
| 10676 | cheat_action *action = &entry->action_list[0]; |
| 10717 | 10677 | |
| 10718 | 10678 | /* set parameters */ |
| 10719 | | action->region = watch->cpu; |
| 10720 | | SET_FIELD(action->type, CPURegion, action->region); |
| 10721 | | SET_FIELD(action->type, AddressSize, watch->elementBytes); |
| 10722 | | action->address = action->originalAddress = watch->address; |
| 10723 | | action->extendData = ~0; |
| 10724 | | action->lastValue = NULL; |
| 10679 | action->region = watch->cpu; |
| 10680 | action->address = watch->address; |
| 10681 | action->original_address = watch->address; |
| 10682 | action->extend_data = ~0; |
| 10683 | action->last_value = NULL; |
| 10684 | action->data = ReadData(action); |
| 10685 | SET_FIELD(action->type, AddressSize, watch->element_bytes); |
| 10725 | 10686 | |
| 10726 | | action->data = ReadData(action); |
| 10727 | | |
| 10728 | 10687 | /* set name */ |
| 10729 | | tempStringLength = sprintf(tempString, "%.8X (%d) = %.*X", watch->address, watch->cpu, kSearchByteDigitsTable[watch->elementBytes], action->data); |
| 10730 | | entry->name = create_string_copy(tempString); |
| 10688 | temp_string_length = sprintf(temp_string, "%.8X (%d) = %.*X", watch->address, watch->cpu, kSearchByteDigitsTable[watch->element_bytes], action->data); |
| 10689 | entry->name = create_string_copy(temp_string); |
| 10731 | 10690 | |
| 10732 | | UpdateCheatInfo(entry, 0); |
| 10691 | update_cheat_info(entry, 0); |
| 10733 | 10692 | |
| 10734 | | messageType = kCheatMessage_SucceededToAdd; |
| 10735 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10693 | SET_MESSAGE(kCheatMessage_SucceededToAdd); |
| 10736 | 10694 | } |
| 10737 | 10695 | else |
| 10738 | | { |
| 10739 | | messageType = kCheatMessage_FailedToAdd; |
| 10740 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10741 | | } |
| 10696 | SET_MESSAGE(kCheatMessage_FailedToAdd); |
| 10742 | 10697 | } |
| 10743 | 10698 | |
| 10744 | | /*-------------------------------------------------------------------------------------- |
| 10745 | | SetupCheatFromWatchAsWatch - add new watch code from watchpoint list to cheat list |
| 10746 | | If watchpoint is not displayed (length = 0), don't add |
| 10747 | | --------------------------------------------------------------------------------------*/ |
| 10699 | /*--------------------------------------------------------------------------- |
| 10700 | add_cheat_from_watch_as_watch - add new watchpoint cheat from watchpoint |
| 10701 | ---------------------------------------------------------------------------*/ |
| 10748 | 10702 | |
| 10749 | | static void SetupCheatFromWatchAsWatch(CheatEntry * entry, WatchInfo * watch) |
| 10703 | static void add_cheat_from_watch_as_watch(cheat_entry *entry, watch_info *watch) |
| 10750 | 10704 | { |
| 10751 | | if(watch && entry && watch->numElements) |
| 10705 | /* NOTE : don't add in case of undisplayed watchpoint */ |
| 10706 | if(watch && entry && watch->num_elements) |
| 10752 | 10707 | { |
| 10753 | | char tempString[256]; |
| 10754 | | CheatAction * action; |
| 10708 | char temp_string[256]; |
| 10709 | cheat_action *action; |
| 10755 | 10710 | |
| 10756 | | DisposeCheat(entry); |
| 10757 | | ResizeCheatActionList(entry, 1); |
| 10711 | /* free then add new cheat entry */ |
| 10712 | dispose_cheat(entry); |
| 10713 | resize_cheat_action_list(entry, 1, REQUEST_DISPOSE); |
| 10714 | action = &entry->action_list[0]; |
| 10758 | 10715 | |
| 10759 | | action = &entry->actionList[0]; |
| 10716 | /* set name and comments */ |
| 10717 | sprintf(temp_string, "Watch %.8X (%d)", watch->address, watch->cpu); |
| 10760 | 10718 | |
| 10761 | | sprintf(tempString, "Watch %.8X (%d)", watch->address, watch->cpu); |
| 10762 | | |
| 10763 | | /* set name */ |
| 10764 | | entry->name = create_string_copy(tempString); |
| 10719 | entry->name = create_string_copy(temp_string); |
| 10765 | 10720 | entry->comment = create_string_copy(watch->label); |
| 10766 | 10721 | |
| 10767 | 10722 | /* set parameters */ |
| 10768 | | SET_FIELD(action->type, CodeType, kCodeType_Watch); |
| 10769 | | SET_FIELD(action->type, AddressSize, kSearchByteIncrementTable[watch->elementBytes] - 1); |
| 10723 | action->region = watch->cpu; |
| 10724 | action->address = watch->address; |
| 10725 | action->original_address = watch->address; |
| 10726 | action->original_data = action->data; |
| 10727 | action->extend_data = ~0; |
| 10770 | 10728 | |
| 10771 | | action->region = watch->cpu; |
| 10772 | | action->address = watch->address; |
| 10773 | | action->originalAddress = action->address; |
| 10774 | | action->originalDataField = action->data; |
| 10775 | | action->extendData = 0xFFFFFFFF; |
| 10776 | | |
| 10777 | | SET_FIELD(action->data, WatchNumElements, watch->numElements - 1); |
| 10729 | SET_FIELD(action->type, CodeType, kCodeType_Watch); |
| 10730 | SET_FIELD(action->type, AddressSize, kSearchByteIncrementTable[watch->element_bytes] - 1); |
| 10731 | SET_FIELD(action->data, WatchNumElements, watch->num_elements - 1); |
| 10778 | 10732 | SET_FIELD(action->data, WatchSkip, watch->skip); |
| 10779 | | SET_FIELD(action->data, WatchElementsPerLine, watch->elementsPerLine); |
| 10780 | | SET_FIELD(action->data, WatchAddValue, watch->addValue); |
| 10733 | SET_FIELD(action->data, WatchElementsPerLine, watch->elements_per_line); |
| 10734 | SET_FIELD(action->data, WatchAddValue, watch->add_value); |
| 10781 | 10735 | |
| 10782 | | /* set comment */ |
| 10736 | update_cheat_info(entry, 0); |
| 10783 | 10737 | |
| 10784 | | UpdateCheatInfo(entry, 0); |
| 10785 | | |
| 10786 | | messageType = kCheatMessage_SucceededToAdd; |
| 10787 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10738 | SET_MESSAGE(kCheatMessage_SucceededToAdd); |
| 10788 | 10739 | } |
| 10789 | 10740 | else |
| 10790 | | { |
| 10791 | | messageType = kCheatMessage_FailedToAdd; |
| 10792 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 10793 | | } |
| 10741 | SET_MESSAGE(kCheatMessage_FailedToAdd); |
| 10794 | 10742 | } |
| 10795 | 10743 | |
| 10796 | | /*----------------------------------------------------------- |
| 10797 | | ResetWatch - clear data in WatchInfo except x/y position |
| 10798 | | -----------------------------------------------------------*/ |
| 10744 | /*---------------------------------------------------------------------- |
| 10745 | reset_watch - clear data in selected watch list except the position |
| 10746 | ----------------------------------------------------------------------*/ |
| 10799 | 10747 | |
| 10800 | | static void ResetWatch(WatchInfo * watch) |
| 10748 | static void reset_watch(watch_info *watch) |
| 10801 | 10749 | { |
| 10802 | 10750 | if(watch) |
| 10803 | 10751 | { |
| 10804 | | watch->address = 0; |
| 10805 | | watch->cpu = 0; |
| 10806 | | watch->numElements = 0; |
| 10807 | | watch->elementBytes = kWatchSizeConversionTable[0]; |
| 10808 | | watch->labelType = kWatchLabel_None; |
| 10809 | | watch->displayType = kWatchDisplayType_Hex; |
| 10810 | | watch->skip = 0; |
| 10811 | | watch->elementsPerLine = 0; |
| 10812 | | watch->addValue = 0; |
| 10813 | | watch->addressShift = 0; |
| 10814 | | watch->dataShift = 0; |
| 10815 | | watch->xor = 0; |
| 10816 | | watch->linkedCheat = NULL; |
| 10817 | | watch->label[0] = 0; |
| 10752 | watch->address = 0; |
| 10753 | watch->cpu = 0; |
| 10754 | watch->num_elements = 0; |
| 10755 | watch->element_bytes = kWatchSizeConversionTable[0]; |
| 10756 | watch->label_type = kWatchLabel_None; |
| 10757 | watch->display_type = kWatchDisplayType_Hex; |
| 10758 | watch->skip = 0; |
| 10759 | watch->elements_per_line = 0; |
| 10760 | watch->add_value = 0; |
| 10761 | watch->address_shift = 0; |
| 10762 | watch->data_shift = 0; |
| 10763 | watch->xor = 0; |
| 10764 | watch->linked_cheat = NULL; |
| 10765 | watch->label[0] = 0; |
| 10818 | 10766 | } |
| 10767 | else |
| 10768 | SET_MESSAGE(kCheatMessage_FailedToDelete); |
| 10819 | 10769 | } |
| 10820 | 10770 | |
| 10821 | 10771 | /*------------------------------------------------------------------ |
| r2821 | r2822 | |
| 10826 | 10776 | { |
| 10827 | 10777 | if(new_length != search_list_length) |
| 10828 | 10778 | { |
| 10829 | | /* if delete, dispose deleted or later search lists */ |
| 10779 | /* free search list if delete */ |
| 10830 | 10780 | if(new_length < search_list_length) |
| 10831 | 10781 | { |
| 10832 | 10782 | int i; |
| r2821 | r2822 | |
| 10840 | 10790 | |
| 10841 | 10791 | if(search_list == NULL && new_length != 0) |
| 10842 | 10792 | { |
| 10843 | | /* memory allocation error */ |
| 10844 | | logerror("ResizeSearchList: out of memory resizing search list\n"); |
| 10845 | | ui_popup_time(2, "out of memory while adding search"); |
| 10846 | | |
| 10847 | | search_list_length = 0; |
| 10848 | | |
| 10849 | | return; |
| 10793 | fatalerror("cheat: [search info] memory allocation error\n" |
| 10794 | " length = %.8X\n" |
| 10795 | " new_length = %.8X\n" |
| 10796 | " search_list = %p\n", |
| 10797 | search_list_length, new_length, search_list); |
| 10850 | 10798 | } |
| 10851 | 10799 | |
| 10852 | | /* if insert, initialize new search list */ |
| 10800 | /* add new search list if insert */ |
| 10853 | 10801 | if(new_length > search_list_length) |
| 10854 | 10802 | { |
| 10855 | 10803 | int i; |
| r2821 | r2822 | |
| 10934 | 10882 | static void init_search(search_info *info) |
| 10935 | 10883 | { |
| 10936 | 10884 | if(info) |
| 10937 | | info->search_speed = ksearch_speed_Medium; |
| 10885 | info->search_speed = SEARCH_SPEED_MEDIUM; |
| 10938 | 10886 | } |
| 10939 | 10887 | |
| 10940 | 10888 | /*--------------------------------------------------------------------------- |
| r2821 | r2822 | |
| 10998 | 10946 | fill_buffer_from_region - fill selected search region with a value read from search address |
| 10999 | 10947 | ----------------------------------------------------------------------------------------------*/ |
| 11000 | 10948 | |
| 11001 | | static void fill_buffer_from_region(search_region *region, UINT8 * buf) |
| 10949 | static void fill_buffer_from_region(search_region *region, UINT8 *buf) |
| 11002 | 10950 | { |
| 11003 | 10951 | UINT32 offset; |
| 11004 | 10952 | |
| r2821 | r2822 | |
| 11066 | 11014 | info->backup_valid = 0; |
| 11067 | 11015 | |
| 11068 | 11016 | #if 1 |
| 11069 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 11070 | | messageType = kCheatMessage_RestoreValue; |
| 11017 | SET_MESSAGE(kCheatMessage_RestoreValue); |
| 11071 | 11018 | #else |
| 11072 | 11019 | ui_popup_time(1, "values restored"); /* not displayed when ui is opend */ |
| 11073 | 11020 | #endif |
| r2821 | r2822 | |
| 11075 | 11022 | else |
| 11076 | 11023 | { |
| 11077 | 11024 | #if 1 |
| 11078 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 11079 | | messageType = kCheatMessage_NoOldValue; |
| 11025 | SET_MESSAGE(kCheatMessage_NoOldValue); |
| 11080 | 11026 | #else |
| 11081 | 11027 | ui_popup_time(1, "there are no old values"); /* not displayed when ui is opend */ |
| 11082 | 11028 | #endif |
| r2821 | r2822 | |
| 11120 | 11066 | static UINT8 default_enable_region(running_machine *machine, search_region *region, search_info *info) |
| 11121 | 11067 | { |
| 11122 | 11068 | write8_machine_func handler = region->write_handler->write.mhandler8; |
| 11123 | | FPTR handlerAddress = (FPTR)handler; |
| 11069 | FPTR handler_address = (FPTR)handler; |
| 11124 | 11070 | |
| 11125 | 11071 | switch(info->search_speed) |
| 11126 | 11072 | { |
| 11127 | | case ksearch_speed_Fast: |
| 11128 | | #if HAS_SH2 |
| 11129 | | if( machine->config->cpu[0].type == CPU_SH2 && |
| 11130 | | (info->target_type == kRegionType_CPU && info->target_idx == 0 && region->address == 0x06000000)) |
| 11131 | | return 1; |
| 11132 | | else |
| 11133 | | return 0; |
| 11134 | | #endif |
| 11073 | case SEARCH_SPEED_FAST: |
| 11135 | 11074 | if(handler == SMH_RAM && region->write_handler->baseptr != NULL) |
| 11136 | 11075 | return 1; |
| 11137 | 11076 | |
| 11138 | | case ksearch_speed_Medium: |
| 11139 | | if(handlerAddress >= (FPTR)SMH_BANK1 && handlerAddress <= (FPTR)SMH_BANK24) |
| 11077 | case SEARCH_SPEED_MEDIUM: |
| 11078 | if(handler_address >= (FPTR)SMH_BANK1 && handler_address <= (FPTR)SMH_BANK32) |
| 11140 | 11079 | return 1; |
| 11141 | 11080 | |
| 11142 | 11081 | if(handler == SMH_RAM) |
| r2821 | r2822 | |
| 11144 | 11083 | |
| 11145 | 11084 | return 0; |
| 11146 | 11085 | |
| 11147 | | case ksearch_speed_Slow: |
| 11086 | case SEARCH_SPEED_SLOW: |
| 11148 | 11087 | if(handler == SMH_NOP || handler == SMH_ROM) |
| 11149 | 11088 | return 0; |
| 11150 | 11089 | |
| 11151 | | if(handlerAddress > STATIC_COUNT && region->write_handler->baseptr == NULL) |
| 11090 | if(handler_address > STATIC_COUNT && region->write_handler->baseptr == NULL) |
| 11152 | 11091 | return 0; |
| 11153 | 11092 | |
| 11154 | 11093 | return 1; |
| 11155 | 11094 | |
| 11156 | | case ksearch_speed_VerySlow: |
| 11095 | case SEARCH_SPEED_VERY_SLOW: |
| 11157 | 11096 | if(handler == SMH_NOP || handler == SMH_ROM) |
| 11158 | 11097 | return 0; |
| 11159 | 11098 | |
| r2821 | r2822 | |
| 11180 | 11119 | genf *handler = region->write_handler->write.generic; |
| 11181 | 11120 | FPTR handler_address = (FPTR)handler; |
| 11182 | 11121 | |
| 11183 | | if(handler_address >= (FPTR)SMH_BANK1 && handler_address <= (FPTR)SMH_BANK24) |
| 11122 | if(handler_address >= (FPTR)SMH_BANK1 && handler_address <= (FPTR)SMH_BANK32) |
| 11184 | 11123 | { |
| 11185 | 11124 | sprintf(desc, "BANK%.2d", (int)(handler_address - (FPTR)SMH_BANK1) + 1); |
| 11186 | 11125 | } |
| r2821 | r2822 | |
| 11214 | 11153 | } |
| 11215 | 11154 | } |
| 11216 | 11155 | |
| 11217 | | /*------------------------------------------------------------------------------------- |
| 11218 | | allocate_search_regions - free memory for search region then realloc if searchable |
| 11219 | | -------------------------------------------------------------------------------------*/ |
| 11156 | /*------------------------------------------------------------------ |
| 11157 | is_search_region_in_range - check valid range for search region |
| 11158 | ------------------------------------------------------------------*/ |
| 11220 | 11159 | |
| 11160 | static UINT8 is_search_region_in_range(UINT8 cpu, UINT32 length) |
| 11161 | { |
| 11162 | if(length > cpu_info_list[cpu].address_mask) |
| 11163 | return 0; |
| 11164 | |
| 11165 | /* all memory in 32-bit cpu causes zero length in several cases */ |
| 11166 | if(length == 0) |
| 11167 | return 0; |
| 11168 | |
| 11169 | if(length > SAFE_SEARCH_REGION_RANGE) |
| 11170 | return 0; |
| 11171 | |
| 11172 | return 1; |
| 11173 | } |
| 11174 | |
| 11175 | /*---------------------------------------------------------------- |
| 11176 | allocate_search_regions - memory allocation for search region |
| 11177 | ----------------------------------------------------------------*/ |
| 11178 | |
| 11221 | 11179 | static void allocate_search_regions(search_info *info) |
| 11222 | 11180 | { |
| 11223 | 11181 | int i; |
| r2821 | r2822 | |
| 11227 | 11185 | |
| 11228 | 11186 | for(i = 0; i < info->region_list_length; i++) |
| 11229 | 11187 | { |
| 11230 | | search_region *region; |
| 11188 | search_region *region = &info->region_list[i]; |
| 11231 | 11189 | |
| 11232 | | region = &info->region_list[i]; |
| 11233 | | region->num_results = 0; |
| 11190 | region->num_results = 0; |
| 11234 | 11191 | |
| 11235 | 11192 | free(region->first); |
| 11236 | 11193 | free(region->last); |
| r2821 | r2822 | |
| 11247 | 11204 | region->backup_status = malloc(region->length); |
| 11248 | 11205 | |
| 11249 | 11206 | if(region->first == NULL || region->last == NULL || region->status == NULL || region->backup_last == NULL || region->backup_status == NULL) |
| 11250 | | fatalerror( "cheat: [search region] memory allocation error\n" |
| 11251 | | " ----- %s -----\n" |
| 11252 | | " first = %p\n" |
| 11253 | | " last = %p\n" |
| 11254 | | " status = %p\n" |
| 11255 | | " backup_last = %p\n" |
| 11256 | | " backup_status = %p\n", |
| 11257 | | region->name, |
| 11258 | | region->first, region->last, region->status, region->backup_last, region->backup_status); |
| 11207 | { |
| 11208 | /* NOTE : ignored memory allocation error but locked this region */ |
| 11209 | free(region->first); |
| 11210 | free(region->last); |
| 11211 | free(region->status); |
| 11212 | free(region->backup_last); |
| 11213 | free(region->backup_status); |
| 11214 | |
| 11215 | region->first = NULL; |
| 11216 | region->last = NULL; |
| 11217 | region->status = NULL; |
| 11218 | region->backup_last = NULL; |
| 11219 | region->backup_status = NULL; |
| 11220 | region->flags &= ~kRegionFlag_Enabled; |
| 11221 | region->flags |= kRegionFlag_HasError; |
| 11222 | |
| 11223 | SET_MESSAGE(kCheatMessage_FailedToAllocate); |
| 11224 | } |
| 11259 | 11225 | } |
| 11260 | 11226 | else |
| 11261 | 11227 | { |
| r2821 | r2822 | |
| 11284 | 11250 | { |
| 11285 | 11251 | case kRegionType_CPU: |
| 11286 | 11252 | { |
| 11287 | | if(info->search_speed == ksearch_speed_AllMemory) |
| 11253 | if(info->search_speed == SEARCH_SPEED_ALL_MEMORY) |
| 11288 | 11254 | { |
| 11289 | 11255 | UINT32 length = cpu_info_list[info->target_idx].address_mask + 1; |
| 11290 | 11256 | search_region *region; |
| r2821 | r2822 | |
| 11303 | 11269 | region->status = NULL; |
| 11304 | 11270 | region->backup_last = NULL; |
| 11305 | 11271 | region->backup_status = NULL; |
| 11306 | | region->flags = kRegionFlag_Enabled; |
| 11307 | 11272 | |
| 11308 | 11273 | set_search_region_default_name(region); |
| 11274 | |
| 11275 | if(is_search_region_in_range(info->target_idx, length) == 0) |
| 11276 | { |
| 11277 | region->flags &= ~kRegionFlag_Enabled; |
| 11278 | region->flags |= kRegionFlag_HasError; |
| 11279 | } |
| 11280 | else |
| 11281 | region->flags = kRegionFlag_Enabled; |
| 11309 | 11282 | } |
| 11310 | 11283 | else |
| 11311 | 11284 | { |
| r2821 | r2822 | |
| 11342 | 11315 | traverse->status = NULL; |
| 11343 | 11316 | traverse->backup_last = NULL; |
| 11344 | 11317 | traverse->backup_status = NULL; |
| 11345 | | traverse->flags = default_enable_region(machine, traverse, info) ? kRegionFlag_Enabled : 0; |
| 11346 | 11318 | |
| 11319 | if(is_search_region_in_range(info->target_idx, length) == 0) |
| 11320 | { |
| 11321 | traverse->flags &= ~kRegionFlag_Enabled; |
| 11322 | traverse->flags |= kRegionFlag_HasError; |
| 11323 | } |
| 11324 | else |
| 11325 | traverse->flags = default_enable_region(machine, traverse, info) ? kRegionFlag_Enabled : 0; |
| 11326 | |
| 11347 | 11327 | set_search_region_default_name(traverse); |
| 11348 | 11328 | |
| 11349 | 11329 | traverse++; |
| r2821 | r2822 | |
| 11506 | 11486 | return newCode; |
| 11507 | 11487 | } |
| 11508 | 11488 | |
| 11509 | | /*------------------- |
| 11510 | | ConvertToNewCode |
| 11511 | | -------------------*/ |
| 11489 | /*---------------------- |
| 11490 | convert_to_new_code |
| 11491 | ----------------------*/ |
| 11512 | 11492 | |
| 11513 | | static int ConvertToNewCode(CheatAction * action) |
| 11493 | static int convert_to_new_code(cheat_action *action) |
| 11514 | 11494 | { |
| 11515 | | int newType = 0; |
| 11495 | int new_type = 0; |
| 11516 | 11496 | |
| 11517 | | if(EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed) |
| 11518 | | SET_FIELD(newType, CPURegion, EXTRACT_FIELD(action->type, LocationParameterCPU)); |
| 11519 | | else if(EXTRACT_FIELD(action->type, LocationType) != kLocation_Custom) |
| 11520 | | SET_FIELD(newType, CPURegion, EXTRACT_FIELD(action->type, LocationParameter)); |
| 11521 | | |
| 11522 | | if(TEST_FIELD(action->type, UserSelectEnable)) |
| 11523 | | SET_FIELD(newType, CodeType, kCodeType_VWrite); |
| 11524 | | else if(EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed) |
| 11525 | | { SET_FIELD(newType, CodeType, kCodeType_IWrite); |
| 11526 | | SET_FIELD(newType, IndexSize, EXTRACT_FIELD(action->type, LocationParameterOption)); } |
| 11527 | | else |
| 11528 | | { SET_FIELD(newType, CodeType, kCodeType_PDWWrite); |
| 11529 | | SET_FIELD(newType, IndexSize, kSearchSize_32Bit); } |
| 11530 | | |
| 11531 | | SET_FIELD(newType, AddressSize, EXTRACT_FIELD(action->type, BytesUsed)); |
| 11532 | | |
| 11533 | | if(TEST_FIELD(action->type, LinkEnable)) |
| 11534 | | SET_FIELD(newType, Link, kLink_Link); |
| 11535 | | |
| 11497 | if(EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed) { |
| 11498 | SET_FIELD(new_type, CodeType, kCodeType_IWrite); |
| 11499 | SET_FIELD(new_type, CodeParameter, EXTRACT_FIELD(action->type, LocationParameterOption)); } |
| 11500 | SET_FIELD(new_type, AddressSize, kSearchSize_32Bit); |
| 11501 | SET_MASK_FIELD(new_type, Endianness); |
| 11536 | 11502 | if(TEST_FIELD(action->type, RestorePreviousValue)) |
| 11537 | | SET_MASK_FIELD(newType, RestoreValue); |
| 11538 | | |
| 11503 | SET_MASK_FIELD(new_type, RestoreValue); |
| 11539 | 11504 | if(EXTRACT_FIELD(action->type, Prefill)) |
| 11540 | | SET_MASK_FIELD(newType, PrefillEnable); |
| 11505 | SET_FIELD(new_type, PrefillEnable, 0); |
| 11506 | if(EXTRACT_FIELD(action->type, Type) == kLocation_Standard && EXTRACT_FIELD(action->type, TypeParameter)) |
| 11507 | SET_MASK_FIELD(new_type, DelayEnable); |
| 11541 | 11508 | |
| 11542 | | if(!EXTRACT_FIELD(action->type, Type) && EXTRACT_FIELD(action->type, TypeParameter)) |
| 11543 | | SET_MASK_FIELD(newType, DelayEnable); |
| 11544 | | |
| 11545 | | if(TEST_FIELD(action->type, OneShot)) |
| 11546 | | SET_MASK_FIELD(newType, OneShot); |
| 11547 | | |
| 11548 | | return newType; |
| 11509 | return new_type; |
| 11549 | 11510 | } |
| 11550 | 11511 | |
| 11551 | | /*-------------------------- |
| 11552 | | HandleLocalCommandCheat |
| 11553 | | --------------------------*/ |
| 11512 | /*------------------------------------------------------------------- |
| 11513 | handle_local_command_cheat - handle specified cheat command code |
| 11514 | -------------------------------------------------------------------*/ |
| 11554 | 11515 | |
| 11555 | | static void HandleLocalCommandCheat(running_machine *machine, int cpu, int type, int address, int data, UINT8 format) |
| 11516 | static void handle_local_command_cheat(running_machine *machine, int cpu, int type, int address, int data, UINT8 format) |
| 11556 | 11517 | { |
| 11557 | 11518 | int command = 0; |
| 11558 | 11519 | |
| 11559 | | if(format != 1) |
| 11520 | if(format != FORMAT_NEW) |
| 11560 | 11521 | { |
| 11561 | 11522 | switch(EXTRACT_FIELD(type, LocationParameter)) |
| 11562 | 11523 | { |
| 11563 | 11524 | case kCustomLocation_AssignActivationKey: |
| 11564 | | command = kCustomCode_ActivationKey1; |
| 11525 | command = CUSTOM_CODE_ACTIVATION_KEY_1; |
| 11565 | 11526 | |
| 11566 | 11527 | if(TEST_FIELD(type, OneShot)) |
| 11567 | | command = kCustomCode_ActivationKey2; |
| 11528 | command = CUSTOM_CODE_ACTIVATION_KEY_2; |
| 11568 | 11529 | break; |
| 11569 | 11530 | |
| 11570 | 11531 | case kCustomLocation_Enable: |
| 11571 | | command = kCustomCode_PreEnable; |
| 11532 | command = CUSTOM_CODE_PRE_ENABLE; |
| 11572 | 11533 | break; |
| 11573 | 11534 | |
| 11574 | 11535 | case kCustomLocation_Overclock: |
| 11575 | | command = kCustomCode_OverClock; |
| 11536 | command = CUSTOM_CODE_OVER_CLOCK; |
| 11576 | 11537 | break; |
| 11577 | 11538 | |
| 11578 | 11539 | case kCustomLocation_RefreshRate: |
| 11579 | | command = kCustomCode_RefreshRate; |
| 11540 | command = CUSTOM_CODE_REFRESH_RATE; |
| 11580 | 11541 | break; |
| 11581 | 11542 | |
| 11582 | 11543 | default: |
| r2821 | r2822 | |
| 11584 | 11545 | } |
| 11585 | 11546 | } |
| 11586 | 11547 | else |
| 11587 | | command = EXTRACT_FIELD(type, CodeType); |
| 11548 | command = cpu; |
| 11588 | 11549 | |
| 11589 | 11550 | switch(command) |
| 11590 | 11551 | { |
| 11591 | | case kCustomCode_ActivationKey1: |
| 11592 | | case kCustomCode_ActivationKey2: |
| 11593 | | if(address < cheatListLength) |
| 11552 | case CUSTOM_CODE_ACTIVATION_KEY_1: |
| 11553 | case CUSTOM_CODE_ACTIVATION_KEY_2: |
| 11554 | if(address < cheat_list_length) |
| 11594 | 11555 | { |
| 11595 | | CheatEntry * entry = &cheatList[address]; |
| 11556 | cheat_entry *entry = &cheat_list[address]; |
| 11596 | 11557 | |
| 11597 | | if(command == kCustomCode_ActivationKey1) |
| 11558 | if(command == CUSTOM_CODE_ACTIVATION_KEY_1) |
| 11598 | 11559 | { |
| 11599 | | entry->activationKey2 = data; |
| 11560 | entry->activation_key2 = data; |
| 11600 | 11561 | entry->flags |= kCheatFlag_HasActivationKey2; |
| 11601 | 11562 | } |
| 11602 | 11563 | else |
| 11603 | 11564 | { |
| 11604 | | entry->activationKey1 = data; |
| 11565 | entry->activation_key1 = data; |
| 11605 | 11566 | entry->flags |= kCheatFlag_HasActivationKey1; |
| 11606 | 11567 | } |
| 11607 | 11568 | } |
| 11608 | 11569 | break; |
| 11609 | 11570 | |
| 11610 | | case kCustomCode_PreEnable: |
| 11611 | | if(address < cheatListLength) |
| 11571 | case CUSTOM_CODE_PRE_ENABLE: |
| 11572 | if(address < cheat_list_length) |
| 11612 | 11573 | { |
| 11613 | | CheatEntry * entry = &cheatList[address]; |
| 11574 | cheat_entry *entry = &cheat_list[address]; |
| 11614 | 11575 | |
| 11615 | 11576 | ActivateCheat(entry); |
| 11616 | 11577 | |
| 11617 | | if(data && (data < entry->actionListLength)) |
| 11578 | if(data && data < entry->action_list_length) |
| 11618 | 11579 | entry->selection = data; |
| 11619 | 11580 | } |
| 11620 | 11581 | break; |
| 11621 | 11582 | |
| 11622 | | case kCustomCode_OverClock: |
| 11623 | | if(VALID_CPU(cpu)) |
| 11583 | case CUSTOM_CODE_OVER_CLOCK: |
| 11584 | if(VALID_CPU(address)) |
| 11624 | 11585 | { |
| 11625 | | double overclock = data / 65536.0; |
| 11586 | double over_clock = data / 65536.0; |
| 11626 | 11587 | |
| 11627 | | cpunum_set_clockscale(machine, address, overclock); |
| 11588 | cpunum_set_clockscale(machine, address, over_clock); |
| 11628 | 11589 | } |
| 11629 | 11590 | break; |
| 11630 | 11591 | |
| 11631 | | case kCustomCode_RefreshRate: |
| 11592 | case CUSTOM_CODE_REFRESH_RATE: |
| 11632 | 11593 | { |
| 11633 | 11594 | int width = video_screen_get_width(machine->primary_screen); |
| 11634 | 11595 | int height = video_screen_get_height(machine->primary_screen); |
| r2821 | r2822 | |
| 11642 | 11603 | } |
| 11643 | 11604 | } |
| 11644 | 11605 | |
| 11645 | | /*---------------------------------------------------- |
| 11646 | | LoadCheatOption - load cheat option from database |
| 11647 | | ----------------------------------------------------*/ |
| 11606 | /*------------------------------------------------------ |
| 11607 | load_cheat_option - load cheat option from database |
| 11608 | ------------------------------------------------------*/ |
| 11648 | 11609 | |
| 11649 | | static void LoadCheatOption(char * fileName) |
| 11610 | static void load_cheat_option(char *file_name) |
| 11650 | 11611 | { |
| 11651 | 11612 | static char buf[2048]; |
| 11652 | | mame_file * theFile; |
| 11613 | mame_file *the_file; |
| 11653 | 11614 | file_error filerr; |
| 11654 | | cheat_format * format = &cheat_format_table[0]; |
| 11615 | cheat_format *format = &cheat_format_table[0]; |
| 11655 | 11616 | |
| 11656 | 11617 | /* open the database */ |
| 11657 | | filerr = mame_fopen(SEARCHPATH_CHEAT, fileName, OPEN_FLAG_READ, &theFile); |
| 11618 | filerr = mame_fopen(SEARCHPATH_CHEAT, file_name, OPEN_FLAG_READ, &the_file); |
| 11658 | 11619 | |
| 11659 | 11620 | if(filerr != FILERR_NONE) |
| 11660 | 11621 | { |
| 11661 | | messageType = kCheatMessage_FailedToLoadDatabase; |
| 11662 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 11622 | SET_MESSAGE(kCheatMessage_FailedToLoadDatabase); |
| 11663 | 11623 | return; |
| 11664 | 11624 | } |
| 11665 | 11625 | |
| 11666 | | while(mame_fgets(buf, 2048, theFile)) |
| 11626 | while(mame_fgets(buf, 2048, the_file)) |
| 11667 | 11627 | { |
| 11668 | | char preCommand[9]; |
| 11628 | char pre_command[9]; |
| 11669 | 11629 | |
| 11670 | | if(sscanf(buf, format->format_string, preCommand) == format->arguments_matched) |
| 11630 | if(sscanf(buf, format->format_string, pre_command) == format->arguments_matched) |
| 11671 | 11631 | { |
| 11672 | | if(strlen(preCommand) == format->length_matched) |
| 11632 | if(strlen(pre_command) == format->type_matched) |
| 11673 | 11633 | { |
| 11674 | | sscanf(preCommand, "%X", &cheatOptions); |
| 11675 | | messageType = kCheatMessage_ReloadCheatOption; |
| 11676 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 11634 | sscanf(pre_command, "%X", &cheat_options); |
| 11635 | SET_MESSAGE(kCheatMessage_ReloadCheatOption); |
| 11677 | 11636 | } |
| 11678 | 11637 | } |
| 11679 | 11638 | } |
| 11680 | 11639 | |
| 11681 | | mame_fclose(theFile); |
| 11640 | mame_fclose(the_file); |
| 11682 | 11641 | } |
| 11683 | 11642 | |
| 11684 | | /*------------------------------------------------ |
| 11685 | | LoadCheatCode - load cheat code from database |
| 11686 | | ------------------------------------------------*/ |
| 11643 | /*-------------------------------------------------- |
| 11644 | load_cheat_code - load cheat code from database |
| 11645 | --------------------------------------------------*/ |
| 11687 | 11646 | |
| 11688 | | static void LoadCheatCode(running_machine *machine, char * fileName) |
| 11647 | static void load_cheat_code(running_machine *machine, char *file_name) |
| 11689 | 11648 | { |
| 11690 | | enum{ |
| 11691 | | kFormatLevel_New = 1, |
| 11692 | | kFormatLevel_Standard, |
| 11693 | | kFormatLevel_Old }; |
| 11694 | | |
| 11695 | 11649 | char buf[2048]; |
| 11696 | | mame_file * theFile; |
| 11650 | mame_file *the_file; |
| 11697 | 11651 | file_error filerr; |
| 11698 | 11652 | |
| 11699 | 11653 | /* open the database */ |
| 11700 | | filerr = mame_fopen(SEARCHPATH_CHEAT, fileName, OPEN_FLAG_READ, &theFile); |
| 11654 | filerr = mame_fopen(SEARCHPATH_CHEAT, file_name, OPEN_FLAG_READ, &the_file); |
| 11701 | 11655 | |
| 11702 | 11656 | if(filerr != FILERR_NONE) |
| 11703 | 11657 | return; |
| 11704 | 11658 | |
| 11705 | | foundCheatDatabase = 1; |
| 11659 | found_database = 1; |
| 11706 | 11660 | |
| 11707 | 11661 | /* get a line from database */ |
| 11708 | | while(mame_fgets(buf, 2048, theFile)) |
| 11662 | while(mame_fgets(buf, 2048, the_file)) |
| 11709 | 11663 | { |
| 11710 | | int i; |
| 11664 | int i; |
| 11711 | 11665 | #ifdef MESS |
| 11712 | | int crc; |
| 11666 | int crc; |
| 11713 | 11667 | #endif |
| 11714 | | int type = 0; |
| 11715 | | int address = 0; |
| 11716 | | int data = 0; |
| 11717 | | int extendData = 0; |
| 11718 | | int argumentsMatched = 0; |
| 11719 | | int formatLevel = 0; |
| 11720 | | int oldCPU = 0; |
| 11721 | | int oldCode = 0; |
| 11722 | | char name[16] = { 0 }; |
| 11723 | | char preData[16] = { 0 }; |
| 11724 | | char preExtendData[16] = { 0 }; |
| 11725 | | char description[256] = { 0 }; |
| 11726 | | char comment[256] = { 0 }; |
| 11727 | | CheatEntry * entry; |
| 11728 | | CheatAction * action; |
| 11668 | int type = 0; |
| 11669 | int address = 0; |
| 11670 | int data = 0; |
| 11671 | int extend_data = 0; |
| 11672 | int arguments_matched = 0; |
| 11673 | int format_level = 0; |
| 11674 | int cpu = 0; |
| 11675 | int code = 0; |
| 11676 | char name[16] = { 0 }; |
| 11677 | char pre_type[16] = { 0 }; |
| 11678 | char pre_data[16] = { 0 }; |
| 11679 | char pre_extend_data[16] = { 0 }; |
| 11680 | char description[256] = { 0 }; |
| 11681 | char comment[256] = { 0 }; |
| 11729 | 11682 | |
| 11683 | cheat_entry *entry; |
| 11684 | cheat_action *action; |
| 11685 | |
| 11730 | 11686 | /* scan and check format */ |
| 11731 | 11687 | for(i = 1; i < 4; i++) |
| 11732 | 11688 | { |
| 11733 | | cheat_format * format = &cheat_format_table[i]; |
| 11689 | cheat_format *format = &cheat_format_table[i]; |
| 11734 | 11690 | |
| 11691 | if(TEST_FIELD(cheat_options, LoadOldFormat) == 0) |
| 11692 | { |
| 11693 | if(i != 1) |
| 11694 | break; |
| 11695 | } |
| 11696 | |
| 11735 | 11697 | /* scan a parameter */ |
| 11736 | 11698 | switch(i) |
| 11737 | 11699 | { |
| 11738 | | case kFormatLevel_New: |
| 11739 | | case kFormatLevel_Standard: |
| 11700 | case FORMAT_NEW: |
| 11701 | case FORMAT_STANDARD: |
| 11740 | 11702 | #ifdef MESS |
| 11741 | | argumentsMatched = sscanf(buf, format->format_string, name, &crc, &type, &address, preData, preExtendData, description, comment); |
| 11703 | arguments_matched = sscanf(buf, format->format_string, name, &crc, pre_type, &address, pre_data, pre_extend_data, description, comment); |
| 11742 | 11704 | #else |
| 11743 | | argumentsMatched = sscanf(buf, format->format_string, name, &type, &address, preData, preExtendData, description, comment); |
| 11705 | arguments_matched = sscanf(buf, format->format_string, name, pre_type, &address, pre_data, pre_extend_data, description, comment); |
| 11744 | 11706 | #endif |
| 11745 | 11707 | break; |
| 11746 | 11708 | |
| 11747 | | case kFormatLevel_Old: |
| 11709 | case FORMAT_OLD: |
| 11748 | 11710 | #ifdef MESS |
| 11749 | | argumentsMatched = sscanf(buf, format->format_string, &crc, name, &oldCPU, &address, &data, &oldCode, description, comment); |
| 11711 | arguments_matched = sscanf(buf, format->format_string, &crc, name, &cpu, &address, &data, &code, description, comment); |
| 11750 | 11712 | #else |
| 11751 | | argumentsMatched = sscanf(buf, format->format_string, name, &oldCPU, &address, &data, &oldCode, description, comment); |
| 11713 | arguments_matched = sscanf(buf, format->format_string, name, &cpu, &address, &data, &code, description, comment); |
| 11752 | 11714 | #endif |
| 11753 | 11715 | } |
| 11754 | 11716 | |
| 11755 | 11717 | /* NOTE : description and comment are not always needed */ |
| 11756 | | if(argumentsMatched < format->arguments_matched) |
| 11718 | if(arguments_matched < format->arguments_matched) |
| 11757 | 11719 | continue; |
| 11758 | 11720 | |
| 11759 | 11721 | #ifdef MESS |
| 11760 | 11722 | /* check name */ |
| 11761 | | if(TEST_FIELD(cheatOptions, SharedCode) && strcmp(machine->gamedrv->parent, "0")) |
| 11723 | if(TEST_FIELD(cheat_options, SharedCode) && strcmp(machine->gamedrv->parent, "0")) |
| 11762 | 11724 | { |
| 11763 | 11725 | if(strcmp(name, machine->gamedrv->parent)) |
| 11764 | 11726 | break; |
| r2821 | r2822 | |
| 11772 | 11734 | if(MatchesCRCTable(crc) == 0) |
| 11773 | 11735 | break; |
| 11774 | 11736 | #endif |
| 11775 | | if(i != kFormatLevel_Old) |
| 11737 | if(i != FORMAT_OLD) |
| 11776 | 11738 | { |
| 11777 | | UINT8 hasError = 0; |
| 11739 | UINT8 is_error = 0; |
| 11778 | 11740 | |
| 11779 | | /* check the length of data and extendData */ |
| 11780 | | if(strlen(preData) != format->length_matched) |
| 11741 | /* check length */ |
| 11742 | if(strlen(pre_type) != format->type_matched) |
| 11781 | 11743 | { |
| 11782 | | logerror("cheat - LoadCheatFile : %s has invalid extend data field length\n", description); |
| 11783 | | messageType = kCheatMessage_WrongCode; |
| 11784 | | hasError++; |
| 11744 | logerror("cheat: [load code] %s has invalid type field length (%X)\n", description, (int)strlen(pre_type)); |
| 11745 | is_error++; |
| 11785 | 11746 | } |
| 11786 | 11747 | |
| 11787 | | if(strlen(preExtendData) != format->length_matched) |
| 11748 | if(strlen(pre_data) != format->data_matched) |
| 11788 | 11749 | { |
| 11789 | | logerror("cheat - LoadCheatFile : %s has invalid data field length\n", description); |
| 11790 | | messageType = kCheatMessage_WrongCode; |
| 11791 | | hasError++; |
| 11750 | logerror("cheat: [load code] %s has invalid data field length (%X)\n", description, (int)strlen(pre_type)); |
| 11751 | is_error++; |
| 11792 | 11752 | } |
| 11793 | 11753 | |
| 11794 | | if(hasError) |
| 11754 | if(strlen(pre_extend_data) != format->data_matched) |
| 11755 | { |
| 11756 | logerror("cheat: [load code] %s has invalid extend data field length (%X)\n", description, (int)strlen(pre_extend_data)); |
| 11757 | is_error++; |
| 11758 | } |
| 11759 | |
| 11760 | if(is_error) |
| 11761 | { |
| 11762 | SET_MESSAGE(kCheatMessage_WrongCode); |
| 11795 | 11763 | continue; |
| 11764 | } |
| 11796 | 11765 | else |
| 11797 | 11766 | { |
| 11798 | | sscanf(preData, "%X", &data); |
| 11799 | | sscanf(preExtendData, "%X", &extendData); |
| 11767 | if(i == FORMAT_NEW) |
| 11768 | sscanf(pre_type, "%2X%8X", &cpu, &type); |
| 11769 | else |
| 11770 | { |
| 11771 | sscanf(pre_type, "%X", &type); |
| 11772 | cpu = EXTRACT_FIELD(type, LocationParameter) & 0x0F; |
| 11773 | } |
| 11774 | |
| 11775 | sscanf(pre_data, "%X", &data); |
| 11776 | sscanf(pre_extend_data, "%X", &extend_data); |
| 11800 | 11777 | } |
| 11801 | 11778 | } |
| 11802 | 11779 | else |
| 11803 | | type = ConvertOldCode(oldCode, oldCPU, &data, &extendData); |
| 11780 | type = ConvertOldCode(code, cpu, &data, &extend_data); |
| 11804 | 11781 | |
| 11805 | 11782 | /* matched! */ |
| 11806 | | formatLevel = i; |
| 11783 | format_level = i; |
| 11807 | 11784 | break; |
| 11808 | 11785 | } |
| 11809 | 11786 | |
| 11810 | 11787 | /* attemp to get next line if unmatched */ |
| 11811 | | if(formatLevel == 0) |
| 11788 | if(format_level == 0 || format_level >= 4) |
| 11812 | 11789 | continue; |
| 11813 | 11790 | |
| 11814 | | //logerror("cheat: processing %s\n", buf); |
| 11791 | /* logerror("cheat: processing %s\n", buf); */ |
| 11815 | 11792 | |
| 11816 | 11793 | /* handle command code */ |
| 11817 | | if(formatLevel == kFormatLevel_New) |
| 11794 | if(cpu >= CUSTOM_CODE_ACTIVATION_KEY_1) |
| 11818 | 11795 | { |
| 11819 | | if(EXTRACT_FIELD(type, CPURegion) == CUSTOM_CODE && EXTRACT_FIELD(type, CodeType) >= kCustomCode_ActivationKey1) |
| 11820 | | { |
| 11821 | | // logerror("cheat: cheat line removed\n", buf); |
| 11822 | | HandleLocalCommandCheat(machine, EXTRACT_FIELD(type, CPUIndex), type, address, data, formatLevel); |
| 11823 | | continue; |
| 11824 | | } |
| 11796 | /* logerror("cheat: cheat line removed\n", buf); */ |
| 11797 | handle_local_command_cheat(machine, cpu, type, address, data, format_level); |
| 11798 | continue; |
| 11825 | 11799 | } |
| 11826 | | else |
| 11827 | | { |
| 11828 | | if( EXTRACT_FIELD(type, LocationType) == kLocation_Custom && |
| 11829 | | EXTRACT_FIELD(type, LocationParameter) <= kCustomLocation_AssignActivationKey) |
| 11830 | | { |
| 11831 | | HandleLocalCommandCheat(machine, EXTRACT_FIELD(type, LocationParameter), type, address, data, formatLevel); |
| 11832 | | continue; |
| 11833 | | } |
| 11834 | | } |
| 11835 | 11800 | |
| 11836 | 11801 | /***** ENTRY *****/ |
| 11837 | 11802 | if(EXTRACT_FIELD(type, Link) == kLink_Master) |
| 11838 | 11803 | { |
| 11839 | 11804 | /* 1st (master) code in an entry */ |
| 11840 | | ResizeCheatList(cheatListLength + 1); |
| 11805 | resize_cheat_list(cheat_list_length + 1, REQUEST_DISPOSE); |
| 11841 | 11806 | |
| 11842 | | if(cheatListLength == 0) |
| 11807 | if(cheat_list_length == 0) |
| 11843 | 11808 | { |
| 11844 | | logerror("cheat - LoadCheatFile: cheat list resize failed; bailing\n"); |
| 11809 | logerror("cheat: [load code] cheat list resize failed. bailing\n"); |
| 11845 | 11810 | goto bail; |
| 11846 | 11811 | } |
| 11847 | 11812 | |
| 11848 | | entry = &cheatList[cheatListLength - 1]; |
| 11813 | entry = &cheat_list[cheat_list_length - 1]; |
| 11849 | 11814 | |
| 11850 | 11815 | entry->name = create_string_copy(description); |
| 11851 | 11816 | |
| 11852 | | if(argumentsMatched == cheat_format_table[formatLevel].comment_matched) |
| 11817 | if(arguments_matched == cheat_format_table[format_level].comment_matched) |
| 11853 | 11818 | entry->comment = create_string_copy(comment); |
| 11854 | 11819 | } |
| 11855 | 11820 | else |
| 11856 | 11821 | { |
| 11857 | 11822 | /* 2nd or later (link) code in an entry */ |
| 11858 | | if(cheatListLength == 0) |
| 11823 | if(cheat_list_length == 0) |
| 11859 | 11824 | { |
| 11860 | | logerror("cheat - LoadCheatFile: first cheat found was link cheat; bailing\n"); |
| 11825 | logerror("cheat: [load code] first cheat found was link cheat. bailing\n"); |
| 11861 | 11826 | goto bail; |
| 11862 | 11827 | } |
| 11863 | 11828 | |
| 11864 | | entry = &cheatList[cheatListLength - 1]; |
| 11829 | entry = &cheat_list[cheat_list_length - 1]; |
| 11865 | 11830 | } |
| 11866 | 11831 | |
| 11867 | 11832 | /***** ACTION *****/ |
| 11868 | | ResizeCheatActionList(&cheatList[cheatListLength - 1], entry->actionListLength + 1); |
| 11833 | resize_cheat_action_list(&cheat_list[cheat_list_length - 1], entry->action_list_length + 1, REQUEST_DISPOSE); |
| 11869 | 11834 | |
| 11870 | | if(entry->actionListLength == 0) |
| 11835 | if(entry->action_list_length == 0) |
| 11871 | 11836 | { |
| 11872 | | logerror("cheat - LoadCheatFile: action list resize failed; bailing\n"); |
| 11837 | logerror("cheat: [load code] action list resize failed. bailing\n"); |
| 11873 | 11838 | goto bail; |
| 11874 | 11839 | } |
| 11875 | 11840 | |
| 11876 | | action = &entry->actionList[entry->actionListLength - 1]; |
| 11841 | action = &entry->action_list[entry->action_list_length - 1]; |
| 11842 | action->flags = 0; |
| 11843 | action->type = type; |
| 11844 | action->region = cpu; |
| 11845 | action->address = address; |
| 11846 | action->original_address = address; |
| 11847 | action->data = data; |
| 11848 | action->original_data = data; |
| 11849 | action->extend_data = extend_data; |
| 11850 | action->optional_name = create_string_copy(description); |
| 11851 | action->last_value = NULL; |
| 11877 | 11852 | |
| 11878 | | action->flags = 0; |
| 11879 | | action->type = type; |
| 11880 | | action->address = action->originalAddress = address; |
| 11881 | | action->data = action->originalDataField = data; |
| 11882 | | action->extendData = extendData; |
| 11883 | | action->optionalName = create_string_copy(description); |
| 11884 | | action->lastValue = NULL; |
| 11885 | | |
| 11886 | | if(formatLevel != kFormatLevel_New) |
| 11853 | if(format_level != FORMAT_NEW) |
| 11887 | 11854 | action->flags |= kActionFlag_OldFormat; |
| 11888 | 11855 | } |
| 11889 | 11856 | |
| 11890 | 11857 | bail: |
| 11891 | 11858 | |
| 11892 | | /* close the database */ |
| 11893 | | mame_fclose(theFile); |
| 11859 | mame_fclose(the_file); |
| 11894 | 11860 | } |
| 11895 | 11861 | |
| 11896 | | /*-------------------------------------------------------------------------------- |
| 11897 | | LoadUserDefinedSearchRegion - load user region code and rebuild search region |
| 11898 | | --------------------------------------------------------------------------------*/ |
| 11862 | /*------------------------------------------------------------------------------------ |
| 11863 | load_user_defined_search_region - load user region code and rebuild search region |
| 11864 | ------------------------------------------------------------------------------------*/ |
| 11899 | 11865 | |
| 11900 | | static void LoadUserDefinedSearchRegion(running_machine *machine, char * fileName) |
| 11866 | static void load_user_defined_search_region(running_machine *machine, char *file_name) |
| 11901 | 11867 | { |
| 11902 | 11868 | int count = 0; |
| 11903 | 11869 | char buf[2048]; |
| 11904 | 11870 | |
| 11905 | | search_info *info = get_current_search(); |
| 11906 | | mame_file * theFile; |
| 11871 | search_info *info = get_current_search(); |
| 11872 | mame_file *the_file; |
| 11907 | 11873 | file_error filerr; |
| 11908 | | cheat_format * format = &cheat_format_table[4]; |
| 11874 | cheat_format *format = &cheat_format_table[4]; |
| 11909 | 11875 | |
| 11910 | 11876 | /* 1st, free all search regions in current search_info */ |
| 11911 | 11877 | dispose_search_reigons(info); |
| 11912 | 11878 | |
| 11913 | 11879 | /* 2nd, attempt to open the memorymap file */ |
| 11914 | | filerr = mame_fopen(SEARCHPATH_CHEAT, fileName, OPEN_FLAG_READ, &theFile); |
| 11880 | filerr = mame_fopen(SEARCHPATH_CHEAT, file_name, OPEN_FLAG_READ, &the_file); |
| 11915 | 11881 | |
| 11916 | 11882 | if(filerr != FILERR_NONE) |
| 11917 | 11883 | { |
| 11918 | | info->region_list_length = 0; |
| 11919 | | messageType = kCheatMessage_FailedToLoadDatabase; |
| 11920 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 11884 | info->region_list_length = 0; |
| 11885 | SET_MESSAGE(kCheatMessage_FailedToLoadDatabase); |
| 11921 | 11886 | return; |
| 11922 | 11887 | } |
| 11923 | 11888 | |
| 11924 | 11889 | /* 3rd, scan parameters from the file */ |
| 11925 | | while(mame_fgets(buf, 2048, theFile)) |
| 11890 | while(mame_fgets(buf, 2048, the_file)) |
| 11926 | 11891 | { |
| 11927 | 11892 | #ifdef MESS |
| 11928 | 11893 | int crc; |
| r2821 | r2822 | |
| 11932 | 11897 | int start; |
| 11933 | 11898 | int end; |
| 11934 | 11899 | int status; |
| 11935 | | char name[9]; |
| 11936 | | char description[64]; |
| 11900 | char name[16] = { 0 }; |
| 11901 | char description[64] = { 0 }; |
| 11937 | 11902 | |
| 11938 | 11903 | cpu_region_info *cpu_info; |
| 11939 | 11904 | search_region *region; |
| 11940 | 11905 | |
| 11941 | | description[0] = 0; |
| 11942 | | |
| 11943 | 11906 | #ifdef MESS |
| 11944 | 11907 | if(sscanf(buf, format->format_string, name, &crc, &cpu, &space, &start, &end, &status, description) < format->arguments_matched) |
| 11945 | 11908 | #else |
| r2821 | r2822 | |
| 11949 | 11912 | else |
| 11950 | 11913 | { |
| 11951 | 11914 | #ifdef MESS |
| 11952 | | if(!MatchesCRCTable(crc)) |
| 11915 | if(MatchesCRCTable(crc) == 0) |
| 11953 | 11916 | continue; |
| 11954 | 11917 | #endif |
| 11955 | 11918 | if(cpu != info->target_idx) |
| r2821 | r2822 | |
| 11959 | 11922 | cpu_info = get_cpu_info(cpu); |
| 11960 | 11923 | |
| 11961 | 11924 | /* check parameters */ |
| 11925 | switch(space) |
| 11962 | 11926 | { |
| 11963 | | switch(space) |
| 11964 | | { |
| 11965 | | case kAddressSpace_Program: // standard program space |
| 11966 | | case kAddressSpace_DirectMemory: // direct memory access for standard program space |
| 11967 | | /* check length */ |
| 11968 | | if(start >= end) |
| 11969 | | { |
| 11970 | | logerror("cheat - LoadUserDefinedSearchRegion : invalid length (start : %X >= end : %X) \n", start, end); |
| 11971 | | continue; |
| 11972 | | } |
| 11927 | case kAddressSpace_Program: |
| 11928 | case kAddressSpace_DirectMemory: |
| 11929 | /* check length */ |
| 11930 | if(start >= end) |
| 11931 | { |
| 11932 | logerror("cheat: [user region] invalid length (start : %.8X >= end : %.8X)\n", start, end); |
| 11933 | continue; |
| 11934 | } |
| 11973 | 11935 | |
| 11974 | | /* check bound */ |
| 11975 | | if(end > cpu_info->address_mask) |
| 11976 | | { |
| 11977 | | logerror("cheat - LoadUserDefinedSearchRegion : end address (%X) is out of range\n", end); |
| 11978 | | continue; |
| 11979 | | } |
| 11980 | | break; |
| 11981 | | |
| 11982 | | case kAddressSpace_DataSpace: // data space |
| 11983 | | case kAddressSpace_IOSpace: // I/O space |
| 11984 | | // underconstruction... |
| 11985 | | break; |
| 11986 | | |
| 11987 | | default: |
| 11988 | | logerror("cheat - LoadUserDefinedSearchRegion : %X is invalid space\n", space); |
| 11936 | /* check bound */ |
| 11937 | if(is_search_region_in_range(info->target_idx, start + end + 1) == 0) |
| 11938 | { |
| 11939 | logerror("cheat: [user region] invalid length (%.8X)\n", start - end); |
| 11989 | 11940 | continue; |
| 11990 | | } |
| 11941 | } |
| 11942 | break; |
| 11991 | 11943 | |
| 11992 | | /* check status */ |
| 11993 | | if(status > 1) |
| 11994 | | { |
| 11995 | | logerror("cheat - LoadUserDefinedSearchRegion : %X is invalid status\n", status); |
| 11944 | case kAddressSpace_DataSpace: |
| 11945 | case kAddressSpace_IOSpace: |
| 11946 | /* underconstruction... */ |
| 11947 | break; |
| 11948 | |
| 11949 | default: |
| 11950 | logerror("cheat: [user region] %X is invalid space\n", space); |
| 11996 | 11951 | continue; |
| 11997 | | } |
| 11998 | 11952 | } |
| 11999 | 11953 | |
| 11954 | /* check status */ |
| 11955 | if(status > kRegionFlag_Enabled) |
| 11956 | { |
| 11957 | logerror("cheat: [user region] %X is invalid status\n", status); |
| 11958 | continue; |
| 11959 | } |
| 11960 | |
| 12000 | 11961 | /* allocate memory for new search region */ |
| 12001 | 11962 | info->region_list = realloc(info->region_list, (count + 1) * sizeof(search_region)); |
| 12002 | 11963 | |
| 12003 | | if(!info->region_list) |
| 11964 | if(info->region_list == NULL) |
| 12004 | 11965 | { |
| 12005 | | /* memory allocation error */ |
| 12006 | | logerror("cheat - LoadUserDefinedSearchRegion: out of memory resizing search region\n"); |
| 12007 | | ui_popup_time(2, "out of memory while buiding user search region"); |
| 12008 | | info->region_list_length = 0; |
| 12009 | | mame_fclose(theFile); |
| 12010 | | return; |
| 11966 | mame_fclose(the_file); |
| 11967 | fatalerror( "cheat: [user region] memory allocation error\n" |
| 11968 | " length = %.8X\n" |
| 11969 | " region_list = %p\n", |
| 11970 | count + 1, info->region_list); |
| 12011 | 11971 | } |
| 12012 | 11972 | |
| 12013 | 11973 | region = &info->region_list[count]; |
| r2821 | r2822 | |
| 12043 | 12003 | cpu_info->address_chars_needed, region->address + region->length - 1, |
| 12044 | 12004 | description); |
| 12045 | 12005 | |
| 12006 | if(is_search_region_in_range(cpu, region->length) == 0) |
| 12007 | { |
| 12008 | region->flags &= ~kRegionFlag_Enabled; |
| 12009 | region->flags |= kRegionFlag_HasError; |
| 12010 | } |
| 12011 | else |
| 12012 | region->flags = status; |
| 12013 | |
| 12046 | 12014 | count++; |
| 12047 | 12015 | } |
| 12048 | 12016 | |
| 12049 | 12017 | info->region_list_length = count; |
| 12050 | 12018 | |
| 12051 | 12019 | if(info->region_list_length) |
| 12052 | | { |
| 12053 | | messageType = kCheatMessage_ReloadUserRegion; |
| 12054 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12055 | | } |
| 12020 | SET_MESSAGE(kCheatMessage_ReloadUserRegion); |
| 12056 | 12021 | |
| 12057 | | mame_fclose(theFile); |
| 12022 | mame_fclose(the_file); |
| 12058 | 12023 | } |
| 12059 | 12024 | |
| 12060 | | /*--------------------------------------------------------- |
| 12061 | | LoadCheatDatabase - get the database name then load it |
| 12062 | | ---------------------------------------------------------*/ |
| 12025 | /*----------------------------------------------------------- |
| 12026 | load_cheat_database - get the database name then load it |
| 12027 | -----------------------------------------------------------*/ |
| 12063 | 12028 | |
| 12064 | | static void LoadCheatDatabase(running_machine *machine, UINT8 flags) |
| 12029 | static void load_cheat_database(running_machine *machine, UINT8 flags) |
| 12065 | 12030 | { |
| 12066 | 12031 | UINT8 first = 1; |
| 12067 | | |
| 12068 | | char buf[256]; |
| 12032 | char buf[256] = { 0 }; |
| 12069 | 12033 | char data; |
| 12070 | | const char * inTraverse; |
| 12071 | | char * outTraverse; |
| 12072 | | char * mainTraverse; |
| 12034 | const char *in_traverse; |
| 12035 | char *out_traverse; |
| 12036 | char *main_traverse; |
| 12073 | 12037 | |
| 12074 | | cheatfile = options_get_string(mame_options(), OPTION_CHEAT_FILE); |
| 12038 | cheat_file = options_get_string(mame_options(), OPTION_CHEAT_FILE); |
| 12075 | 12039 | |
| 12076 | | if (!cheatfile[0]) |
| 12077 | | cheatfile = "cheat.dat"; |
| 12040 | if(cheat_file[0] == 0) |
| 12041 | cheat_file = "cheat.dat"; |
| 12078 | 12042 | |
| 12079 | | inTraverse = cheatfile; |
| 12080 | | outTraverse = buf; |
| 12081 | | mainTraverse = mainDatabaseName; |
| 12043 | in_traverse = cheat_file; |
| 12044 | out_traverse = buf; |
| 12045 | main_traverse = main_database_name; |
| 12082 | 12046 | |
| 12083 | | buf[0] = 0; |
| 12084 | | |
| 12085 | 12047 | do |
| 12086 | 12048 | { |
| 12087 | | data = *inTraverse; |
| 12049 | data = *in_traverse; |
| 12088 | 12050 | |
| 12089 | 12051 | /* check separator or end */ |
| 12090 | | if(data == ';' || !data) |
| 12052 | if(data == ';' || data == 0) |
| 12091 | 12053 | { |
| 12092 | | *outTraverse++ = 0; |
| 12054 | *out_traverse++ = 0; |
| 12093 | 12055 | |
| 12094 | 12056 | if(first) |
| 12095 | | *mainTraverse++ = 0; |
| 12057 | *main_traverse++ = 0; |
| 12096 | 12058 | |
| 12097 | 12059 | if(buf[0]) |
| 12098 | 12060 | { |
| 12099 | 12061 | /* load database based on the name we gotten */ |
| 12100 | 12062 | if(flags & kLoadFlag_CheatOption) |
| 12101 | | LoadCheatOption(buf); |
| 12063 | load_cheat_option(buf); |
| 12102 | 12064 | if(flags & kLoadFlag_CheatCode) |
| 12103 | | LoadCheatCode(machine, buf); |
| 12065 | load_cheat_code(machine, buf); |
| 12104 | 12066 | if(flags & kLoadFlag_UserRegion) |
| 12105 | | LoadUserDefinedSearchRegion(machine, buf); |
| 12067 | load_user_defined_search_region(machine, buf); |
| 12106 | 12068 | |
| 12107 | | outTraverse = buf; |
| 12108 | | buf[0] = 0; |
| 12109 | | first = 0; |
| 12069 | out_traverse = buf; |
| 12070 | buf[0] = 0; |
| 12071 | first = 0; |
| 12110 | 12072 | break; |
| 12111 | 12073 | } |
| 12112 | 12074 | } |
| 12113 | 12075 | else |
| 12114 | 12076 | { |
| 12115 | | *outTraverse++ = data; |
| 12077 | *out_traverse++ = data; |
| 12116 | 12078 | |
| 12117 | 12079 | if(first) |
| 12118 | | *mainTraverse++ = data; |
| 12080 | *main_traverse++ = data; |
| 12119 | 12081 | } |
| 12120 | 12082 | |
| 12121 | | inTraverse++; |
| 12083 | in_traverse++; |
| 12122 | 12084 | } |
| 12123 | 12085 | while(data); |
| 12124 | 12086 | |
| 12125 | | UpdateAllCheatInfo(); |
| 12087 | update_all_cheat_info(); |
| 12126 | 12088 | } |
| 12127 | 12089 | |
| 12128 | | /*--------------------------------------------------------------------------------------- |
| 12129 | | DisposeCheatDatabase - deactivate all cheats when reload a code or exit cheat system |
| 12130 | | ---------------------------------------------------------------------------------------*/ |
| 12090 | /*--------------------------------------------------------------------------- |
| 12091 | reload_cheat_database - reload cheat database directly on the cheat menu |
| 12092 | ---------------------------------------------------------------------------*/ |
| 12131 | 12093 | |
| 12132 | | static void DisposeCheatDatabase(void) |
| 12094 | static void reload_cheat_database(running_machine *machine) |
| 12133 | 12095 | { |
| 12096 | dispose_cheat_database(); |
| 12097 | load_cheat_database(machine, kLoadFlag_CheatCode); |
| 12098 | |
| 12099 | SET_MESSAGE(found_database ? kCheatMessage_ReloadCheatCode : kCheatMessage_FailedToLoadDatabase); |
| 12100 | } |
| 12101 | |
| 12102 | /*------------------------------------------------- |
| 12103 | dispose_cheat_database - free all cheat entries |
| 12104 | -------------------------------------------------*/ |
| 12105 | |
| 12106 | static void dispose_cheat_database(void) |
| 12107 | { |
| 12134 | 12108 | int i; |
| 12135 | 12109 | |
| 12136 | 12110 | /* first, turn all cheats "OFF" */ |
| 12137 | | for(i = 0; i < cheatListLength; i++) |
| 12138 | | TempDeactivateCheat(&cheatList[i]); |
| 12111 | for(i = 0; i < cheat_list_length; i++) |
| 12112 | TempDeactivateCheat(&cheat_list[i]); |
| 12139 | 12113 | |
| 12140 | 12114 | /* next, free memory for all cheat entries */ |
| 12141 | | if(cheatList) |
| 12115 | if(cheat_list) |
| 12142 | 12116 | { |
| 12143 | | for(i = 0; i < cheatListLength; i++) |
| 12144 | | DisposeCheat(&cheatList[i]); |
| 12117 | for(i = 0; i < cheat_list_length; i++) |
| 12118 | dispose_cheat(&cheat_list[i]); |
| 12145 | 12119 | |
| 12146 | | free(cheatList); |
| 12120 | free(cheat_list); |
| 12147 | 12121 | |
| 12148 | | cheatList = NULL; |
| 12149 | | cheatListLength = 0; |
| 12122 | cheat_list = NULL; |
| 12123 | cheat_list_length = 0; |
| 12150 | 12124 | } |
| 12151 | 12125 | } |
| 12152 | 12126 | |
| 12153 | | /*------------------------------------------------------------------------- |
| 12154 | | ReloadCheatDatabase - reload cheat database directly on the cheat menu |
| 12155 | | -------------------------------------------------------------------------*/ |
| 12156 | | |
| 12157 | | static void ReloadCheatDatabase(running_machine *machine) |
| 12158 | | { |
| 12159 | | DisposeCheatDatabase(); |
| 12160 | | LoadCheatDatabase(machine, kLoadFlag_CheatCode); |
| 12161 | | |
| 12162 | | if(foundCheatDatabase) |
| 12163 | | messageType = kCheatMessage_ReloadCheatCode; |
| 12164 | | else |
| 12165 | | messageType = kCheatMessage_FailedToLoadDatabase; |
| 12166 | | |
| 12167 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12168 | | } |
| 12169 | | |
| 12170 | 12127 | /*------------------------------------------------------ |
| 12171 | 12128 | SaveCheatCode - save a cheat code into the database |
| 12172 | 12129 | ------------------------------------------------------*/ |
| 12173 | 12130 | |
| 12174 | | static void SaveCheatCode(running_machine *machine, CheatEntry * entry) |
| 12131 | static void SaveCheatCode(running_machine *machine, cheat_entry *entry) |
| 12175 | 12132 | { |
| 12176 | | #ifdef MESS |
| 12133 | #if 0 |
| 12177 | 12134 | INT8 i; |
| 12178 | 12135 | INT8 error = 0; |
| 12179 | 12136 | char buf[4096]; |
| r2821 | r2822 | |
| 12181 | 12138 | mame_file * theFile; |
| 12182 | 12139 | file_error filerr; |
| 12183 | 12140 | |
| 12184 | | if(!entry || !entry->actionList || ((entry->flags & kCheatFlag_Select) && entry->actionListLength == 1)) |
| 12141 | if(entry == NULL || entry->action_list == NULL || ((entry->flags & kCheatFlag_Select) && entry->action_list_length == 1)) |
| 12185 | 12142 | error = 1; |
| 12186 | 12143 | |
| 12187 | 12144 | /* open the database */ |
| 12188 | 12145 | if(!error) |
| 12189 | 12146 | { |
| 12190 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE, &theFile); |
| 12147 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE, &theFile); |
| 12191 | 12148 | |
| 12192 | 12149 | if(!theFile) |
| 12193 | 12150 | error = 1; |
| 12194 | 12151 | else if(filerr != FILERR_NONE) |
| 12195 | 12152 | { |
| 12196 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12153 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12197 | 12154 | |
| 12198 | 12155 | if(filerr != FILERR_NONE) |
| 12199 | 12156 | error = 1; |
| r2821 | r2822 | |
| 12202 | 12159 | |
| 12203 | 12160 | if(error) |
| 12204 | 12161 | { |
| 12205 | | messageType = kCheatMessage_FailedToSave; |
| 12206 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12162 | SET_MESSAGE(kCheatMessage_FailedToSave); |
| 12207 | 12163 | return; |
| 12208 | 12164 | } |
| 12209 | 12165 | |
| 12210 | 12166 | mame_fseek(theFile, 0, SEEK_END); |
| 12211 | 12167 | |
| 12212 | 12168 | /* write the code to the database */ |
| 12213 | | for(i = 0; i < entry->actionListLength; i++) |
| 12169 | for(i = 0; i < entry->action_list_length; i++) |
| 12214 | 12170 | { |
| 12215 | 12171 | UINT8 addressLength = 8; |
| 12216 | 12172 | char * name; |
| 12217 | 12173 | char * bufTraverse = buf; |
| 12218 | 12174 | |
| 12219 | | CheatAction * action = &entry->actionList[i]; |
| 12175 | cheat_action *action = &entry->action_list[i]; |
| 12220 | 12176 | |
| 12221 | 12177 | /* get name */ |
| 12222 | 12178 | if(!i) |
| 12223 | 12179 | name = entry->name; |
| 12224 | 12180 | else |
| 12225 | | name = action->optionalName; |
| 12181 | name = action->optional_name; |
| 12226 | 12182 | |
| 12227 | 12183 | /* get address length of CPU/Region */ |
| 12228 | 12184 | addressLength = get_address_length(EXTRACT_FIELD(action->type, CPURegion)); |
| r2821 | r2822 | |
| 12234 | 12190 | thisGameCRC, |
| 12235 | 12191 | action->type, |
| 12236 | 12192 | addressLength, |
| 12237 | | action->originalAddress, |
| 12238 | | action->originalDataField, |
| 12239 | | action->extendData); |
| 12193 | action->original_address, |
| 12194 | action->original_data, |
| 12195 | action->extend_data); |
| 12240 | 12196 | #else |
| 12241 | 12197 | bufTraverse += sprintf(bufTraverse, ">%s:%.8X:%.*X:%.8X:%.8X", |
| 12242 | 12198 | machine->gamedrv->name, |
| 12243 | 12199 | action->type, |
| 12244 | 12200 | addressLength, |
| 12245 | | action->originalAddress, |
| 12246 | | action->originalDataField, |
| 12247 | | action->extendData); |
| 12201 | action->original_address, |
| 12202 | action->original_data, |
| 12203 | action->extend_data); |
| 12248 | 12204 | #endif |
| 12249 | 12205 | /* set name */ |
| 12250 | 12206 | if(name) |
| r2821 | r2822 | |
| 12277 | 12233 | /* clear dirty flag as "this entry is already saved" */ |
| 12278 | 12234 | entry->flags &= ~kCheatFlag_Dirty; |
| 12279 | 12235 | |
| 12280 | | messageType = kCheatMessage_SucceededToSave; |
| 12281 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12282 | | #endif |
| 12236 | SET_MESSAGE(kCheatMessage_SucceededToSave); |
| 12237 | #else |
| 12283 | 12238 | SaveDescription(machine); |
| 12239 | #endif |
| 12284 | 12240 | } |
| 12285 | 12241 | |
| 12286 | 12242 | /*----------------------------------------------------------------- |
| 12287 | 12243 | SaveActivationKey - save activation key code into the database |
| 12288 | 12244 | -----------------------------------------------------------------*/ |
| 12289 | 12245 | |
| 12290 | | static void SaveActivationKey(running_machine *machine, CheatEntry * entry, int entryIndex) |
| 12246 | static void SaveActivationKey(running_machine *machine, cheat_entry *entry, int entryIndex) |
| 12291 | 12247 | { |
| 12248 | #if 0 |
| 12292 | 12249 | INT8 i; |
| 12293 | 12250 | INT8 error = 0; |
| 12294 | 12251 | char buf[4096]; |
| 12295 | 12252 | |
| 12296 | | mame_file * theFile = NULL; |
| 12253 | mame_file * theFile; |
| 12297 | 12254 | file_error filerr; |
| 12298 | 12255 | |
| 12299 | 12256 | if(!(entry->flags & kCheatFlag_HasActivationKey1) && !(entry->flags & kCheatFlag_HasActivationKey2)) |
| 12300 | 12257 | error = 1; |
| 12301 | 12258 | |
| 12302 | | if(!error && (!entry || !entry->actionList || ((entry->flags & kCheatFlag_Select) && entry->actionListLength == 1))) |
| 12259 | if(error == 0 && (entry == NULL || entry->action_list == NULL || ((entry->flags & kCheatFlag_Select) && entry->action_list_length == 1))) |
| 12303 | 12260 | error = 2; |
| 12304 | 12261 | |
| 12305 | 12262 | /* open the database */ |
| 12306 | 12263 | if(!error) |
| 12307 | 12264 | { |
| 12308 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE, &theFile); |
| 12265 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE, &theFile); |
| 12309 | 12266 | |
| 12310 | 12267 | if(!theFile) |
| 12311 | 12268 | error = 2; |
| 12312 | 12269 | else if(filerr != FILERR_NONE) |
| 12313 | 12270 | { |
| 12314 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12271 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12315 | 12272 | |
| 12316 | 12273 | if(filerr != FILERR_NONE) |
| 12317 | 12274 | error = 2; |
| r2821 | r2822 | |
| 12321 | 12278 | switch(error) |
| 12322 | 12279 | { |
| 12323 | 12280 | case 1: |
| 12324 | | messageType = kCheatMessage_NoActivationKey; |
| 12325 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12281 | SET_MESSAGE(kCheatMessage_NoActivationKey); |
| 12326 | 12282 | return; |
| 12327 | 12283 | |
| 12328 | 12284 | case 2: |
| 12329 | | messageType = kCheatMessage_FailedToSave; |
| 12330 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12285 | SET_MESSAGE(kCheatMessage_FailedToSave); |
| 12331 | 12286 | return; |
| 12332 | 12287 | } |
| 12333 | 12288 | |
| r2821 | r2822 | |
| 12337 | 12292 | for(i = 0; i < 2; i++) |
| 12338 | 12293 | { |
| 12339 | 12294 | int addressLength = 8; |
| 12340 | | int activationKey = !i ? entry->activationKey1 : entry->activationKey2; |
| 12295 | int activationKey = !i ? entry->activation_key1 : entry->activation_key2; |
| 12341 | 12296 | int type = 0; |
| 12342 | 12297 | char * bufTraverse = buf; |
| 12343 | 12298 | |
| 12344 | | CheatAction * action = &entry->actionList[0]; |
| 12345 | | astring * name = input_code_name(astring_alloc(), activationKey); |
| 12299 | cheat_action *action = &entry->action_list[0]; |
| 12300 | astring *name = input_code_name(astring_alloc(), activationKey); |
| 12346 | 12301 | |
| 12347 | | /* set the flag in type field */ |
| 12348 | | SET_FIELD(type, CPURegion, CUSTOM_CODE); |
| 12349 | | |
| 12350 | 12302 | if(activationKey) |
| 12351 | | SET_FIELD(type, CodeType, kCustomCode_ActivationKey1); |
| 12303 | SET_FIELD(type, CodeType, CUSTOM_CODE_ACTIVATION_KEY_1); |
| 12352 | 12304 | else |
| 12353 | | SET_FIELD(type, CodeType, kCustomCode_ActivationKey2); |
| 12305 | SET_FIELD(type, CodeType, CUSTOM_CODE_ACTIVATION_KEY_2); |
| 12354 | 12306 | |
| 12355 | 12307 | /* get address length of CPU/Region */ |
| 12356 | | addressLength = get_address_length(EXTRACT_FIELD(action->type, CPURegion)); |
| 12308 | addressLength = get_address_length(action->region); |
| 12357 | 12309 | |
| 12358 | 12310 | /* if not find 1st activation key at saving 1st key, try to save 2nd key */ |
| 12359 | 12311 | if(!i && !(entry->flags & kCheatFlag_HasActivationKey1)) |
| r2821 | r2822 | |
| 12417 | 12369 | /* close the database */ |
| 12418 | 12370 | mame_fclose(theFile); |
| 12419 | 12371 | |
| 12420 | | messageType = kCheatMessage_ActivationKeySaved; |
| 12421 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12372 | SET_MESSAGE(kCheatMessage_ActivationKeySaved); |
| 12373 | #endif |
| 12422 | 12374 | } |
| 12423 | 12375 | |
| 12424 | 12376 | /*----------------------------------------------------------- |
| 12425 | 12377 | SavePreEnable - save a pre-enable code into the database |
| 12426 | 12378 | -----------------------------------------------------------*/ |
| 12427 | 12379 | |
| 12428 | | static void SavePreEnable(running_machine *machine, CheatEntry * entry, int entryIndex) |
| 12380 | static void SavePreEnable(running_machine *machine, cheat_entry *entry, int entryIndex) |
| 12429 | 12381 | { |
| 12382 | #if 0 |
| 12430 | 12383 | int type = 0; |
| 12431 | 12384 | INT8 error = 0; |
| 12432 | 12385 | INT8 addressLength = 8; |
| 12433 | 12386 | char buf[4096]; |
| 12434 | 12387 | char * bufTraverse = buf; |
| 12435 | 12388 | |
| 12436 | | CheatAction * action = &entry->actionList[0]; |
| 12437 | | mame_file * theFile = NULL; |
| 12389 | cheat_action *action = &entry->action_list[0]; |
| 12390 | mame_file *theFile; |
| 12438 | 12391 | file_error filerr; |
| 12439 | 12392 | |
| 12440 | | if(!entry || !entry->actionList || ((entry->flags & kCheatFlag_Select) && entry->actionListLength == 1)) |
| 12393 | if(entry == NULL || entry->action_list == NULL || ((entry->flags & kCheatFlag_Select) && entry->action_list_length == 1)) |
| 12441 | 12394 | error = 1; |
| 12442 | 12395 | |
| 12443 | 12396 | /* open the database */ |
| 12444 | 12397 | if(!error) |
| 12445 | 12398 | { |
| 12446 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE, &theFile); |
| 12399 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE, &theFile); |
| 12447 | 12400 | |
| 12448 | 12401 | if(!theFile) |
| 12449 | 12402 | error = 1; |
| 12450 | 12403 | else if(filerr != FILERR_NONE) |
| 12451 | 12404 | { |
| 12452 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12405 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12453 | 12406 | |
| 12454 | 12407 | if(filerr != FILERR_NONE) |
| 12455 | 12408 | error = 1; |
| r2821 | r2822 | |
| 12458 | 12411 | |
| 12459 | 12412 | if(error) |
| 12460 | 12413 | { |
| 12461 | | messageType = kCheatMessage_FailedToSave; |
| 12462 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12414 | SET_MESSAGE(kCheatMessage_FailedToSave); |
| 12463 | 12415 | return; |
| 12464 | 12416 | } |
| 12465 | 12417 | else |
| 12466 | 12418 | { |
| 12467 | | SET_FIELD(type, CPURegion, CUSTOM_CODE); |
| 12468 | | SET_FIELD(type, CodeType, kCustomCode_PreEnable); |
| 12419 | SET_FIELD(type, CodeType, CUSTOM_CODE_PRE_ENABLE); |
| 12469 | 12420 | } |
| 12470 | 12421 | |
| 12471 | 12422 | mame_fseek(theFile, 0, SEEK_END); |
| r2821 | r2822 | |
| 12498 | 12449 | |
| 12499 | 12450 | /* set label name */ |
| 12500 | 12451 | if(entry->selection) |
| 12501 | | bufTraverse += sprintf(bufTraverse, " Label - %s", entry->actionList[entry->labelIndex[entry->selection]].optionalName); |
| 12452 | bufTraverse += sprintf(bufTraverse, " Label - %s", entry->action_list[entry->label_index[entry->selection]].optional_name); |
| 12502 | 12453 | |
| 12503 | 12454 | bufTraverse += sprintf(bufTraverse, "\n"); |
| 12504 | 12455 | |
| r2821 | r2822 | |
| 12508 | 12459 | /* close the database */ |
| 12509 | 12460 | mame_fclose(theFile); |
| 12510 | 12461 | |
| 12511 | | messageType = kCheatMessage_PreEnableSaved; |
| 12512 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12462 | SET_MESSAGE(kCheatMessage_PreEnableSaved); |
| 12463 | #endif |
| 12513 | 12464 | } |
| 12514 | 12465 | |
| 12515 | 12466 | /*-------------------------------------------------------------- |
| 12516 | | SaveCheatOptions - save cheat option code into the database |
| 12467 | Savecheat_options - save cheat option code into the database |
| 12517 | 12468 | --------------------------------------------------------------*/ |
| 12518 | 12469 | |
| 12519 | | static void SaveCheatOptions(void) |
| 12470 | static void Savecheat_options(void) |
| 12520 | 12471 | { |
| 12521 | 12472 | UINT8 error = 0; |
| 12522 | 12473 | char buf[32]; |
| r2821 | r2822 | |
| 12525 | 12476 | file_error filerr; |
| 12526 | 12477 | |
| 12527 | 12478 | /* open the database */ |
| 12528 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE, &theFile); |
| 12479 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE, &theFile); |
| 12529 | 12480 | |
| 12530 | 12481 | if(!theFile) |
| 12531 | 12482 | error = 1; |
| 12532 | 12483 | else if(filerr != FILERR_NONE) |
| 12533 | 12484 | { |
| 12534 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12485 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12535 | 12486 | |
| 12536 | 12487 | if(filerr != FILERR_NONE) |
| 12537 | 12488 | error = 1; |
| r2821 | r2822 | |
| 12539 | 12490 | |
| 12540 | 12491 | if(error) |
| 12541 | 12492 | { |
| 12542 | | messageType = kCheatMessage_FailedToSave; |
| 12543 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12493 | SET_MESSAGE(kCheatMessage_FailedToSave); |
| 12544 | 12494 | return; |
| 12545 | 12495 | } |
| 12546 | 12496 | |
| 12547 | 12497 | mame_fseek(theFile, 0, SEEK_END); |
| 12548 | 12498 | |
| 12549 | | sprintf(buf, ":_command:%.8X\n", cheatOptions); |
| 12499 | sprintf(buf, ":_command:%.8X\n", cheat_options); |
| 12550 | 12500 | |
| 12551 | 12501 | /* write the command code */ |
| 12552 | 12502 | mame_fwrite(theFile, buf, (UINT32)strlen(buf)); |
| r2821 | r2822 | |
| 12554 | 12504 | /* close the database */ |
| 12555 | 12505 | mame_fclose(theFile); |
| 12556 | 12506 | |
| 12557 | | messageType = kCheatMessage_SucceededToSave; |
| 12558 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12507 | SET_MESSAGE(kCheatMessage_SucceededToSave); |
| 12559 | 12508 | } |
| 12560 | 12509 | |
| 12561 | 12510 | /*------------------ |
| r2821 | r2822 | |
| 12570 | 12519 | mame_file * theFile; |
| 12571 | 12520 | file_error filerr; |
| 12572 | 12521 | |
| 12573 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE, &theFile); |
| 12522 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE, &theFile); |
| 12574 | 12523 | |
| 12575 | 12524 | if(!theFile) |
| 12576 | 12525 | error = 1; |
| 12577 | 12526 | else if(filerr != FILERR_NONE) |
| 12578 | 12527 | { |
| 12579 | | filerr = mame_fopen(SEARCHPATH_CHEAT, mainDatabaseName, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12528 | filerr = mame_fopen(SEARCHPATH_CHEAT, main_database_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &theFile); |
| 12580 | 12529 | |
| 12581 | 12530 | if(filerr != FILERR_NONE) |
| 12582 | 12531 | error = 1; |
| r2821 | r2822 | |
| 12584 | 12533 | |
| 12585 | 12534 | if(error) |
| 12586 | 12535 | { |
| 12587 | | messageType = kCheatMessage_FailedToSave; |
| 12588 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12536 | SET_MESSAGE(kCheatMessage_FailedToSave); |
| 12589 | 12537 | return; |
| 12590 | 12538 | } |
| 12591 | 12539 | |
| 12592 | 12540 | mame_fseek(theFile, 0, SEEK_END); |
| 12593 | | sprintf(buf, "> [ %s ]\n", machine->gamedrv->description); |
| 12541 | sprintf(buf, "; [ %s ]\n", machine->gamedrv->description); |
| 12594 | 12542 | |
| 12595 | 12543 | /* write the command code */ |
| 12596 | 12544 | mame_fwrite(theFile, buf, (UINT32)strlen(buf)); |
| r2821 | r2822 | |
| 12598 | 12546 | /* close the database */ |
| 12599 | 12547 | mame_fclose(theFile); |
| 12600 | 12548 | |
| 12601 | | messageType = kCheatMessage_SucceededToSave; |
| 12602 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12549 | SET_MESSAGE(kCheatMessage_SucceededToSave); |
| 12603 | 12550 | } |
| 12604 | 12551 | |
| 12605 | 12552 | /*-------------------------------------------------------------------------- |
| r2821 | r2822 | |
| 12610 | 12557 | { |
| 12611 | 12558 | int i; |
| 12612 | 12559 | |
| 12613 | | for(i = 0; i < cheatListLength; i++) |
| 12560 | for(i = 0; i < cheat_list_length; i++) |
| 12614 | 12561 | { |
| 12615 | | CheatEntry * entry = &cheatList[i]; |
| 12562 | cheat_entry *entry = &cheat_list[i]; |
| 12616 | 12563 | |
| 12617 | 12564 | /* if the entry is not edited/added newly or has not been already saved, save it */ |
| 12618 | 12565 | if(entry->flags & kCheatFlag_Dirty) |
| r2821 | r2822 | |
| 12628 | 12575 | { |
| 12629 | 12576 | if((region->target_type == kRegionType_CPU) || (region->target_type == kRegionType_Memory)) |
| 12630 | 12577 | { |
| 12631 | | CheatEntry * entry = GetNewCheat(); |
| 12632 | | CheatAction * action = &entry->actionList[0]; |
| 12633 | | char tempString[1024]; |
| 12634 | | int tempStringLength; |
| 12635 | | UINT32 data = read_search_operand(kSearchOperand_First, search, region, address); |
| 12578 | cheat_entry *entry = get_new_cheat(); |
| 12579 | cheat_action *action = &entry->action_list[0]; |
| 12580 | char tempString[1024]; |
| 12581 | int tempStringLength; |
| 12582 | UINT32 data = read_search_operand(kSearchOperand_First, search, region, address); |
| 12636 | 12583 | |
| 12637 | 12584 | tempStringLength = sprintf(tempString, "%.8X (%d) = %.*X", address, region->target_idx, kSearchByteDigitsTable[search->bytes], data); |
| 12638 | 12585 | |
| 12639 | 12586 | entry->name = realloc(entry->name, tempStringLength + 1); |
| 12640 | 12587 | memcpy(entry->name, tempString, tempStringLength + 1); |
| 12641 | 12588 | |
| 12642 | | SET_FIELD(action->type, CPURegion, region->target_idx); |
| 12589 | action->region = region->target_idx; |
| 12590 | action->address = address; |
| 12591 | action->data = data; |
| 12592 | action->original_data = data; |
| 12593 | action->extend_data = 0xFFFFFFFF; |
| 12594 | action->last_value = NULL; |
| 12595 | |
| 12643 | 12596 | SET_FIELD(action->type, AddressSize, kSearchByteIncrementTable[search->bytes] - 1); |
| 12644 | | action->address = address; |
| 12645 | | action->data = action->originalDataField = data; |
| 12646 | | action->extendData = 0xFFFFFFFF; |
| 12647 | | action->lastValue = NULL; |
| 12648 | 12597 | |
| 12649 | | UpdateCheatInfo(entry, 0); |
| 12598 | update_cheat_info(entry, 0); |
| 12650 | 12599 | } |
| 12651 | 12600 | } |
| 12652 | 12601 | |
| r2821 | r2822 | |
| 12688 | 12637 | { |
| 12689 | 12638 | if(region->target_type == kRegionType_CPU || region->target_type == kRegionType_Memory) |
| 12690 | 12639 | { |
| 12691 | | WatchInfo * info = GetUnusedWatch(); |
| 12640 | watch_info *info = get_unused_watch(); |
| 12692 | 12641 | |
| 12693 | 12642 | info->address = address; |
| 12694 | 12643 | info->cpu = region->target_idx; |
| 12695 | | info->numElements = 1; |
| 12696 | | info->elementBytes = kWatchSizeConversionTable[search->bytes]; |
| 12697 | | info->labelType = kWatchLabel_None; |
| 12698 | | info->displayType = kWatchDisplayType_Hex; |
| 12644 | info->num_elements = 1; |
| 12645 | info->element_bytes = kWatchSizeConversionTable[search->bytes]; |
| 12646 | info->label_type = kWatchLabel_None; |
| 12647 | info->display_type = kWatchDisplayType_Hex; |
| 12699 | 12648 | info->skip = 0; |
| 12700 | | info->elementsPerLine = 0; |
| 12701 | | info->addValue = 0; |
| 12702 | | info->linkedCheat = NULL; |
| 12649 | info->elements_per_line = 0; |
| 12650 | info->add_value = 0; |
| 12651 | info->linked_cheat = NULL; |
| 12703 | 12652 | info->label[0] = 0; |
| 12704 | 12653 | |
| 12705 | | messageType = kCheatMessage_SucceededToAdd; |
| 12706 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12654 | SET_MESSAGE(kCheatMessage_SucceededToAdd); |
| 12707 | 12655 | } |
| 12708 | 12656 | else |
| 12709 | | { |
| 12710 | | messageType = kCheatMessage_FailedToAdd; |
| 12711 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 12712 | | } |
| 12657 | SET_MESSAGE(kCheatMessage_FailedToAdd); |
| 12713 | 12658 | } |
| 12714 | 12659 | |
| 12715 | 12660 | /*--------------------- |
| r2821 | r2822 | |
| 13437 | 13382 | ReadData |
| 13438 | 13383 | -----------*/ |
| 13439 | 13384 | |
| 13440 | | static UINT32 ReadData(CheatAction * action) |
| 13385 | static UINT32 ReadData(cheat_action *action) |
| 13441 | 13386 | { |
| 13442 | 13387 | UINT8 addressRead = EXTRACT_FIELD(action->type, AddressRead); |
| 13443 | 13388 | UINT8 bytes = EXTRACT_FIELD(action->type, AddressSize) + 1; |
| r2821 | r2822 | |
| 13450 | 13395 | if(addressRead == kReadFrom_Address) address = action->address; |
| 13451 | 13396 | else if(addressRead == kReadFrom_Index) address = cheatVariable[action->address]; |
| 13452 | 13397 | |
| 13453 | | if(!TEST_FIELD(action->region, RegionFlag)) |
| 13398 | if(action->region < REGION_INVALID) |
| 13454 | 13399 | { |
| 13455 | 13400 | /* read a data from CPU */ |
| 13456 | 13401 | UINT8 cpu = EXTRACT_FIELD(action->region, CPUIndex); |
| r2821 | r2822 | |
| 13464 | 13409 | |
| 13465 | 13410 | cpu_region_info *info = get_cpu_info(cpu); |
| 13466 | 13411 | |
| 13467 | | indexAddress = DoCPURead(cpu, address, EXTRACT_FIELD(action->type, IndexSize) + 1, cpu_needs_swap(cpu)); |
| 13412 | indexAddress = DoCPURead(cpu, address, EXTRACT_FIELD(action->type, CodeParameterLower) + 1, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13468 | 13413 | |
| 13469 | 13414 | if(info && info->address_shift) |
| 13470 | 13415 | indexAddress = DoShift(indexAddress, info->address_shift); |
| 13471 | 13416 | |
| 13472 | 13417 | if(indexAddress) |
| 13473 | 13418 | { |
| 13474 | | indexAddress += action->extendData; |
| 13475 | | return DoCPURead(cpu, indexAddress, bytes, cpu_needs_swap(cpu)); |
| 13419 | indexAddress += action->extend_data; |
| 13420 | return DoCPURead(cpu, indexAddress, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13476 | 13421 | } |
| 13477 | 13422 | } |
| 13478 | 13423 | else if(action->flags & kActionFlag_PDWWrite) |
| r2821 | r2822 | |
| 13480 | 13425 | if(action->flags & kActionFlag_IsFirst) |
| 13481 | 13426 | { |
| 13482 | 13427 | address += bytes; |
| 13483 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13428 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13484 | 13429 | action->flags &= ~kActionFlag_IsFirst; |
| 13485 | 13430 | } |
| 13486 | 13431 | else |
| 13487 | 13432 | action->flags |= kActionFlag_IsFirst; |
| 13488 | 13433 | |
| 13489 | | return DoCPURead(cpu, address, bytes, cpu_needs_swap(cpu)); |
| 13434 | return DoCPURead(cpu, address, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13490 | 13435 | } |
| 13491 | 13436 | else |
| 13492 | 13437 | { |
| 13493 | | return DoCPURead(cpu, address, bytes, cpu_needs_swap(cpu)); |
| 13438 | return DoCPURead(cpu, address, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13494 | 13439 | } |
| 13495 | 13440 | break; |
| 13496 | 13441 | |
| r2821 | r2822 | |
| 13501 | 13446 | { |
| 13502 | 13447 | UINT8 * buf; |
| 13503 | 13448 | |
| 13504 | | action->cachedPointer = GetMemoryRegionBasePointer(cpu, EXTRACT_FIELD(action->type, AddressSpace), address); |
| 13505 | | buf = (UINT8 *) action->cachedPointer; |
| 13449 | action->cached_pointer = GetMemoryRegionBasePointer(cpu, EXTRACT_FIELD(action->type, AddressSpace), address); |
| 13450 | buf = (UINT8 *) action->cached_pointer; |
| 13506 | 13451 | |
| 13507 | 13452 | if(buf) |
| 13508 | 13453 | { |
| r2821 | r2822 | |
| 13511 | 13456 | if(action->flags & kActionFlag_IsFirst) |
| 13512 | 13457 | { |
| 13513 | 13458 | address += bytes; |
| 13514 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13459 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13515 | 13460 | action->flags &= ~kActionFlag_IsFirst; |
| 13516 | 13461 | } |
| 13517 | 13462 | else |
| 13518 | 13463 | action->flags |= kActionFlag_IsFirst; |
| 13519 | 13464 | } |
| 13520 | 13465 | |
| 13521 | | return DoMemoryRead(buf, address, bytes, cpu_needs_swap(cpu), get_cpu_info(cpu)); |
| 13466 | return DoMemoryRead(buf, address, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness), get_cpu_info(cpu)); |
| 13522 | 13467 | } |
| 13523 | 13468 | } |
| 13524 | 13469 | break; |
| 13525 | 13470 | |
| 13526 | 13471 | case kAddressSpace_MappedMemory: |
| 13527 | 13472 | { |
| 13528 | | int relativeAddress; |
| 13529 | | UINT8 ** buf; |
| 13473 | int relativeAddress; |
| 13474 | UINT8 **buf; |
| 13530 | 13475 | |
| 13531 | | action->cachedPointer = LookupHandlerMemory(cpu, address, &action->cachedOffset); |
| 13532 | | buf = action->cachedPointer; |
| 13533 | | relativeAddress = action->cachedOffset; |
| 13476 | action->cached_pointer = LookupHandlerMemory(cpu, address, &action->cached_offset); |
| 13477 | buf = action->cached_pointer; |
| 13478 | relativeAddress = action->cached_offset; |
| 13534 | 13479 | |
| 13535 | 13480 | if(buf && *buf) |
| 13536 | 13481 | { |
| r2821 | r2822 | |
| 13539 | 13484 | if(action->flags & kActionFlag_IsFirst) |
| 13540 | 13485 | { |
| 13541 | 13486 | relativeAddress += bytes; |
| 13542 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13487 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13543 | 13488 | action->flags &= ~kActionFlag_IsFirst; |
| 13544 | 13489 | } |
| 13545 | 13490 | else |
| 13546 | 13491 | action->flags |= kActionFlag_IsFirst; |
| 13547 | 13492 | } |
| 13548 | 13493 | |
| 13549 | | return DoMemoryRead(*buf, relativeAddress, bytes, cpu_needs_swap(cpu), get_cpu_info(cpu)); |
| 13494 | return DoMemoryRead(*buf, relativeAddress, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness), get_cpu_info(cpu)); |
| 13550 | 13495 | } |
| 13551 | 13496 | } |
| 13552 | 13497 | break; |
| r2821 | r2822 | |
| 13554 | 13499 | case kAddressSpace_EEPROM: |
| 13555 | 13500 | { |
| 13556 | 13501 | int length; |
| 13557 | | UINT8 * buf; |
| 13502 | UINT8 *buf; |
| 13558 | 13503 | |
| 13559 | 13504 | buf = eeprom_get_data_pointer(&length); |
| 13560 | 13505 | |
| 13561 | | if(IsAddressInRange(action, length)) |
| 13506 | if(is_address_in_range(action, length)) |
| 13562 | 13507 | { |
| 13563 | 13508 | if(action->flags & kActionFlag_PDWWrite) |
| 13564 | 13509 | { |
| 13565 | 13510 | if(action->flags & kActionFlag_IsFirst) |
| 13566 | 13511 | { |
| 13567 | 13512 | address += bytes; |
| 13568 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13513 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13569 | 13514 | action->flags &= ~kActionFlag_IsFirst; |
| 13570 | 13515 | } |
| 13571 | 13516 | else |
| r2821 | r2822 | |
| 13583 | 13528 | /* read a data from region */ |
| 13584 | 13529 | UINT8 * buf = memory_region(action->region); |
| 13585 | 13530 | |
| 13586 | | if(buf && IsAddressInRange(action, memory_region_length(action->region))) |
| 13531 | if(buf && is_address_in_range(action, memory_region_length(action->region))) |
| 13587 | 13532 | { |
| 13588 | 13533 | if(action->flags & kActionFlag_PDWWrite) |
| 13589 | 13534 | { |
| 13590 | 13535 | if(action->flags & kActionFlag_IsFirst) |
| 13591 | 13536 | { |
| 13592 | 13537 | address += bytes; |
| 13593 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13538 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13594 | 13539 | action->flags &= ~kActionFlag_IsFirst; |
| 13595 | 13540 | } |
| 13596 | 13541 | else |
| 13597 | 13542 | action->flags |= kActionFlag_IsFirst; |
| 13598 | 13543 | |
| 13599 | | return DoMemoryRead(buf, address, bytes, region_needs_swap(action->region), get_region_info(action->region)); |
| 13544 | return DoMemoryRead(buf, address, bytes, region_needs_swap(action->region) ^ EXTRACT_FIELD(action->type, Endianness), get_region_info(action->region)); |
| 13600 | 13545 | } |
| 13601 | 13546 | else |
| 13602 | | return DoMemoryRead(buf, address, bytes, region_needs_swap(action->region), get_region_info(action->region)); |
| 13547 | return DoMemoryRead(buf, address, bytes, region_needs_swap(action->region) ^ EXTRACT_FIELD(action->type, Endianness), get_region_info(action->region)); |
| 13603 | 13548 | } |
| 13604 | 13549 | } |
| 13605 | 13550 | } |
| r2821 | r2822 | |
| 13614 | 13559 | WriteData - write a data to memory |
| 13615 | 13560 | -------------------------------------*/ |
| 13616 | 13561 | |
| 13617 | | static void WriteData(CheatAction * action, UINT32 data) |
| 13562 | static void WriteData(cheat_action *action, UINT32 data) |
| 13618 | 13563 | { |
| 13619 | 13564 | UINT8 addressRead = EXTRACT_FIELD(action->type, AddressRead); |
| 13620 | 13565 | UINT8 bytes = EXTRACT_FIELD(action->type, AddressSize) + 1; |
| r2821 | r2822 | |
| 13627 | 13572 | if(addressRead == kReadFrom_Address) address = action->address; |
| 13628 | 13573 | else if(addressRead == kReadFrom_Index) address = cheatVariable[action->address]; |
| 13629 | 13574 | |
| 13630 | | if(!TEST_FIELD(action->region, RegionFlag)) |
| 13575 | if(action->region < REGION_INVALID) |
| 13631 | 13576 | { |
| 13632 | 13577 | UINT8 cpu = EXTRACT_FIELD(action->region, CPUIndex); |
| 13633 | 13578 | |
| r2821 | r2822 | |
| 13640 | 13585 | |
| 13641 | 13586 | cpu_region_info *info = get_cpu_info(cpu); |
| 13642 | 13587 | |
| 13643 | | indexAddress = DoCPURead(cpu, address, EXTRACT_FIELD(action->type, IndexSize) + 1, cpu_needs_swap(cpu)); |
| 13588 | indexAddress = DoCPURead(cpu, address, EXTRACT_FIELD(action->type, CodeParameterLower) + 1, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13644 | 13589 | |
| 13645 | 13590 | if(info && info->address_shift) |
| 13646 | 13591 | indexAddress = DoShift(indexAddress, info->address_shift); |
| 13647 | 13592 | |
| 13648 | 13593 | if(indexAddress) |
| 13649 | 13594 | { |
| 13650 | | indexAddress += action->extendData; |
| 13651 | | DoCPUWrite(data, cpu, indexAddress, bytes, cpu_needs_swap(cpu)); |
| 13595 | indexAddress += action->extend_data; |
| 13596 | DoCPUWrite(data, cpu, indexAddress, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13652 | 13597 | } |
| 13653 | 13598 | } |
| 13654 | 13599 | else if(action->flags & kActionFlag_PDWWrite) |
| r2821 | r2822 | |
| 13656 | 13601 | if(action->flags & kActionFlag_IsFirst) |
| 13657 | 13602 | { |
| 13658 | 13603 | address += bytes; |
| 13659 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13604 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13660 | 13605 | action->flags &= ~kActionFlag_IsFirst; |
| 13661 | 13606 | } |
| 13662 | 13607 | else |
| 13663 | 13608 | action->flags |= kActionFlag_IsFirst; |
| 13664 | 13609 | |
| 13665 | | DoCPUWrite(data, cpu, address, bytes, cpu_needs_swap(cpu)); |
| 13610 | DoCPUWrite(data, cpu, address, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13666 | 13611 | } |
| 13667 | 13612 | else |
| 13668 | 13613 | { |
| 13669 | | DoCPUWrite(data, cpu, address, bytes, cpu_needs_swap(cpu)); |
| 13614 | DoCPUWrite(data, cpu, address, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness)); |
| 13670 | 13615 | } |
| 13671 | 13616 | break; |
| 13672 | 13617 | |
| r2821 | r2822 | |
| 13677 | 13622 | { |
| 13678 | 13623 | UINT8 * buf; |
| 13679 | 13624 | |
| 13680 | | action->cachedPointer = GetMemoryRegionBasePointer(cpu, EXTRACT_FIELD(action->type, AddressSpace), address); |
| 13681 | | buf = (UINT8 *) action->cachedPointer; |
| 13625 | action->cached_pointer = GetMemoryRegionBasePointer(cpu, EXTRACT_FIELD(action->type, AddressSpace), address); |
| 13626 | buf = (UINT8 *) action->cached_pointer; |
| 13682 | 13627 | |
| 13683 | 13628 | if(buf) |
| 13684 | 13629 | { |
| r2821 | r2822 | |
| 13687 | 13632 | if(action->flags & kActionFlag_IsFirst) |
| 13688 | 13633 | { |
| 13689 | 13634 | address += bytes; |
| 13690 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13635 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13691 | 13636 | action->flags &= ~kActionFlag_IsFirst; |
| 13692 | 13637 | } |
| 13693 | 13638 | else |
| 13694 | 13639 | action->flags |= kActionFlag_IsFirst; |
| 13695 | 13640 | } |
| 13696 | 13641 | |
| 13697 | | DoMemoryWrite(data, buf, address, bytes, cpu_needs_swap(cpu), get_cpu_info(cpu)); |
| 13642 | DoMemoryWrite(data, buf, address, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness), get_cpu_info(cpu)); |
| 13698 | 13643 | } |
| 13699 | 13644 | } |
| 13700 | 13645 | break; |
| r2821 | r2822 | |
| 13704 | 13649 | int relativeAddress; |
| 13705 | 13650 | UINT8 ** buf; |
| 13706 | 13651 | |
| 13707 | | action->cachedPointer = LookupHandlerMemory(cpu, address, &action->cachedOffset); |
| 13708 | | buf = action->cachedPointer; |
| 13709 | | relativeAddress = action->cachedOffset; |
| 13652 | action->cached_pointer = LookupHandlerMemory(cpu, address, &action->cached_offset); |
| 13653 | buf = action->cached_pointer; |
| 13654 | relativeAddress = action->cached_offset; |
| 13710 | 13655 | |
| 13711 | 13656 | if(buf && *buf) |
| 13712 | 13657 | { |
| r2821 | r2822 | |
| 13715 | 13660 | if(action->flags & kActionFlag_IsFirst) |
| 13716 | 13661 | { |
| 13717 | 13662 | relativeAddress += bytes; |
| 13718 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13663 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13719 | 13664 | action->flags &= ~kActionFlag_IsFirst; |
| 13720 | 13665 | } |
| 13721 | 13666 | else |
| 13722 | 13667 | action->flags |= kActionFlag_IsFirst; |
| 13723 | 13668 | } |
| 13724 | 13669 | |
| 13725 | | DoMemoryWrite(data, *buf, relativeAddress, bytes, cpu_needs_swap(cpu), get_cpu_info(cpu)); |
| 13726 | | return; |
| 13670 | DoMemoryWrite(data, *buf, relativeAddress, bytes, cpu_needs_swap(cpu) ^ EXTRACT_FIELD(action->type, Endianness), get_cpu_info(cpu)); |
| 13727 | 13671 | } |
| 13728 | 13672 | } |
| 13729 | 13673 | break; |
| r2821 | r2822 | |
| 13735 | 13679 | |
| 13736 | 13680 | buf = eeprom_get_data_pointer(&length); |
| 13737 | 13681 | |
| 13738 | | if(IsAddressInRange(action, length)) |
| 13682 | if(is_address_in_range(action, length)) |
| 13739 | 13683 | { |
| 13740 | 13684 | if(action->flags & kActionFlag_PDWWrite) |
| 13741 | 13685 | { |
| 13742 | 13686 | if(action->flags & kActionFlag_IsFirst) |
| 13743 | 13687 | { |
| 13744 | 13688 | address += bytes; |
| 13745 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13689 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13746 | 13690 | action->flags &= ~kActionFlag_IsFirst; |
| 13747 | 13691 | } |
| 13748 | 13692 | else |
| r2821 | r2822 | |
| 13750 | 13694 | } |
| 13751 | 13695 | |
| 13752 | 13696 | DoMemoryWrite(data, buf, address, bytes, 0, &raw_cpu_info); |
| 13753 | | return; |
| 13754 | 13697 | } |
| 13755 | 13698 | } |
| 13756 | 13699 | break; |
| r2821 | r2822 | |
| 13761 | 13704 | /* write a data into region */ |
| 13762 | 13705 | UINT8 * buf = memory_region(action->region); |
| 13763 | 13706 | |
| 13764 | | if(buf && IsAddressInRange(action, memory_region_length(action->region))) |
| 13707 | if(buf && is_address_in_range(action, memory_region_length(action->region))) |
| 13765 | 13708 | { |
| 13766 | 13709 | if(action->flags & kActionFlag_PDWWrite) |
| 13767 | 13710 | { |
| 13768 | 13711 | if(action->flags & kActionFlag_IsFirst) |
| 13769 | 13712 | { |
| 13770 | 13713 | address += bytes; |
| 13771 | | bytes = EXTRACT_FIELD(action->type, IndexSize) + 1; |
| 13714 | bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1; |
| 13772 | 13715 | action->flags &= ~kActionFlag_IsFirst; |
| 13773 | 13716 | } |
| 13774 | 13717 | else |
| 13775 | 13718 | action->flags |= kActionFlag_IsFirst; |
| 13776 | 13719 | } |
| 13777 | 13720 | |
| 13778 | | DoMemoryWrite(data, buf, address, bytes, region_needs_swap(action->region), get_region_info(action->region)); |
| 13779 | | return; |
| 13721 | DoMemoryWrite(data, buf, address, bytes, region_needs_swap(action->region) ^ EXTRACT_FIELD(action->type, Endianness), get_region_info(action->region)); |
| 13780 | 13722 | } |
| 13781 | 13723 | } |
| 13782 | 13724 | } |
| r2821 | r2822 | |
| 13788 | 13730 | WatchCheatEntry - set watchpoint when watch value key is pressed in several menus |
| 13789 | 13731 | ------------------------------------------------------------------------------------*/ |
| 13790 | 13732 | |
| 13791 | | static void WatchCheatEntry(CheatEntry * entry, UINT8 associate) |
| 13733 | static void WatchCheatEntry(cheat_entry *entry, UINT8 associate) |
| 13792 | 13734 | { |
| 13793 | 13735 | int i, j; |
| 13794 | | CheatEntry * associateEntry = NULL; |
| 13736 | cheat_entry *associateEntry = NULL; |
| 13795 | 13737 | |
| 13796 | 13738 | /* NOTE : calling with associate = 1 doesn't exist right now */ |
| 13797 | 13739 | if(associate) |
| r2821 | r2822 | |
| 13799 | 13741 | |
| 13800 | 13742 | if(!entry) |
| 13801 | 13743 | { |
| 13802 | | messageType = kCheatMessage_FailedToAdd; |
| 13803 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 13744 | SET_MESSAGE(kCheatMessage_FailedToAdd); |
| 13804 | 13745 | return; |
| 13805 | 13746 | } |
| 13806 | 13747 | |
| 13807 | | for(i = 0; i < entry->actionListLength; i++) |
| 13748 | for(i = 0; i < entry->action_list_length; i++) |
| 13808 | 13749 | { |
| 13809 | | CheatAction * action = &entry->actionList[i]; |
| 13750 | cheat_action *action = &entry->action_list[i]; |
| 13810 | 13751 | |
| 13811 | 13752 | if(!(action->flags & kActionFlag_NoAction) && !EXTRACT_FIELD(action->type, AddressRead)) |
| 13812 | 13753 | { |
| 13813 | 13754 | /* NOTE : unsupported the watchpoint for indirect index right now */ |
| 13814 | | if((action->flags & kActionFlag_IndexAddress) && action->extendData != ~0) |
| 13755 | if((action->flags & kActionFlag_IndexAddress) && action->extend_data != ~0) |
| 13815 | 13756 | continue; |
| 13816 | 13757 | |
| 13817 | 13758 | if(!i) |
| 13818 | 13759 | { |
| 13819 | | /* first CheatAction */ |
| 13820 | | AddActionWatch(&entry->actionList[i], associateEntry); |
| 13760 | /* first cheat action */ |
| 13761 | AddActionWatch(&entry->action_list[i], associateEntry); |
| 13821 | 13762 | } |
| 13822 | 13763 | else |
| 13823 | 13764 | { |
| 13824 | | /* 2nd or later CheatAction */ |
| 13765 | /* 2nd or later cheat action */ |
| 13825 | 13766 | UINT8 differentAddress = 1; |
| 13826 | 13767 | |
| 13827 | 13768 | for(j = 0; j < i; j++) |
| 13828 | 13769 | { |
| 13829 | | /* if we find the same address CheatAction, skip it */ |
| 13830 | | if(entry->actionList[j].address == entry->actionList[i].address) |
| 13770 | /* if we find the same address cheat action, skip it */ |
| 13771 | if(entry->action_list[j].address == entry->action_list[i].address) |
| 13831 | 13772 | differentAddress = 0; |
| 13832 | 13773 | } |
| 13833 | 13774 | |
| 13834 | 13775 | if(differentAddress) |
| 13835 | | AddActionWatch(&entry->actionList[i], associateEntry); |
| 13776 | AddActionWatch(&entry->action_list[i], associateEntry); |
| 13836 | 13777 | } |
| 13837 | 13778 | } |
| 13838 | 13779 | } |
| 13839 | 13780 | |
| 13840 | | messageType = kCheatMessage_SucceededToAdd; |
| 13841 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 13781 | SET_MESSAGE(kCheatMessage_SucceededToAdd); |
| 13842 | 13782 | } |
| 13843 | 13783 | |
| 13844 | 13784 | /*----------------------------------------------------------------------- |
| r2821 | r2822 | |
| 13847 | 13787 | or ActivateCheat() via watchpoint code. |
| 13848 | 13788 | -----------------------------------------------------------------------*/ |
| 13849 | 13789 | |
| 13850 | | static void AddActionWatch(CheatAction * action, CheatEntry * entry) |
| 13790 | static void AddActionWatch(cheat_action *action, cheat_entry *entry) |
| 13851 | 13791 | { |
| 13852 | 13792 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 13853 | 13793 | { |
| 13854 | 13794 | case kCodeType_Write: |
| 13855 | | case kCodeType_PDWWrite: |
| 13856 | | case kCodeType_RWrite: |
| 13857 | 13795 | case kCodeType_IWrite: |
| 13796 | case kCodeType_RWrite: |
| 13858 | 13797 | case kCodeType_CWrite: |
| 13859 | | case kCodeType_VWrite: |
| 13860 | | case kCodeType_VRWrite: |
| 13861 | | case kCodeType_Branch: |
| 13798 | case kCodeType_CBit: |
| 13799 | case kCodeType_PDWWrite: |
| 13862 | 13800 | case kCodeType_Move: |
| 13801 | case kCodeType_Branch: |
| 13863 | 13802 | case kCodeType_Loop: |
| 13864 | 13803 | case kCodeType_Popup: |
| 13865 | 13804 | { |
| 13866 | | WatchInfo * info = GetUnusedWatch(); |
| 13805 | watch_info *info = get_unused_watch(); |
| 13867 | 13806 | |
| 13868 | 13807 | info->address = action->address; |
| 13869 | 13808 | info->cpu = action->region; |
| 13870 | | info->displayType = kWatchDisplayType_Hex; |
| 13871 | | info->elementBytes = kSearchSize_8Bit; |
| 13809 | info->display_type = kWatchDisplayType_Hex; |
| 13810 | info->element_bytes = kSearchSize_8Bit; |
| 13872 | 13811 | info->label[0] = 0; |
| 13873 | | info->labelType = kWatchLabel_None; |
| 13874 | | info->numElements = EXTRACT_FIELD(action->type, AddressSize) + 1; |
| 13875 | | info->linkedCheat = entry; |
| 13812 | info->label_type = kWatchLabel_None; |
| 13813 | info->num_elements = EXTRACT_FIELD(action->type, AddressSize) + 1; |
| 13814 | info->linked_cheat = entry; |
| 13876 | 13815 | info->skip = 0; |
| 13877 | 13816 | |
| 13878 | 13817 | if(action->flags & kActionFlag_PDWWrite) |
| 13879 | 13818 | { |
| 13880 | | info->numElements += (EXTRACT_FIELD(action->type, IndexSize) + 1); |
| 13819 | info->num_elements += (EXTRACT_FIELD(action->type, CodeParameterLower) + 1); |
| 13881 | 13820 | } |
| 13882 | 13821 | else if(action->flags & kActionFlag_Repeat) |
| 13883 | 13822 | { |
| 13884 | | info->numElements = EXTRACT_FIELD(action->extendData, LSB16); |
| 13885 | | info->skip = EXTRACT_FIELD(action->extendData, MSB16) - 1; |
| 13823 | info->num_elements = EXTRACT_FIELD(action->extend_data, LSB16); |
| 13824 | info->skip = EXTRACT_FIELD(action->extend_data, MSB16) - 1; |
| 13886 | 13825 | } |
| 13887 | 13826 | } |
| 13888 | 13827 | break; |
| 13889 | 13828 | |
| 13890 | 13829 | case kCodeType_Watch: |
| 13891 | 13830 | { |
| 13892 | | WatchInfo * info = GetUnusedWatch(); |
| 13831 | watch_info *info = get_unused_watch(); |
| 13893 | 13832 | |
| 13894 | 13833 | info->address = action->address; |
| 13895 | | info->cpu = EXTRACT_FIELD(action->type, CPURegion); |
| 13896 | | info->displayType = EXTRACT_FIELD(action->type, WatchDisplayFormat); |
| 13897 | | info->elementBytes = kByteConversionTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 13834 | info->cpu = action->region; |
| 13835 | info->display_type = EXTRACT_FIELD(action->type, WatchDisplayFormat); |
| 13836 | info->element_bytes = kByteConversionTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 13898 | 13837 | info->label[0] = 0; |
| 13899 | | info->linkedCheat = entry; |
| 13900 | | info->numElements = EXTRACT_FIELD(action->data, WatchNumElements) + 1; |
| 13838 | info->linked_cheat = entry; |
| 13839 | info->num_elements = EXTRACT_FIELD(action->data, WatchNumElements) + 1; |
| 13901 | 13840 | info->skip = EXTRACT_FIELD(action->data, WatchSkip); |
| 13902 | | info->elementsPerLine = EXTRACT_FIELD(action->data, WatchElementsPerLine); |
| 13903 | | info->addValue = EXTRACT_FIELD(action->data, WatchAddValue); |
| 13841 | info->elements_per_line = EXTRACT_FIELD(action->data, WatchElementsPerLine); |
| 13842 | info->add_value = EXTRACT_FIELD(action->data, WatchAddValue); |
| 13904 | 13843 | |
| 13905 | | if(info->addValue & 0x80) |
| 13906 | | info->addValue |= ~0xFF; |
| 13844 | if(info->add_value & 0x80) |
| 13845 | info->add_value |= ~0xFF; |
| 13907 | 13846 | |
| 13908 | | if(action->extendData != ~0) |
| 13847 | if(action->extend_data != ~0) |
| 13909 | 13848 | { |
| 13910 | 13849 | /* ### fix me... ### */ |
| 13911 | | info->x = (float)(EXTRACT_FIELD(action->extendData, LSB16)) / 100; |
| 13912 | | info->y = (float)(EXTRACT_FIELD(action->extendData, MSB16)) / 100; |
| 13850 | info->x = (float)(EXTRACT_FIELD(action->extend_data, LSB16)) / 100; |
| 13851 | info->y = (float)(EXTRACT_FIELD(action->extend_data, MSB16)) / 100; |
| 13913 | 13852 | } |
| 13914 | 13853 | |
| 13915 | 13854 | if(TEST_FIELD(action->type, WatchShowLabel) && entry->comment && strlen(entry->comment) < 256) |
| 13916 | 13855 | { |
| 13917 | | info->labelType = kWatchLabel_String; |
| 13856 | info->label_type = kWatchLabel_String; |
| 13918 | 13857 | strcpy(info->label, entry->comment); |
| 13919 | 13858 | } |
| 13920 | 13859 | else |
| 13921 | | info->labelType = kWatchLabel_None; |
| 13860 | info->label_type = kWatchLabel_None; |
| 13922 | 13861 | } |
| 13923 | 13862 | break; |
| 13924 | 13863 | } |
| r2821 | r2822 | |
| 13929 | 13868 | called from DeactivateCheat(). |
| 13930 | 13869 | ------------------------------------------------------------------------------*/ |
| 13931 | 13870 | |
| 13932 | | static void RemoveAssociatedWatches(CheatEntry * entry) |
| 13871 | static void RemoveAssociatedWatches(cheat_entry *entry) |
| 13933 | 13872 | { |
| 13934 | 13873 | int i; |
| 13935 | 13874 | |
| 13936 | | for(i = watchListLength - 1; i >= 0; i--) |
| 13875 | for(i = watch_list_length - 1; i >= 0; i--) |
| 13937 | 13876 | { |
| 13938 | | WatchInfo * info = &watchList[i]; |
| 13877 | watch_info *info = &watch_list[i]; |
| 13939 | 13878 | |
| 13940 | | if(info->linkedCheat == entry) |
| 13941 | | DeleteWatchAt(i); |
| 13879 | if(info->linked_cheat == entry) |
| 13880 | delete_watch_at(i); |
| 13942 | 13881 | } |
| 13943 | 13882 | } |
| 13944 | 13883 | |
| r2821 | r2822 | |
| 13946 | 13885 | ResetAction - back up data and set action flags |
| 13947 | 13886 | --------------------------------------------------*/ |
| 13948 | 13887 | |
| 13949 | | static void ResetAction(CheatAction * action) |
| 13888 | static void ResetAction(cheat_action *action) |
| 13950 | 13889 | { |
| 13951 | 13890 | if(action->flags & kActionFlag_NoAction) |
| 13952 | 13891 | return; |
| 13953 | 13892 | |
| 13954 | 13893 | /* back up a value */ |
| 13955 | | if(!(action->flags & kActionFlag_LastValueGood)) |
| 13894 | if(action->flags & kActionFlag_OldFormat) |
| 13956 | 13895 | { |
| 13957 | | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 13896 | UINT32 type = action->type; |
| 13897 | |
| 13898 | action->last_value = malloc_or_die(sizeof(action->last_value)); |
| 13899 | action->type = convert_to_new_code(action); |
| 13900 | action->last_value[0] = ReadData(action); |
| 13901 | action->type = type; |
| 13902 | } |
| 13903 | else |
| 13904 | { |
| 13905 | if(!(action->flags & kActionFlag_LastValueGood)) |
| 13958 | 13906 | { |
| 13959 | | default: |
| 13960 | | action->lastValue = malloc_or_die(sizeof(action->lastValue)); |
| 13961 | | action->lastValue[0] = ReadData(action); |
| 13962 | | break; |
| 13907 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 13908 | { |
| 13909 | default: |
| 13910 | action->last_value = malloc_or_die(sizeof(action->last_value)); |
| 13911 | action->last_value[0] = ReadData(action); |
| 13912 | break; |
| 13963 | 13913 | |
| 13964 | | case kCodeType_PDWWrite: |
| 13965 | | action->lastValue = malloc_or_die(sizeof(action->lastValue) * 2); |
| 13966 | | action->lastValue[0] = ReadData(action); |
| 13967 | | action->lastValue[1] = ReadData(action); |
| 13968 | | break; |
| 13914 | case kCodeType_PDWWrite: |
| 13915 | action->last_value = malloc_or_die(sizeof(action->last_value) * 2); |
| 13916 | action->last_value[0] = ReadData(action); |
| 13917 | action->last_value[1] = ReadData(action); |
| 13918 | break; |
| 13969 | 13919 | |
| 13970 | | case kCodeType_RWrite: |
| 13971 | | case kCodeType_VRWrite: |
| 13972 | | { |
| 13973 | | int i; |
| 13974 | | |
| 13975 | | for(i = 0; i < EXTRACT_FIELD(action->extendData, LSB16); i++) |
| 13920 | case kCodeType_RWrite: |
| 13976 | 13921 | { |
| 13977 | | action->lastValue = realloc(action->lastValue, sizeof(action->lastValue) * EXTRACT_FIELD(action->extendData, LSB16)); |
| 13978 | | action->lastValue[i] = ReadData(action); |
| 13979 | | action->address += EXTRACT_FIELD(action->extendData, MSB16) ? |
| 13980 | | EXTRACT_FIELD(action->extendData, MSB16) : |
| 13981 | | kSearchByteIncrementTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 13922 | int i; |
| 13923 | |
| 13924 | for(i = 0; i < EXTRACT_FIELD(action->extend_data, LSB16); i++) |
| 13925 | { |
| 13926 | action->last_value = realloc(action->last_value, sizeof(action->last_value) * EXTRACT_FIELD(action->extend_data, LSB16)); |
| 13927 | action->last_value[i] = ReadData(action); |
| 13928 | action->address += EXTRACT_FIELD(action->extend_data, MSB16) ? |
| 13929 | EXTRACT_FIELD(action->extend_data, MSB16) : |
| 13930 | kSearchByteIncrementTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 13931 | } |
| 13932 | action->address = action->original_address; |
| 13982 | 13933 | } |
| 13983 | | action->address = action->originalAddress; |
| 13984 | | } |
| 13985 | | break; |
| 13934 | break; |
| 13935 | } |
| 13986 | 13936 | } |
| 13987 | 13937 | } |
| 13988 | 13938 | |
| 13989 | | action->frameTimer = 0; |
| 13939 | action->frame_timer = 0; |
| 13990 | 13940 | action->flags &= ~kActionFlag_StateMask; |
| 13991 | 13941 | action->flags |= kActionFlag_LastValueGood; |
| 13992 | 13942 | |
| r2821 | r2822 | |
| 13995 | 13945 | if(EXTRACT_FIELD(action->type, CodeParameter) == kCondition_PreviousValue) |
| 13996 | 13946 | { |
| 13997 | 13947 | if(EXTRACT_FIELD(action->type, CodeType) == kCodeType_CWrite) |
| 13998 | | action->extendData = ReadData(action); |
| 13948 | action->extend_data = ReadData(action); |
| 13999 | 13949 | else |
| 14000 | 13950 | action->data = ReadData(action); |
| 14001 | 13951 | } |
| r2821 | r2822 | |
| 14006 | 13956 | ActivateCheat - reset action entry and set activate entry flag when turn CODE "ON" |
| 14007 | 13957 | -------------------------------------------------------------------------------------*/ |
| 14008 | 13958 | |
| 14009 | | static void ActivateCheat(CheatEntry * entry) |
| 13959 | static void ActivateCheat(cheat_entry *entry) |
| 14010 | 13960 | { |
| 14011 | 13961 | int i; |
| 14012 | 13962 | |
| 14013 | | for(i = 0; i < entry->actionListLength; i++) |
| 13963 | for(i = 0; i < entry->action_list_length; i++) |
| 14014 | 13964 | { |
| 14015 | | CheatAction * action = &entry->actionList[i]; |
| 13965 | cheat_action *action = &entry->action_list[i]; |
| 14016 | 13966 | |
| 14017 | 13967 | ResetAction(action); |
| 14018 | 13968 | |
| r2821 | r2822 | |
| 14029 | 13979 | DeactivateCheat - restore previous value and remove watchpoint when turn CODE "OFF" |
| 14030 | 13980 | --------------------------------------------------------------------------------------*/ |
| 14031 | 13981 | |
| 14032 | | static void DeactivateCheat(CheatEntry * entry) |
| 13982 | static void DeactivateCheat(cheat_entry *entry) |
| 14033 | 13983 | { |
| 14034 | 13984 | int i; |
| 14035 | 13985 | |
| 14036 | | for(i = 0; i < entry->actionListLength; i++) |
| 13986 | for(i = 0; i < entry->action_list_length; i++) |
| 14037 | 13987 | { |
| 14038 | | CheatAction * action = &entry->actionList[i]; |
| 13988 | cheat_action *action = &entry->action_list[i]; |
| 14039 | 13989 | |
| 14040 | 13990 | /* restore previous value and clear backup flag if needed */ |
| 14041 | 13991 | if(TEST_FIELD(action->type, RestoreValue) && (action->flags & kActionFlag_LastValueGood)) |
| r2821 | r2822 | |
| 14043 | 13993 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 14044 | 13994 | { |
| 14045 | 13995 | default: |
| 14046 | | WriteData(action, (UINT32)action->lastValue[0]); |
| 13996 | WriteData(action, (UINT32)action->last_value[0]); |
| 14047 | 13997 | break; |
| 14048 | 13998 | |
| 14049 | 13999 | case kCodeType_PDWWrite: |
| 14050 | | WriteData(action, (UINT32)action->lastValue[0]); |
| 14051 | | WriteData(action, (UINT32)action->lastValue[1]); |
| 14000 | WriteData(action, (UINT32)action->last_value[0]); |
| 14001 | WriteData(action, (UINT32)action->last_value[1]); |
| 14052 | 14002 | break; |
| 14053 | 14003 | |
| 14054 | 14004 | case kCodeType_RWrite: |
| 14055 | | case kCodeType_VRWrite: |
| 14056 | 14005 | { |
| 14057 | 14006 | int j; |
| 14058 | 14007 | |
| 14059 | | for(j = 0; j < EXTRACT_FIELD(action->extendData, LSB16); j++) |
| 14008 | for(j = 0; j < EXTRACT_FIELD(action->extend_data, LSB16); j++) |
| 14060 | 14009 | { |
| 14061 | | WriteData(action, (UINT32)action->lastValue[j]); |
| 14062 | | action->address += EXTRACT_FIELD(action->extendData, MSB16) ? |
| 14063 | | EXTRACT_FIELD(action->extendData, MSB16) : |
| 14010 | WriteData(action, (UINT32)action->last_value[j]); |
| 14011 | action->address += EXTRACT_FIELD(action->extend_data, MSB16) ? |
| 14012 | EXTRACT_FIELD(action->extend_data, MSB16) : |
| 14064 | 14013 | kSearchByteIncrementTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 14065 | 14014 | } |
| 14066 | | action->address = action->originalAddress; |
| 14015 | action->address = action->original_address; |
| 14067 | 14016 | } |
| 14068 | 14017 | break; |
| 14069 | 14018 | } |
| 14070 | 14019 | action->flags &= ~kActionFlag_LastValueGood; |
| 14071 | 14020 | } |
| 14072 | | free(action->lastValue); |
| 14073 | | action->lastValue = NULL; |
| 14021 | free(action->last_value); |
| 14022 | action->last_value = NULL; |
| 14074 | 14023 | } |
| 14075 | 14024 | |
| 14076 | 14025 | /* remove watchpoint */ |
| r2821 | r2822 | |
| 14084 | 14033 | TempDeactivateCheat - restore previous value when turn CHEAT "OFF" |
| 14085 | 14034 | --------------------------------------------------------------------*/ |
| 14086 | 14035 | |
| 14087 | | static void TempDeactivateCheat(CheatEntry * entry) |
| 14036 | static void TempDeactivateCheat(cheat_entry *entry) |
| 14088 | 14037 | { |
| 14089 | 14038 | if(entry->flags & kCheatFlag_Active) |
| 14090 | 14039 | { |
| 14091 | 14040 | int i; |
| 14092 | 14041 | |
| 14093 | | for(i = 0; i < entry->actionListLength; i++) |
| 14042 | for(i = 0; i < entry->action_list_length; i++) |
| 14094 | 14043 | { |
| 14095 | | CheatAction * action = &entry->actionList[i]; |
| 14044 | cheat_action *action = &entry->action_list[i]; |
| 14096 | 14045 | |
| 14097 | | action->frameTimer = 0; |
| 14046 | action->frame_timer = 0; |
| 14098 | 14047 | action->flags &= ~kActionFlag_OperationDone; |
| 14099 | 14048 | |
| 14100 | 14049 | /* restore previous value if needed */ |
| 14101 | 14050 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 14102 | 14051 | { |
| 14103 | 14052 | default: |
| 14104 | | WriteData(action, (UINT32)action->lastValue[0]); |
| 14053 | WriteData(action, (UINT32)action->last_value[0]); |
| 14105 | 14054 | break; |
| 14106 | 14055 | |
| 14107 | 14056 | case kCodeType_PDWWrite: |
| 14108 | | WriteData(action, (UINT32)action->lastValue[0]); |
| 14109 | | WriteData(action, (UINT32)action->lastValue[1]); |
| 14057 | WriteData(action, (UINT32)action->last_value[0]); |
| 14058 | WriteData(action, (UINT32)action->last_value[1]); |
| 14110 | 14059 | break; |
| 14111 | 14060 | |
| 14112 | 14061 | case kCodeType_RWrite: |
| 14113 | | case kCodeType_VRWrite: |
| 14114 | 14062 | { |
| 14115 | 14063 | int j; |
| 14116 | 14064 | |
| 14117 | | for(j = 0; j < EXTRACT_FIELD(action->extendData, LSB16); j++) |
| 14065 | for(j = 0; j < EXTRACT_FIELD(action->extend_data, LSB16); j++) |
| 14118 | 14066 | { |
| 14119 | | WriteData(action, (UINT32)action->lastValue[j]); |
| 14120 | | action->address += EXTRACT_FIELD(action->extendData, MSB16) ? |
| 14121 | | EXTRACT_FIELD(action->extendData, MSB16) : |
| 14067 | WriteData(action, (UINT32)action->last_value[j]); |
| 14068 | action->address += EXTRACT_FIELD(action->extend_data, MSB16) ? |
| 14069 | EXTRACT_FIELD(action->extend_data, MSB16) : |
| 14122 | 14070 | kSearchByteIncrementTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 14123 | 14071 | } |
| 14124 | | action->address = action->originalAddress; |
| 14072 | action->address = action->original_address; |
| 14125 | 14073 | } |
| 14126 | 14074 | break; |
| 14127 | 14075 | } |
| r2821 | r2822 | |
| 14134 | 14082 | cheat_periodicOperation - management for cheat operations |
| 14135 | 14083 | ------------------------------------------------------------*/ |
| 14136 | 14084 | |
| 14137 | | static void cheat_periodicOperation(CheatAction * action) |
| 14085 | static void cheat_periodicOperation(cheat_action *action) |
| 14138 | 14086 | { |
| 14139 | 14087 | int data = TEST_FIELD(action->type, DataRead) ? cheatVariable[action->data] : action->data; |
| 14140 | 14088 | |
| r2821 | r2822 | |
| 14142 | 14090 | { |
| 14143 | 14091 | action->flags &= ~kActionFlag_IsFirst; |
| 14144 | 14092 | WriteData(action, data); |
| 14145 | | WriteData(action, action->extendData); |
| 14093 | WriteData(action, action->extend_data); |
| 14146 | 14094 | } |
| 14147 | 14095 | else if(action->flags & kActionFlag_Repeat) |
| 14148 | 14096 | { |
| 14149 | 14097 | int i; |
| 14150 | 14098 | |
| 14151 | | for(i = 0; i < EXTRACT_FIELD(action->extendData, LSB16); i++) |
| 14099 | for(i = 0; i < EXTRACT_FIELD(action->extend_data, LSB16); i++) |
| 14152 | 14100 | { |
| 14153 | 14101 | WriteData(action, data); |
| 14154 | | action->address += EXTRACT_FIELD(action->extendData, MSB16) ? |
| 14155 | | EXTRACT_FIELD(action->extendData, MSB16) : |
| 14102 | action->address += EXTRACT_FIELD(action->extend_data, MSB16) ? |
| 14103 | EXTRACT_FIELD(action->extend_data, MSB16) : |
| 14156 | 14104 | kSearchByteIncrementTable[EXTRACT_FIELD(action->type, AddressSize)]; |
| 14157 | 14105 | } |
| 14158 | | action->address = action->originalAddress; |
| 14106 | action->address = action->original_address; |
| 14159 | 14107 | } |
| 14160 | 14108 | else |
| 14161 | 14109 | { |
| 14162 | 14110 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 14163 | 14111 | { |
| 14164 | 14112 | case kCodeType_Write: |
| 14165 | | WriteData(action, (data & action->extendData) | (ReadData(action) & ~action->extendData)); |
| 14113 | WriteData(action, (data & action->extend_data) | (ReadData(action) & ~action->extend_data)); |
| 14166 | 14114 | break; |
| 14167 | 14115 | |
| 14168 | 14116 | case kCodeType_IWrite: |
| 14169 | 14117 | switch(EXTRACT_FIELD(action->type, CodeParameter)) |
| 14170 | 14118 | { |
| 14171 | | case kIWrite_Write: |
| 14119 | case IWRITE_WRITE: |
| 14172 | 14120 | WriteData(action, data); |
| 14173 | 14121 | break; |
| 14174 | 14122 | |
| 14175 | | case kIWrite_BitSet: |
| 14123 | case IWRITE_BIT_SET: |
| 14176 | 14124 | WriteData(action, ReadData(action) | data); |
| 14177 | 14125 | break; |
| 14178 | 14126 | |
| 14179 | | case kIWrite_BitClear: |
| 14127 | case IWRITE_BIT_CLEAR: |
| 14180 | 14128 | WriteData(action, ReadData(action) & ~data); |
| 14181 | 14129 | break; |
| 14182 | 14130 | |
| 14183 | | case kIWrite_LimitedMask: |
| 14131 | case IWRITE_LIMITED_MASK: |
| 14184 | 14132 | WriteData(action, (EXTRACT_FIELD(data, MSB16) & EXTRACT_FIELD(data, LSB16)) | (ReadData(action) & ~EXTRACT_FIELD(data, LSB16))); |
| 14185 | 14133 | break; |
| 14186 | 14134 | } |
| 14187 | 14135 | break; |
| 14188 | 14136 | |
| 14189 | 14137 | case kCodeType_CWrite: |
| 14190 | | case kCodeType_VWrite: |
| 14191 | 14138 | WriteData(action, data); |
| 14192 | 14139 | break; |
| 14193 | 14140 | |
| 14141 | case kCodeType_CBit: |
| 14142 | switch(EXTRACT_FIELD(action->type, CodeParameterUpper)) |
| 14143 | { |
| 14144 | case CBIT_BIT_SET: |
| 14145 | WriteData(action, ReadData(action) | data); |
| 14146 | break; |
| 14147 | |
| 14148 | case CBIT_BIT_CLEAR: |
| 14149 | WriteData(action, ReadData(action) & ~data); |
| 14150 | break; |
| 14151 | |
| 14152 | case CBIT_LIMITED_MASK: |
| 14153 | WriteData(action, (EXTRACT_FIELD(data, MSB16) & EXTRACT_FIELD(data, LSB16)) | (ReadData(action) & ~EXTRACT_FIELD(data, LSB16))); |
| 14154 | break; |
| 14155 | } |
| 14156 | break; |
| 14157 | |
| 14194 | 14158 | case kCodeType_Move: |
| 14195 | 14159 | cheatVariable[EXTRACT_FIELD(action->type, CodeParameter)] = ReadData(action) + data; |
| 14196 | 14160 | break; |
| r2821 | r2822 | |
| 14199 | 14163 | switch(EXTRACT_FIELD(action->type, PopupParameter)) |
| 14200 | 14164 | { |
| 14201 | 14165 | case kPopup_Label: |
| 14202 | | ui_popup_time(1, "%s", action->optionalName); |
| 14166 | ui_popup_time(1, "%s", action->optional_name); |
| 14203 | 14167 | break; |
| 14204 | 14168 | |
| 14205 | 14169 | case kPopup_Value: |
| 14206 | 14170 | ui_popup_time(1, "%*.*X", |
| 14207 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressRead)], |
| 14208 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressRead)], |
| 14171 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 14172 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 14209 | 14173 | ReadData(action)); |
| 14210 | 14174 | break; |
| 14211 | 14175 | |
| 14212 | 14176 | case kPopup_LabelValue: |
| 14213 | 14177 | ui_popup_time(1, "%s %*.*X", |
| 14214 | | action->optionalName, |
| 14215 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressRead)], |
| 14216 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressRead)], |
| 14178 | action->optional_name, |
| 14179 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 14180 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 14217 | 14181 | ReadData(action)); |
| 14218 | 14182 | break; |
| 14219 | 14183 | |
| 14220 | 14184 | case kPopup_ValueLabel: |
| 14221 | 14185 | ui_popup_time(1, "%*.*X %s", |
| 14222 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressRead)], |
| 14223 | | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressRead)], |
| 14186 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 14187 | kCheatSizeDigitsTable[EXTRACT_FIELD(action->type, AddressSize)], |
| 14224 | 14188 | ReadData(action), |
| 14225 | | action->optionalName); |
| 14189 | action->optional_name); |
| 14226 | 14190 | break; |
| 14227 | 14191 | } |
| 14228 | 14192 | break; |
| r2821 | r2822 | |
| 14236 | 14200 | |
| 14237 | 14201 | /*------------------------------------------------------------ |
| 14238 | 14202 | cheat_periodicCondition - management for cheat conditions |
| 14239 | | used by CWrite, Branch, Popup |
| 14240 | 14203 | ------------------------------------------------------------*/ |
| 14241 | 14204 | |
| 14242 | | static UINT8 cheat_periodicCondition(CheatAction * action) |
| 14205 | static UINT8 cheat_periodicCondition(cheat_action *action) |
| 14243 | 14206 | { |
| 14244 | 14207 | int data = ReadData(action); |
| 14245 | | int value = EXTRACT_FIELD(action->type, CodeType) == kCodeType_CWrite ? action->extendData : action->data; |
| 14208 | int value = action->extend_data; |
| 14246 | 14209 | |
| 14247 | | switch(EXTRACT_FIELD(action->type, CodeParameter)) |
| 14210 | if(EXTRACT_FIELD(action->type, CodeType) != kCodeType_CBit) |
| 14248 | 14211 | { |
| 14249 | | case kCondition_Equal: |
| 14250 | | return (data == value); |
| 14212 | /* CWrite, Branch, Popup */ |
| 14213 | switch(EXTRACT_FIELD(action->type, CodeParameter)) |
| 14214 | { |
| 14215 | case kCondition_Equal: |
| 14216 | return (data == value); |
| 14251 | 14217 | |
| 14252 | | case kCondition_NotEqual: |
| 14253 | | return (data != value); |
| 14218 | case kCondition_NotEqual: |
| 14219 | return (data != value); |
| 14254 | 14220 | |
| 14255 | | case kCondition_Less: |
| 14256 | | return (data < value); |
| 14221 | case kCondition_Less: |
| 14222 | return (data < value); |
| 14257 | 14223 | |
| 14258 | | case kCondition_LessOrEqual: |
| 14259 | | return (data <= value); |
| 14224 | case kCondition_LessOrEqual: |
| 14225 | return (data <= value); |
| 14260 | 14226 | |
| 14261 | | case kCondition_Greater: |
| 14262 | | return (data > value); |
| 14227 | case kCondition_Greater: |
| 14228 | return (data > value); |
| 14263 | 14229 | |
| 14264 | | case kCondition_GreaterOrEqual: |
| 14265 | | return (data >= value); |
| 14230 | case kCondition_GreaterOrEqual: |
| 14231 | return (data >= value); |
| 14266 | 14232 | |
| 14267 | | case kCondition_BitSet: |
| 14268 | | return (data & value); |
| 14233 | case kCondition_BitSet: |
| 14234 | return (data & value); |
| 14269 | 14235 | |
| 14270 | | case kCondition_BitClear: |
| 14271 | | return (!(data & value)); |
| 14236 | case kCondition_BitClear: |
| 14237 | return (!(data & value)); |
| 14272 | 14238 | |
| 14273 | | case kCondition_PreviousValue: |
| 14274 | | if(data != value) |
| 14275 | | { |
| 14276 | | if(EXTRACT_FIELD(action->type, CodeType) == kCodeType_CWrite) |
| 14277 | | action->extendData = data; |
| 14278 | | else |
| 14279 | | action->data = data; |
| 14239 | case kCondition_PreviousValue: |
| 14240 | if(data != value) |
| 14241 | { |
| 14242 | if(EXTRACT_FIELD(action->type, CodeType) == kCodeType_CWrite) |
| 14243 | action->extend_data = data; |
| 14244 | else |
| 14245 | action->data = data; |
| 14280 | 14246 | |
| 14281 | | return 1; |
| 14282 | | } |
| 14283 | | break; |
| 14247 | return 1; |
| 14248 | } |
| 14249 | break; |
| 14284 | 14250 | |
| 14285 | | case kCondition_KeyPressedOnce: |
| 14286 | | return (input_code_pressed_once(value)); |
| 14251 | case kCondition_KeyPressedOnce: |
| 14252 | return (input_code_pressed_once(value)); |
| 14287 | 14253 | |
| 14288 | | case kCondition_KeyPressedRepeat: |
| 14289 | | return (input_code_pressed(value)); |
| 14254 | case kCondition_KeyPressedRepeat: |
| 14255 | return (input_code_pressed(value)); |
| 14290 | 14256 | |
| 14291 | | case kCondition_True: |
| 14292 | | return 1; |
| 14257 | case kCondition_True: |
| 14258 | return 1; |
| 14259 | } |
| 14293 | 14260 | } |
| 14261 | else |
| 14262 | { |
| 14263 | /* CBit */ |
| 14264 | switch(EXTRACT_FIELD(action->type, CodeParameterLower)) |
| 14265 | { |
| 14266 | case CONDITION_CBIT_BIT_SET: |
| 14267 | return (data & value); |
| 14294 | 14268 | |
| 14269 | case CONDITION_CBIT_BIT_CLEAR: |
| 14270 | return (!(data & value)); |
| 14271 | } |
| 14272 | } |
| 14273 | |
| 14295 | 14274 | return 0; |
| 14296 | 14275 | } |
| 14297 | 14276 | |
| r2821 | r2822 | |
| 14299 | 14278 | cheat_periodicAction - management for cheat actions |
| 14300 | 14279 | ------------------------------------------------------*/ |
| 14301 | 14280 | |
| 14302 | | static int cheat_periodicAction(running_machine *machine, CheatAction * action, int selection) |
| 14281 | static int cheat_periodicAction(running_machine *machine, cheat_action *action, int selection) |
| 14303 | 14282 | { |
| 14304 | 14283 | UINT8 executeOperation = 0; |
| 14305 | 14284 | |
| 14306 | | if(driverSpecifiedFlag) |
| 14307 | | return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1); |
| 14308 | | |
| 14309 | | if(TEST_FIELD(action->type, PrefillEnable) && !(action->flags & kActionFlag_PrefillDone)) |
| 14285 | if(TEST_FIELD(action->type, PrefillEnable)) |
| 14310 | 14286 | { |
| 14311 | | UINT8 prefillValue = kPrefillValueTable[EXTRACT_FIELD(action->type, PrefillEnable)]; |
| 14312 | | |
| 14313 | | if(!(action->flags & kActionFlag_PrefillWritten)) |
| 14287 | if((action->flags & kActionFlag_PrefillDone) == 0) |
| 14314 | 14288 | { |
| 14315 | | /* set prefill */ |
| 14316 | | WriteData(action, prefillValue); |
| 14317 | | action->flags |= kActionFlag_PrefillWritten; |
| 14318 | | return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1); |
| 14289 | UINT8 prefillValue = kPrefillValueTable[EXTRACT_FIELD(action->type, PrefillEnable)]; |
| 14319 | 14290 | |
| 14320 | | } |
| 14321 | | else |
| 14322 | | { |
| 14323 | | /* do re-write */ |
| 14324 | | if(ReadData(action) == prefillValue) |
| 14291 | if((action->flags & kActionFlag_PrefillWritten) == 0) |
| 14292 | { |
| 14293 | /* set prefill */ |
| 14294 | WriteData(action, prefillValue); |
| 14295 | action->flags |= kActionFlag_PrefillWritten; |
| 14325 | 14296 | return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1); |
| 14297 | } |
| 14298 | else |
| 14299 | { |
| 14300 | /* do re-write */ |
| 14301 | if(ReadData(action) == prefillValue) |
| 14302 | return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1); |
| 14326 | 14303 | |
| 14327 | | action->flags |= kActionFlag_PrefillDone; |
| 14304 | action->flags |= kActionFlag_PrefillDone; |
| 14305 | } |
| 14328 | 14306 | } |
| 14329 | 14307 | } |
| 14330 | 14308 | |
| r2821 | r2822 | |
| 14335 | 14313 | /* Keep */ |
| 14336 | 14314 | executeOperation = 1; |
| 14337 | 14315 | |
| 14338 | | if(action->frameTimer++ >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds)) |
| 14316 | if(action->frame_timer++ >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds)) |
| 14339 | 14317 | action->flags |= kActionFlag_OperationDone; |
| 14340 | 14318 | } |
| 14341 | 14319 | else |
| 14342 | 14320 | { |
| 14343 | | if(action->frameTimer++ >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds)) |
| 14321 | if(action->frame_timer++ >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds)) |
| 14344 | 14322 | { |
| 14345 | 14323 | /* Delay */ |
| 14346 | 14324 | executeOperation = 1; |
| 14347 | | action->frameTimer = 0; |
| 14325 | action->frame_timer = 0; |
| 14348 | 14326 | |
| 14349 | 14327 | if(TEST_FIELD(action->type, OneShot)) |
| 14350 | 14328 | action->flags |= kActionFlag_OperationDone; |
| r2821 | r2822 | |
| 14353 | 14331 | } |
| 14354 | 14332 | else |
| 14355 | 14333 | { |
| 14356 | | if(action->frameTimer++) |
| 14334 | if(action->frame_timer++) |
| 14357 | 14335 | { |
| 14358 | | if(action->frameTimer >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds)) |
| 14359 | | action->frameTimer = 0; |
| 14336 | if(action->frame_timer >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds)) |
| 14337 | action->frame_timer = 0; |
| 14360 | 14338 | |
| 14361 | 14339 | return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1); |
| 14362 | 14340 | } |
| 14363 | 14341 | else |
| 14364 | 14342 | { |
| 14365 | | executeOperation = 1; |
| 14343 | executeOperation = 1; |
| 14366 | 14344 | |
| 14367 | | action->flags |= kActionFlag_OperationDone; |
| 14345 | action->flags |= kActionFlag_OperationDone; |
| 14368 | 14346 | } |
| 14369 | 14347 | } |
| 14370 | 14348 | |
| 14349 | if(action->flags & kActionFlag_CheckCondition) |
| 14350 | { |
| 14351 | if(cheat_periodicCondition(action)) |
| 14352 | executeOperation = 1; |
| 14353 | else |
| 14354 | executeOperation = 0; |
| 14355 | } |
| 14356 | |
| 14371 | 14357 | if(executeOperation) |
| 14372 | 14358 | { |
| 14373 | 14359 | /* do cheat operation */ |
| 14374 | 14360 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 14375 | 14361 | { |
| 14376 | 14362 | case kCodeType_Write: |
| 14377 | | case kCodeType_PDWWrite: |
| 14378 | | case kCodeType_RWrite: |
| 14379 | 14363 | case kCodeType_IWrite: |
| 14380 | | case kCodeType_VWrite: |
| 14381 | | case kCodeType_VRWrite: |
| 14364 | case kCodeType_RWrite: |
| 14365 | case kCodeType_CWrite: |
| 14366 | case kCodeType_CBit: |
| 14367 | case kCodeType_PDWWrite: |
| 14382 | 14368 | case kCodeType_Move: |
| 14369 | case kCodeType_Popup: |
| 14383 | 14370 | cheat_periodicOperation(action); |
| 14384 | 14371 | break; |
| 14385 | 14372 | |
| 14386 | | case kCodeType_CWrite: |
| 14387 | | case kCodeType_Popup: |
| 14388 | | if(cheat_periodicCondition(action)) |
| 14389 | | cheat_periodicOperation(action); |
| 14390 | | break; |
| 14391 | | |
| 14392 | 14373 | case kCodeType_Branch: |
| 14393 | | if(cheat_periodicCondition(action)) |
| 14394 | | return action->extendData; |
| 14395 | | break; |
| 14374 | return action->data; |
| 14396 | 14375 | |
| 14397 | 14376 | case kCodeType_Loop: |
| 14398 | 14377 | { |
| 14399 | 14378 | int counter = ReadData(action); |
| 14400 | 14379 | |
| 14401 | | if(counter) |
| 14380 | if(counter != 0) |
| 14402 | 14381 | { |
| 14403 | 14382 | WriteData(action, counter - 1); |
| 14404 | 14383 | |
| 14405 | 14384 | return (TEST_FIELD(action->type, DataRead) ? cheatVariable[action->data] : action->data); |
| 14406 | 14385 | } |
| 14407 | 14386 | } |
| 14408 | | break; |
| 14409 | 14387 | } |
| 14410 | 14388 | } |
| 14411 | 14389 | |
| r2821 | r2822 | |
| 14416 | 14394 | cheat_periodicEntry - management for cheat entries |
| 14417 | 14395 | -----------------------------------------------------*/ |
| 14418 | 14396 | |
| 14419 | | static void cheat_periodicEntry(running_machine *machine, CheatEntry * entry) |
| 14397 | static void cheat_periodicEntry(running_machine *machine, cheat_entry *entry) |
| 14420 | 14398 | { |
| 14421 | 14399 | int i = 0; |
| 14422 | 14400 | UINT8 pressedKey = 0; |
| r2821 | r2822 | |
| 14427 | 14405 | if(!ui_is_menu_active()) |
| 14428 | 14406 | { |
| 14429 | 14407 | /* NOTE : activation key should be not checked in activating UI menu because it conflicts activation key checker */ |
| 14430 | | if((entry->flags & kCheatFlag_HasActivationKey1) && input_code_pressed_once(entry->activationKey1)) |
| 14408 | if((entry->flags & kCheatFlag_HasActivationKey1) && input_code_pressed_once(entry->activation_key1)) |
| 14431 | 14409 | pressedKey = 1; |
| 14432 | | else if((entry->flags & kCheatFlag_HasActivationKey2) && input_code_pressed_once(entry->activationKey2)) |
| 14410 | else if((entry->flags & kCheatFlag_HasActivationKey2) && input_code_pressed_once(entry->activation_key2)) |
| 14433 | 14411 | pressedKey = 2; |
| 14434 | 14412 | } |
| 14435 | 14413 | |
| r2821 | r2822 | |
| 14440 | 14418 | if(pressedKey == 1) |
| 14441 | 14419 | { |
| 14442 | 14420 | if(--entry->selection < 0) |
| 14443 | | entry->selection = entry->labelIndexLength - 1; |
| 14421 | entry->selection = entry->label_index_length - 1; |
| 14444 | 14422 | } |
| 14445 | 14423 | else |
| 14446 | 14424 | { |
| 14447 | | if(++entry->selection >= entry->labelIndexLength) |
| 14425 | if(++entry->selection >= entry->label_index_length) |
| 14448 | 14426 | entry->selection = 0; |
| 14449 | 14427 | } |
| 14450 | 14428 | |
| 14451 | 14429 | /* NOTE : in handling activatio key, forced to activate a cheat even if one shot */ |
| 14452 | | if(!(entry->flags & kCheatFlag_OneShot) && !(entry->labelIndex[entry->selection])) |
| 14430 | if(!(entry->flags & kCheatFlag_OneShot) && !(entry->label_index[entry->selection])) |
| 14453 | 14431 | DeactivateCheat(entry); |
| 14454 | 14432 | else |
| 14455 | 14433 | ActivateCheat(entry); |
| 14456 | 14434 | |
| 14457 | | if(TEST_FIELD(cheatOptions, ActivationKeyMessage)) |
| 14435 | if(TEST_FIELD(cheat_options, ActivationKeyMessage)) |
| 14458 | 14436 | { |
| 14459 | 14437 | if(!entry->selection) |
| 14460 | 14438 | ui_popup_time(1,"%s disabled", entry->name); |
| 14461 | 14439 | else |
| 14462 | | ui_popup_time(1,"%s : %s selected", entry->name, entry->actionList[entry->labelIndex[entry->selection]].optionalName); |
| 14440 | ui_popup_time(1,"%s : %s selected", entry->name, entry->action_list[entry->label_index[entry->selection]].optional_name); |
| 14463 | 14441 | } |
| 14464 | 14442 | } |
| 14465 | 14443 | } |
| r2821 | r2822 | |
| 14472 | 14450 | { |
| 14473 | 14451 | ActivateCheat(entry); |
| 14474 | 14452 | |
| 14475 | | if(TEST_FIELD(cheatOptions, ActivationKeyMessage)) |
| 14453 | if(TEST_FIELD(cheat_options, ActivationKeyMessage)) |
| 14476 | 14454 | ui_popup_time(1,"set %s", entry->name); |
| 14477 | 14455 | } |
| 14478 | 14456 | else if(entry->flags & kCheatFlag_Active) |
| 14479 | 14457 | { |
| 14480 | 14458 | DeactivateCheat(entry); |
| 14481 | 14459 | |
| 14482 | | if(TEST_FIELD(cheatOptions, ActivationKeyMessage)) |
| 14460 | if(TEST_FIELD(cheat_options, ActivationKeyMessage)) |
| 14483 | 14461 | ui_popup_time(1,"%s disabled", entry->name); |
| 14484 | 14462 | } |
| 14485 | 14463 | else |
| 14486 | 14464 | { |
| 14487 | 14465 | ActivateCheat(entry); |
| 14488 | 14466 | |
| 14489 | | if(TEST_FIELD(cheatOptions, ActivationKeyMessage)) |
| 14467 | if(TEST_FIELD(cheat_options, ActivationKeyMessage)) |
| 14490 | 14468 | ui_popup_time(1,"%s enabled", entry->name); |
| 14491 | 14469 | } |
| 14492 | 14470 | } |
| r2821 | r2822 | |
| 14495 | 14473 | /* ***** 2nd, do cheat actions ***** */ |
| 14496 | 14474 | |
| 14497 | 14475 | /* if "OFF", no action */ |
| 14498 | | if(!(entry->flags & kCheatFlag_Active)) |
| 14476 | if(driverSpecifiedFlag != 0 || (entry->flags & kCheatFlag_Active) == 0) |
| 14499 | 14477 | return; |
| 14500 | 14478 | |
| 14501 | 14479 | while(1) |
| 14502 | 14480 | { |
| 14503 | | if(entry->actionList[i].flags & kActionFlag_Custom) |
| 14481 | if(entry->action_list[i].flags & kActionFlag_Custom) |
| 14504 | 14482 | { |
| 14505 | | if(EXTRACT_FIELD(entry->actionList[i].type, CodeType) == kCustomCode_LabelSelect) |
| 14483 | if(EXTRACT_FIELD(entry->action_list[i].type, CodeType) == CUSTOM_CODE_LABEL_SELECT) |
| 14506 | 14484 | { |
| 14507 | | i = entry->labelIndex[entry->selection]; |
| 14485 | i = entry->label_index[entry->selection]; |
| 14508 | 14486 | isSelect = 1; |
| 14509 | 14487 | continue; |
| 14510 | 14488 | } |
| 14511 | 14489 | else |
| 14512 | 14490 | i++; |
| 14513 | 14491 | } |
| 14514 | | else if((entry->actionList[i].flags & kActionFlag_OperationDone) || (entry->actionList[i].flags & kActionFlag_NoAction)) |
| 14492 | else if((entry->action_list[i].flags & kActionFlag_OperationDone) || (entry->action_list[i].flags & kActionFlag_NoAction)) |
| 14515 | 14493 | { |
| 14516 | 14494 | i++; |
| 14517 | 14495 | } |
| 14518 | | else if(entry->actionList[i].flags & kActionFlag_OldFormat) |
| 14496 | else if(entry->action_list[i].flags & kActionFlag_OldFormat) |
| 14519 | 14497 | { |
| 14520 | | int tempType = entry->actionList[i].type; |
| 14498 | int tempType = entry->action_list[i].type; |
| 14521 | 14499 | int j = i; |
| 14522 | 14500 | |
| 14523 | | entry->actionList[i].type = ConvertToNewCode(&entry->actionList[i]); |
| 14524 | | i = cheat_periodicAction(machine, &entry->actionList[i], i); |
| 14525 | | entry->actionList[j].type = tempType; |
| 14501 | entry->action_list[i].type = convert_to_new_code(&entry->action_list[i]); |
| 14502 | i = cheat_periodicAction(machine, &entry->action_list[i], i); |
| 14503 | entry->action_list[j].type = tempType; |
| 14526 | 14504 | } |
| 14527 | 14505 | else |
| 14528 | | i = cheat_periodicAction(machine, &entry->actionList[i], i); |
| 14506 | i = cheat_periodicAction(machine, &entry->action_list[i], i); |
| 14529 | 14507 | |
| 14530 | | if(i >= entry->actionListLength) |
| 14508 | if(i >= entry->action_list_length) |
| 14531 | 14509 | break; |
| 14532 | 14510 | |
| 14533 | | if(isSelect && EXTRACT_FIELD(entry->actionList[i].type, Link) != kLink_SubLink) |
| 14511 | if(isSelect && EXTRACT_FIELD(entry->action_list[i].type, Link) != kLink_SubLink) |
| 14534 | 14512 | break; |
| 14535 | 14513 | } |
| 14536 | 14514 | |
| r2821 | r2822 | |
| 14545 | 14523 | |
| 14546 | 14524 | while(1) |
| 14547 | 14525 | { |
| 14548 | | if(entry->actionList[i].flags & kActionFlag_Custom) |
| 14526 | if(entry->action_list[i].flags & kActionFlag_Custom) |
| 14549 | 14527 | { |
| 14550 | | if(EXTRACT_FIELD(entry->actionList[i].type, CodeType) == kCustomCode_LabelSelect) |
| 14528 | if(EXTRACT_FIELD(entry->action_list[i].type, CodeType) == CUSTOM_CODE_LABEL_SELECT) |
| 14551 | 14529 | { |
| 14552 | | i = entry->labelIndex[entry->selection]; |
| 14530 | i = entry->label_index[entry->selection]; |
| 14553 | 14531 | isSelect = 1; |
| 14554 | 14532 | continue; |
| 14555 | 14533 | } |
| 14556 | 14534 | } |
| 14557 | | else if(entry->actionList[i].flags & kActionFlag_NoAction) |
| 14535 | else if(entry->action_list[i].flags & kActionFlag_NoAction) |
| 14558 | 14536 | { |
| 14559 | 14537 | i++; |
| 14560 | 14538 | } |
| 14561 | | else if(!(entry->actionList[i].flags & kActionFlag_OperationDone)) |
| 14539 | else if(!(entry->action_list[i].flags & kActionFlag_OperationDone)) |
| 14562 | 14540 | { |
| 14563 | 14541 | done = 0; |
| 14564 | 14542 | i++; |
| r2821 | r2822 | |
| 14566 | 14544 | else |
| 14567 | 14545 | i++; |
| 14568 | 14546 | |
| 14569 | | if(i >= entry->actionListLength) |
| 14547 | if(i >= entry->action_list_length) |
| 14570 | 14548 | break; |
| 14571 | 14549 | |
| 14572 | | if(isSelect && EXTRACT_FIELD(entry->actionList[i].type, Link) != kLink_SubLink) |
| 14550 | if(isSelect && EXTRACT_FIELD(entry->action_list[i].type, Link) != kLink_SubLink) |
| 14573 | 14551 | break; |
| 14574 | 14552 | } |
| 14575 | 14553 | |
| r2821 | r2822 | |
| 14578 | 14556 | } |
| 14579 | 14557 | } |
| 14580 | 14558 | |
| 14581 | | /*------------------------------------------------------------------ |
| 14582 | | UpdateAllCheatInfo - update all cheat info when database loaded |
| 14583 | | ------------------------------------------------------------------*/ |
| 14559 | /*--------------------------------------------------------------------- |
| 14560 | update_all_cheat_info - update all cheat info when database loaded |
| 14561 | ---------------------------------------------------------------------*/ |
| 14584 | 14562 | |
| 14585 | | static void UpdateAllCheatInfo(void) |
| 14563 | static void update_all_cheat_info(void) |
| 14586 | 14564 | { |
| 14587 | 14565 | int i; |
| 14588 | 14566 | |
| 14589 | | /* update flags for all CheatEntry */ |
| 14590 | | for(i = 0; i < cheatListLength; i++) |
| 14567 | /* update flags for all cheat entry */ |
| 14568 | for(i = 0; i < cheat_list_length; i++) |
| 14591 | 14569 | { |
| 14592 | | UpdateCheatInfo(&cheatList[i], 1); |
| 14570 | update_cheat_info(&cheat_list[i], 1); |
| 14593 | 14571 | |
| 14594 | | if(cheatList[i].flags & kCheatFlag_Select) |
| 14595 | | BuildLabelIndexTable(&cheatList[i]); |
| 14572 | if(cheat_list[i].flags & kCheatFlag_Select) |
| 14573 | BuildLabelIndexTable(&cheat_list[i]); |
| 14596 | 14574 | } |
| 14597 | 14575 | |
| 14598 | 14576 | SetLayerIndex(); |
| 14599 | 14577 | } |
| 14600 | 14578 | |
| 14601 | | /*--------------------------------------------------------------------------------------------- |
| 14602 | | UpdateCheatInfo - check several fields on CheatEntry and CheatAction then set flags |
| 14603 | | "isLoadTime" parameter is set when called UpdateAllCheatInfo() right now |
| 14604 | | ---------------------------------------------------------------------------------------------*/ |
| 14579 | /*-------------------------------------------------------------------------------------------------- |
| 14580 | update_cheat_info - check several fields on cheat entry and cheat action then set flags |
| 14581 | "isLoadTime" parameter is set when called update_all_cheat_info() right now |
| 14582 | --------------------------------------------------------------------------------------------------*/ |
| 14605 | 14583 | |
| 14606 | | static void UpdateCheatInfo(CheatEntry * entry, UINT8 isLoadTime) |
| 14584 | static void update_cheat_info(cheat_entry *entry, UINT8 is_load_time) |
| 14607 | 14585 | { |
| 14608 | 14586 | int i; |
| 14609 | 14587 | int flags = 0; |
| 14610 | | UINT8 isOneShot = 1; |
| 14611 | | UINT8 isNull = 1; |
| 14612 | | UINT8 isSeparator = 1; |
| 14613 | | UINT8 isNewFormat = 1; |
| 14588 | UINT8 is_one_shot = 1; |
| 14589 | UINT8 is_null = 1; |
| 14590 | UINT8 is_separator = 1; |
| 14591 | UINT8 is_new_format = 1; |
| 14614 | 14592 | |
| 14615 | 14593 | flags = entry->flags & kCheatFlag_PersistentMask; |
| 14616 | 14594 | |
| 14617 | | for(i = 0; i < entry->actionListLength; i++) |
| 14595 | for(i = 0; i < entry->action_list_length; i++) |
| 14618 | 14596 | { |
| 14619 | | CheatAction * action = &entry->actionList[i]; |
| 14597 | cheat_action *action = &entry->action_list[i]; |
| 14620 | 14598 | |
| 14621 | | int actionFlags = action->flags & kActionFlag_PersistentMask; |
| 14599 | int action_flags = action->flags & kActionFlag_PersistentMask; |
| 14622 | 14600 | |
| 14623 | | action->region = EXTRACT_FIELD(action->type, CPURegion); |
| 14601 | if(TEST_FIELD(action->type, OneShot) == 0) |
| 14602 | is_one_shot = 0; |
| 14624 | 14603 | |
| 14625 | | if(actionFlags & kActionFlag_OldFormat) |
| 14604 | if(action_flags & kActionFlag_OldFormat) |
| 14626 | 14605 | { |
| 14627 | 14606 | if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom) && |
| 14628 | 14607 | (EXTRACT_FIELD(action->type, LocationParameter) == kCustomLocation_Select)) |
| 14629 | 14608 | flags |= kCheatFlag_Select; |
| 14630 | 14609 | |
| 14631 | 14610 | if(EXTRACT_FIELD(action->type, LocationType) != kLocation_Custom) |
| 14632 | | isNull = 0; |
| 14611 | is_null = 0; |
| 14633 | 14612 | |
| 14634 | | if(!TEST_FIELD(action->type, OneShot)) |
| 14635 | | isOneShot = 0; |
| 14636 | | |
| 14637 | 14613 | if(TEST_FIELD(action->type, UserSelectEnable)) |
| 14638 | 14614 | flags |= kCheatFlag_UserSelect; |
| 14639 | 14615 | |
| 14640 | 14616 | if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom) && |
| 14641 | 14617 | (EXTRACT_FIELD(action->type, LocationParameter) == kCustomLocation_Select)) |
| 14642 | | actionFlags |= kActionFlag_NoAction; |
| 14618 | action_flags |= kActionFlag_NoAction; |
| 14643 | 14619 | |
| 14644 | 14620 | if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed) || |
| 14645 | 14621 | ((EXTRACT_FIELD(action->type, LocationType) != kLocation_Custom) && |
| 14646 | 14622 | ((EXTRACT_FIELD(action->type, Operation) | EXTRACT_FIELD(action->type, OperationExtend) << 2) == 1))) |
| 14647 | | actionFlags |= kActionFlag_IndexAddress; |
| 14623 | action_flags |= kActionFlag_IndexAddress; |
| 14648 | 14624 | |
| 14649 | | if(i && entry->actionList[i-1].type == entry->actionList[i].type) |
| 14625 | if(i && entry->action_list[i-1].type == entry->action_list[i].type) |
| 14650 | 14626 | { |
| 14651 | | if( entry->actionList[i].address >= entry->actionList[i-1].address && |
| 14652 | | entry->actionList[i].address <= entry->actionList[i-1].address + 3) |
| 14653 | | actionFlags |= kActionFlag_NoAction; |
| 14627 | if( entry->action_list[i].address >= entry->action_list[i-1].address && |
| 14628 | entry->action_list[i].address <= entry->action_list[i-1].address + 3) |
| 14629 | action_flags |= kActionFlag_NoAction; |
| 14654 | 14630 | } |
| 14655 | 14631 | |
| 14656 | | isNewFormat = 0; |
| 14632 | is_new_format = 0; |
| 14633 | is_one_shot = 0; |
| 14657 | 14634 | } |
| 14658 | 14635 | else |
| 14659 | 14636 | { |
| 14660 | | if(action->region != CUSTOM_CODE) |
| 14637 | if(action->region < CUSTOM_CODE) |
| 14661 | 14638 | { |
| 14662 | 14639 | switch(EXTRACT_FIELD(action->type, CodeType)) |
| 14663 | 14640 | { |
| 14664 | 14641 | case kCodeType_PDWWrite: |
| 14665 | | actionFlags |= kActionFlag_PDWWrite; |
| 14642 | action_flags |= kActionFlag_PDWWrite; |
| 14666 | 14643 | break; |
| 14667 | 14644 | |
| 14645 | case kCodeType_IWrite: |
| 14646 | if(action->extend_data != ~0) |
| 14647 | action_flags |= kActionFlag_IndexAddress; |
| 14648 | if(EXTRACT_FIELD(action->type, CodeParameterUpper) == IWRITE_LIMITED_MASK) |
| 14649 | action_flags |= kActionFlag_LimitedMask; |
| 14650 | break; |
| 14651 | |
| 14652 | case kCodeType_CBit: |
| 14653 | action->flags |= kActionFlag_CheckCondition; |
| 14654 | if(EXTRACT_FIELD(action->type, CodeParameterUpper) == CBIT_LIMITED_MASK) |
| 14655 | action_flags |= kActionFlag_LimitedMask; |
| 14656 | break; |
| 14657 | |
| 14668 | 14658 | case kCodeType_RWrite: |
| 14669 | | actionFlags |= kActionFlag_Repeat; |
| 14659 | action_flags |= kActionFlag_Repeat; |
| 14670 | 14660 | break; |
| 14671 | 14661 | |
| 14672 | | case kCodeType_IWrite: |
| 14673 | 14662 | case kCodeType_Move: |
| 14674 | | case kCodeType_Loop: |
| 14675 | | if(action->extendData != ~0) |
| 14676 | | actionFlags |= kActionFlag_IndexAddress; |
| 14663 | if(action->extend_data != ~0) |
| 14664 | action_flags |= kActionFlag_IndexAddress; |
| 14677 | 14665 | break; |
| 14678 | 14666 | |
| 14679 | 14667 | case kCodeType_CWrite: |
| 14680 | 14668 | case kCodeType_Branch: |
| 14681 | | actionFlags |= kActionFlag_CheckCondition; |
| 14669 | action_flags |= kActionFlag_CheckCondition; |
| 14682 | 14670 | break; |
| 14683 | 14671 | |
| 14684 | | case kCodeType_VWrite: |
| 14685 | | flags |= kCheatFlag_UserSelect; |
| 14686 | | |
| 14687 | | if(action->extendData != ~0) |
| 14688 | | actionFlags |= kActionFlag_IndexAddress; |
| 14672 | case kCodeType_Popup: |
| 14673 | action_flags |= kActionFlag_CheckCondition; |
| 14689 | 14674 | break; |
| 14690 | 14675 | |
| 14691 | | case kCodeType_VRWrite: |
| 14692 | | flags |= kCheatFlag_UserSelect; |
| 14693 | | actionFlags |= kActionFlag_Repeat; |
| 14676 | if(action->extend_data != ~0) |
| 14677 | action_flags |= kActionFlag_IndexAddress; |
| 14694 | 14678 | break; |
| 14695 | 14679 | |
| 14696 | | case kCodeType_Popup: |
| 14697 | | actionFlags |= kActionFlag_CheckCondition; |
| 14698 | | |
| 14699 | | if(action->extendData != ~0) |
| 14700 | | actionFlags |= kActionFlag_IndexAddress; |
| 14701 | | break; |
| 14702 | | |
| 14703 | 14680 | case kCodeType_Watch: |
| 14704 | | actionFlags |= kActionFlag_NoAction; |
| 14681 | action_flags |= kActionFlag_NoAction; |
| 14705 | 14682 | break; |
| 14706 | 14683 | } |
| 14707 | 14684 | |
| 14708 | | isNull = 0; |
| 14709 | | isSeparator = 0; |
| 14685 | if(TEST_FIELD(action->type, ValueSelectEnable)) |
| 14686 | flags |= kCheatFlag_UserSelect; |
| 14687 | |
| 14688 | is_null = 0; |
| 14689 | is_separator = 0; |
| 14710 | 14690 | } |
| 14711 | 14691 | else |
| 14712 | 14692 | { |
| 14713 | 14693 | /* is label-select? */ |
| 14714 | | if(EXTRACT_FIELD(action->type, CodeType) == kCustomCode_LabelSelect) |
| 14694 | if(action->region == CUSTOM_CODE_LABEL_SELECT) |
| 14715 | 14695 | flags |= kCheatFlag_Select; |
| 14716 | 14696 | |
| 14717 | 14697 | /* is comment? */ |
| 14718 | | if(EXTRACT_FIELD(action->type, CodeType) != kCustomCode_Comment) |
| 14719 | | isNull = 0; |
| 14698 | if(action->region != CUSTOM_CODE_COMMENT) |
| 14699 | is_null = 0; |
| 14720 | 14700 | |
| 14721 | 14701 | /* is separator? */ |
| 14722 | | if(EXTRACT_FIELD(action->type, CodeType) != kCustomCode_Separator) |
| 14723 | | isSeparator = 0; |
| 14702 | if(action->region != CUSTOM_CODE_SEPARATOR) |
| 14703 | is_separator = 0; |
| 14724 | 14704 | |
| 14725 | 14705 | /* is layer index? */ |
| 14726 | | if(EXTRACT_FIELD(action->type, CodeType) == kCustomCode_Layer) |
| 14706 | if(action->region == CUSTOM_CODE_LAYER_TAG) |
| 14727 | 14707 | flags |= kCheatFlag_LayerIndex; |
| 14728 | 14708 | |
| 14729 | | actionFlags |= kActionFlag_NoAction; |
| 14730 | | actionFlags |= kActionFlag_Custom; |
| 14709 | action_flags |= kActionFlag_NoAction; |
| 14710 | action_flags |= kActionFlag_Custom; |
| 14731 | 14711 | } |
| 14732 | | |
| 14733 | | /* is one shot? */ |
| 14734 | | if(!TEST_FIELD(action->type, OneShot)) |
| 14735 | | isOneShot = 0; |
| 14736 | 14712 | } |
| 14737 | 14713 | |
| 14738 | | action->flags = actionFlags; |
| 14714 | action->flags = action_flags; |
| 14739 | 14715 | } |
| 14740 | 14716 | |
| 14741 | | /* one shot is set if "ALL" actions are not an one shot */ |
| 14742 | | if(isOneShot) |
| 14717 | if(is_new_format == 0) |
| 14718 | flags |= kCheatFlag_OldFormat; |
| 14719 | |
| 14720 | if(is_one_shot) |
| 14743 | 14721 | flags |= kCheatFlag_OneShot; |
| 14744 | 14722 | |
| 14745 | | if(isNull) |
| 14723 | if(is_null) |
| 14746 | 14724 | { |
| 14747 | | if(entry->actionListLength > 1) |
| 14725 | if(entry->action_list_length > 1) |
| 14748 | 14726 | flags |= kCheatFlag_ExtendComment; |
| 14749 | 14727 | else |
| 14750 | 14728 | flags |= kCheatFlag_Null; |
| 14751 | 14729 | } |
| 14752 | 14730 | |
| 14753 | | if(isSeparator) |
| 14731 | if(is_new_format) |
| 14754 | 14732 | { |
| 14755 | | flags |= kCheatFlag_Null; |
| 14756 | | flags |= kCheatFlag_Separator; |
| 14733 | if(is_separator) |
| 14734 | { |
| 14735 | flags |= kCheatFlag_Null; |
| 14736 | flags |= kCheatFlag_Separator; |
| 14737 | } |
| 14757 | 14738 | } |
| 14758 | 14739 | |
| 14759 | | if(isNewFormat == 0) |
| 14760 | | flags |= kCheatFlag_OldFormat; |
| 14761 | | |
| 14762 | 14740 | entry->flags = (flags & kCheatFlag_InfoMask) | (entry->flags & ~kCheatFlag_InfoMask); |
| 14763 | 14741 | |
| 14764 | | /* clear dirty flag as "this entry has already exist in the database" when loaded from a database */ |
| 14765 | | if(isLoadTime) |
| 14742 | /* clear dirty flag */ |
| 14743 | if(is_load_time) |
| 14766 | 14744 | entry->flags &= ~kCheatFlag_Dirty; |
| 14767 | 14745 | |
| 14768 | | CheckCodeFormat(entry); |
| 14746 | check_code_format(entry); |
| 14769 | 14747 | } |
| 14770 | 14748 | |
| 14771 | 14749 | /*-------------------- |
| 14772 | 14750 | AnalyseCodeFormat |
| 14773 | 14751 | --------------------*/ |
| 14774 | 14752 | |
| 14775 | | static UINT32 AnalyseCodeFormat(CheatEntry * entry, CheatAction * action) |
| 14753 | static UINT32 AnalyseCodeFormat(cheat_entry *entry, cheat_action *action) |
| 14776 | 14754 | { |
| 14777 | 14755 | UINT32 errorFlag = 0; |
| 14778 | 14756 | |
| r2821 | r2822 | |
| 14812 | 14790 | |
| 14813 | 14791 | if(TEST_FIELD(action->type, UserSelectEnable)) |
| 14814 | 14792 | { |
| 14815 | | if(!action->originalDataField) |
| 14793 | if(!action->original_data) |
| 14816 | 14794 | errorFlag |= kErrorFlag_NoSelectableValue; |
| 14817 | 14795 | } |
| 14818 | 14796 | |
| 14819 | 14797 | if(type == kLocation_Custom && parameter == kCustomLocation_Select) |
| 14820 | 14798 | { |
| 14821 | | if(entry->actionListLength == 1) |
| 14799 | if(entry->action_list_length == 1) |
| 14822 | 14800 | errorFlag |= kErrorFlag_NoLabel; |
| 14823 | 14801 | |
| 14824 | | if(action->originalDataField) |
| 14802 | if(action->original_data) |
| 14825 | 14803 | errorFlag |= kErrorFlag_InvalidDataField; |
| 14826 | 14804 | |
| 14827 | | if(action->extendData) |
| 14805 | if(action->extend_data) |
| 14828 | 14806 | errorFlag |= kErrorFlag_InvalidExtendDataField; |
| 14829 | 14807 | } |
| 14830 | 14808 | |
| r2821 | r2822 | |
| 14832 | 14810 | { |
| 14833 | 14811 | if(type == kLocation_Standard) |
| 14834 | 14812 | { |
| 14835 | | if(!action->extendData || action->extendData == 0xFF || action->extendData == 0xFFFF || action->extendData == 0xFFFFFF) |
| 14813 | if(!action->extend_data || action->extend_data == 0xFF || action->extend_data == 0xFFFF || action->extend_data == 0xFFFFFF) |
| 14836 | 14814 | errorFlag |= kErrorFlag_InvalidExtendDataField; |
| 14837 | 14815 | } |
| 14838 | 14816 | else if(type == kLocation_MemoryRegion) |
| 14839 | 14817 | { |
| 14840 | | if(action->extendData != ~0) |
| 14818 | if(action->extend_data != ~0) |
| 14841 | 14819 | errorFlag |= kErrorFlag_InvalidExtendDataField; |
| 14842 | 14820 | } |
| 14843 | 14821 | } |
| r2821 | r2822 | |
| 14849 | 14827 | UINT8 codeType = EXTRACT_FIELD(action->type, CodeType); |
| 14850 | 14828 | UINT8 codeParameter = EXTRACT_FIELD(action->type, CodeParameter); |
| 14851 | 14829 | |
| 14852 | | if(codeType >= kCodeType_Unused1 && codeType <= kCodeType_Unused4) |
| 14830 | if(codeType >= kCodeType_Unused) |
| 14853 | 14831 | errorFlag |= kErrorFlag_InvalidCodeType; |
| 14854 | 14832 | |
| 14855 | 14833 | if(action->flags & kActionFlag_CheckCondition) |
| r2821 | r2822 | |
| 14864 | 14842 | errorFlag |= kErrorFlag_ForbittenVariable; |
| 14865 | 14843 | } |
| 14866 | 14844 | |
| 14867 | | if(EXTRACT_FIELD(action->type, Link) == kLink_CopyLink) |
| 14845 | if(action->region >= REGION_CPU1 || EXTRACT_FIELD(action->type, AddressSpace) == kAddressSpace_OpcodeRAM) |
| 14868 | 14846 | { |
| 14869 | | if(!entry->flags & kCheatFlag_UserSelect) |
| 14870 | | errorFlag |= kErrorFlag_CopyLinkWithoutSelect; |
| 14871 | | } |
| 14872 | | |
| 14873 | | if( TEST_FIELD(action->region, RegionFlag) || |
| 14874 | | EXTRACT_FIELD(action->type, AddressSpace) == kAddressSpace_OpcodeRAM) |
| 14875 | | { |
| 14876 | 14847 | if(!TEST_FIELD(action->type, RestoreValue)) |
| 14877 | 14848 | errorFlag |= kErrorFlag_NoRestorePreviousValue; |
| 14878 | 14849 | } |
| 14879 | 14850 | |
| 14880 | | if( EXTRACT_FIELD(action->type, CodeType) == kCodeType_VWrite || |
| 14881 | | EXTRACT_FIELD(action->type, CodeType) == kCodeType_VRWrite) |
| 14851 | if(action->flags & kActionFlag_LimitedMask) |
| 14882 | 14852 | { |
| 14883 | | if(!action->originalDataField) |
| 14884 | | errorFlag |= kErrorFlag_NoSelectableValue; |
| 14853 | if(EXTRACT_FIELD(action->type, AddressSize) > kSearchSize_16Bit) |
| 14854 | errorFlag |= kErrorFlag_InvalidLimitedMaskSize; |
| 14885 | 14855 | } |
| 14886 | 14856 | |
| 14887 | 14857 | if(action->flags & kActionFlag_Repeat) |
| 14888 | 14858 | { |
| 14889 | | if(!EXTRACT_FIELD(action->extendData, LSB16)) |
| 14859 | if(!EXTRACT_FIELD(action->extend_data, LSB16)) |
| 14890 | 14860 | errorFlag |= kErrorFlag_NoRepeatCount; |
| 14891 | 14861 | } |
| 14892 | 14862 | |
| r2821 | r2822 | |
| 14907 | 14877 | |
| 14908 | 14878 | if(codeType == kCodeType_Write) |
| 14909 | 14879 | { |
| 14910 | | if(!action->extendData || action->extendData == 0xFF || action->extendData == 0xFFFF || action->extendData == 0xFFFFFF) |
| 14880 | if(!action->extend_data || action->extend_data == 0xFF || action->extend_data == 0xFFFF || action->extend_data == 0xFFFFFF) |
| 14911 | 14881 | errorFlag |= kErrorFlag_InvalidExtendDataField; |
| 14912 | 14882 | } |
| 14913 | 14883 | |
| 14914 | | if(!(action->flags & kActionFlag_Custom)) |
| 14884 | if((action->flags & kActionFlag_Custom) == 0) |
| 14915 | 14885 | { |
| 14916 | | if(TEST_FIELD(action->region, RegionFlag)) |
| 14886 | if(action->region < REGION_INVALID) |
| 14917 | 14887 | { |
| 14918 | | UINT8 region = EXTRACT_FIELD(action->region, RegionIndex); |
| 14919 | | |
| 14920 | | if(region >= REGION_MAX) errorFlag |= kErrorFlag_OutOfCPURegion; |
| 14921 | | else if(!region_info_list[region].type) errorFlag |= kErrorFlag_InvalidCPURegion; |
| 14922 | | else if(!IsAddressInRange(action, memory_region_length(action->region))) |
| 14923 | | errorFlag |= kErrorFlag_RegionOutOfRange; |
| 14924 | | } |
| 14925 | | else |
| 14926 | | { |
| 14927 | 14888 | UINT8 cpu = EXTRACT_FIELD(action->region, CPUIndex); |
| 14928 | 14889 | |
| 14929 | | if(!VALID_CPU(cpu)) |
| 14890 | if(VALID_CPU(cpu) == 0) |
| 14930 | 14891 | errorFlag |= kErrorFlag_OutOfCPURegion; |
| 14931 | 14892 | else if(cpu_info_list[cpu].type == 0) |
| 14932 | 14893 | errorFlag |= kErrorFlag_InvalidCPURegion; |
| r2821 | r2822 | |
| 14934 | 14895 | if(EXTRACT_FIELD(action->type, AddressSpace) > kAddressSpace_EEPROM) |
| 14935 | 14896 | errorFlag |= kErrorFlag_InvalidAddressSpace; |
| 14936 | 14897 | } |
| 14898 | else |
| 14899 | { |
| 14900 | UINT8 region = action->region - REGION_INVALID; |
| 14901 | |
| 14902 | if(region >= REGION_MAX) errorFlag |= kErrorFlag_OutOfCPURegion; |
| 14903 | else if(!region_info_list[region].type) errorFlag |= kErrorFlag_InvalidCPURegion; |
| 14904 | else if(!is_address_in_range(action, memory_region_length(action->region))) |
| 14905 | errorFlag |= kErrorFlag_RegionOutOfRange; |
| 14906 | } |
| 14937 | 14907 | } |
| 14938 | 14908 | } |
| 14939 | 14909 | else |
| 14940 | 14910 | { |
| 14941 | | if(EXTRACT_FIELD(action->type, CodeParameter) >= kCustomCode_Unused1) |
| 14911 | if(EXTRACT_FIELD(action->type, CodeParameter) >= CUSTOM_CODE_UNUSED_1) |
| 14942 | 14912 | errorFlag |= kErrorFlag_InvalidCustomCode; |
| 14943 | 14913 | } |
| 14944 | 14914 | } |
| r2821 | r2822 | |
| 14946 | 14916 | return errorFlag; |
| 14947 | 14917 | } |
| 14948 | 14918 | |
| 14949 | | /*---------------------------------------- |
| 14950 | | CheckCodeFormat - code format checker |
| 14951 | | ----------------------------------------*/ |
| 14919 | /*------------------------------------------ |
| 14920 | check_code_format - code format checker |
| 14921 | ------------------------------------------*/ |
| 14952 | 14922 | |
| 14953 | | static void CheckCodeFormat(CheatEntry * entry) |
| 14923 | static void check_code_format(cheat_entry *entry) |
| 14954 | 14924 | { |
| 14955 | 14925 | int i; |
| 14956 | | UINT8 isError = 0; |
| 14926 | UINT8 is_error = 0; |
| 14957 | 14927 | |
| 14958 | | for(i = 0; i < entry->actionListLength; i++) |
| 14928 | for(i = 0; i < entry->action_list_length; i++) |
| 14959 | 14929 | { |
| 14960 | | CheatAction * action = &entry->actionList[i]; |
| 14930 | cheat_action *action = &entry->action_list[i]; |
| 14961 | 14931 | |
| 14962 | 14932 | if(AnalyseCodeFormat(entry, action)) |
| 14963 | | isError = 1; |
| 14933 | is_error = 1; |
| 14964 | 14934 | } |
| 14965 | 14935 | |
| 14966 | | if(isError) |
| 14936 | if(is_error) |
| 14967 | 14937 | { |
| 14968 | 14938 | entry->flags |= kCheatFlag_HasWrongCode; |
| 14969 | | messageType = kCheatMessage_WrongCode; |
| 14970 | | messageTimer = DEFAULT_MESSAGE_TIME; |
| 14939 | SET_MESSAGE(kCheatMessage_WrongCode); |
| 14971 | 14940 | } |
| 14972 | 14941 | } |
| 14973 | 14942 | |
| r2821 | r2822 | |
| 14975 | 14944 | BuildLabelIndexTable - create index table for label-selection and calculate index table length |
| 14976 | 14945 | -------------------------------------------------------------------------------------------------*/ |
| 14977 | 14946 | |
| 14978 | | static void BuildLabelIndexTable(CheatEntry *entry) |
| 14947 | static void BuildLabelIndexTable(cheat_entry *entry) |
| 14979 | 14948 | { |
| 14980 | 14949 | int i, j, length = 0; |
| 14981 | 14950 | |
| 14982 | | entry->labelIndexLength = 0; |
| 14951 | entry->label_index_length = 0; |
| 14983 | 14952 | |
| 14984 | | for(i = 0, j = 0; i < entry->actionListLength; i++) |
| 14953 | for(i = 0, j = 0; i < entry->action_list_length; i++) |
| 14985 | 14954 | { |
| 14986 | | CheatAction * action = &entry->actionList[i]; |
| 14955 | cheat_action *action = &entry->action_list[i]; |
| 14987 | 14956 | |
| 14988 | | if((action->flags && kActionFlag_Custom) && EXTRACT_FIELD(action->type, CodeType) == kCustomCode_LabelSelect) |
| 14957 | if((action->flags && kActionFlag_Custom) && EXTRACT_FIELD(action->type, CodeType) == CUSTOM_CODE_LABEL_SELECT) |
| 14989 | 14958 | { |
| 14990 | | entry->labelIndex = malloc_or_die(sizeof(entry->labelIndex) * (++entry->labelIndexLength + 1)); |
| 14991 | | entry->labelIndex[j++] = i; |
| 14959 | entry->label_index = malloc_or_die(sizeof(entry->label_index) * (++entry->label_index_length + 1)); |
| 14960 | entry->label_index[j++] = i; |
| 14992 | 14961 | |
| 14993 | | length = action->data ? action->data + i : entry->actionListLength; |
| 14962 | length = action->data ? action->data + i : entry->action_list_length; |
| 14994 | 14963 | } |
| 14995 | 14964 | else if(EXTRACT_FIELD(action->type, Link) == kLink_Link) |
| 14996 | 14965 | { |
| 14997 | 14966 | if(length) |
| 14998 | 14967 | { |
| 14999 | | entry->labelIndex = realloc(entry->labelIndex, sizeof(entry->labelIndex) * (++entry->labelIndexLength + 1)); |
| 15000 | | entry->labelIndex[j++] = i; |
| 14968 | entry->label_index = realloc(entry->label_index, sizeof(entry->label_index) * (++entry->label_index_length + 1)); |
| 14969 | entry->label_index[j++] = i; |
| 15001 | 14970 | } |
| 15002 | 14971 | } |
| 15003 | 14972 | } |
| 15004 | 14973 | |
| 15005 | | if(entry->labelIndexLength <= 1) |
| 14974 | if(entry->label_index_length <= 1) |
| 15006 | 14975 | { |
| 15007 | 14976 | logerror("cheat - BuildLabelIndexTable : %s fails to build due to invalid or no link\n", entry->name); |
| 15008 | 14977 | return; |
| r2821 | r2822 | |
| 15011 | 14980 | if(entry->flags & kCheatFlag_OneShot) |
| 15012 | 14981 | entry->selection = 1; |
| 15013 | 14982 | |
| 15014 | | //logerror("Cheat - Finish building index table for %s (length = %x)\n", entry->name, entry->labelIndexLength); |
| 15015 | | //for(i = 0; i < entry->labelIndexLength; i++) |
| 15016 | | // logerror("IndexTable[%x] = %x\n",i,entry->labelIndex[i]); |
| 14983 | //logerror("Cheat - Finish building index table for %s (length = %x)\n", entry->name, entry->label_index_length); |
| 14984 | //for(i = 0; i < entry->label_index_length; i++) |
| 14985 | // logerror("IndexTable[%x] = %x\n",i,entry->label_index[i]); |
| 15017 | 14986 | |
| 15018 | 14987 | } |
| 15019 | 14988 | |
| r2821 | r2822 | |
| 15025 | 14994 | { |
| 15026 | 14995 | int i, j; |
| 15027 | 14996 | |
| 15028 | | for(i = 0; i < cheatListLength; i++) |
| 14997 | for(i = 0; i < cheat_list_length; i++) |
| 15029 | 14998 | { |
| 15030 | | CheatEntry * entry = &cheatList[i]; |
| 14999 | cheat_entry *entry = &cheat_list[i]; |
| 15031 | 15000 | |
| 15032 | 15001 | if(entry->flags & kCheatFlag_LayerIndex) |
| 15033 | 15002 | { |
| 15034 | | int length = entry->actionList[0].extendData; |
| 15003 | int length = entry->action_list[0].extend_data; |
| 15035 | 15004 | |
| 15036 | | if(length < cheatListLength && (i + length) <= cheatListLength) |
| 15005 | if(length < cheat_list_length && (i + length) <= cheat_list_length) |
| 15037 | 15006 | { |
| 15038 | | entry->layerIndex = entry->actionList[0].address; |
| 15007 | entry->layer_index = entry->action_list[0].address; |
| 15039 | 15008 | |
| 15040 | 15009 | for(j = i + 1; j <= i + length; j++) |
| 15041 | 15010 | { |
| 15042 | | CheatEntry * traverse = &cheatList[j]; |
| 15011 | cheat_entry *traverse = &cheat_list[j]; |
| 15043 | 15012 | |
| 15044 | 15013 | if(!(traverse->flags & kCheatFlag_LayerIndex)) |
| 15045 | | traverse->layerIndex = entry->actionList[0].data; |
| 15014 | traverse->layer_index = entry->action_list[0].data; |
| 15046 | 15015 | } |
| 15047 | 15016 | } |
| 15048 | 15017 | } |
| r2821 | r2822 | |
| 15079 | 15048 | "there are no old values!", |
| 15080 | 15049 | "saved all memory regions", |
| 15081 | 15050 | "region invalidated remains results are", |
| 15082 | | "debug mode only!", |
| 15051 | "failed to allocate memory!", |
| 15083 | 15052 | "found wrong code!" }; |
| 15084 | 15053 | |
| 15085 | 15054 | char buf[64]; |
| 15086 | 15055 | |
| 15087 | | if(!messageType) |
| 15056 | if(message_type == 0) |
| 15088 | 15057 | return; |
| 15089 | 15058 | |
| 15090 | | switch(messageType) |
| 15059 | switch(message_type) |
| 15091 | 15060 | { |
| 15092 | 15061 | /* simple message */ |
| 15093 | 15062 | default: |
| 15094 | | sprintf(buf, "%s", kCheatMessageTable[messageType]); |
| 15063 | sprintf(buf, "%s", kCheatMessageTable[message_type]); |
| 15095 | 15064 | break; |
| 15096 | 15065 | |
| 15097 | 15066 | /* message with data */ |
| r2821 | r2822 | |
| 15100 | 15069 | { |
| 15101 | 15070 | search_info *search = get_current_search(); |
| 15102 | 15071 | |
| 15103 | | sprintf(buf, "%d %s", search->num_results, kCheatMessageTable[messageType]); |
| 15072 | sprintf(buf, "%d %s", search->num_results, kCheatMessageTable[message_type]); |
| 15104 | 15073 | } |
| 15105 | 15074 | break; |
| 15106 | 15075 | |
| 15107 | 15076 | case kCheatMessage_AllCheatSaved: |
| 15108 | | sprintf(buf, "%d %s", cheatListLength, kCheatMessageTable[messageType]); |
| 15077 | sprintf(buf, "%d %s", cheat_list_length, kCheatMessageTable[message_type]); |
| 15109 | 15078 | break; |
| 15110 | 15079 | } |
| 15111 | 15080 | |
| 15112 | 15081 | /* draw it */ |
| 15113 | | switch(messageType) |
| 15082 | switch(message_type) |
| 15114 | 15083 | { |
| 15115 | 15084 | default: |
| 15116 | 15085 | ui_draw_text_box(buf, JUSTIFY_CENTER, 0.5f, 0.9f, UI_FILLCOLOR); |
| r2821 | r2822 | |
| 15125 | 15094 | case kCheatMessage_NoSearchRegion: |
| 15126 | 15095 | case kCheatMessage_NoOldValue: |
| 15127 | 15096 | case kCheatMessage_Max: |
| 15128 | | case kCheatMessage_DebugOnly: |
| 15097 | case kCheatMessage_FailedToAllocate: |
| 15129 | 15098 | case kCheatMessage_WrongCode: |
| 15130 | 15099 | /* warning message has red background color */ |
| 15131 | 15100 | ui_draw_text_box(buf, JUSTIFY_CENTER, 0.5f, 0.9f, UI_REDCOLOR); |
| r2821 | r2822 | |
| 15133 | 15102 | } |
| 15134 | 15103 | |
| 15135 | 15104 | /* decrement message timer */ |
| 15136 | | if(--messageTimer == 0) |
| 15137 | | messageType = 0; |
| 15105 | if(--message_timer == 0) |
| 15106 | message_type = 0; |
| 15138 | 15107 | } |
| 15139 | 15108 | |
| 15140 | 15109 | /*--------------------- |
| r2821 | r2822 | |
| 15151 | 15120 | return info->address_chars_needed; |
| 15152 | 15121 | } |
| 15153 | 15122 | |
| 15154 | | return 8; |
| 15123 | return DEFAULT_ADDRESS_LENGTH; |
| 15155 | 15124 | } |
| 15156 | 15125 | |
| 15157 | 15126 | /*------------------ |
| r2821 | r2822 | |
| 15160 | 15129 | |
| 15161 | 15130 | static char *get_region_name(UINT8 region) |
| 15162 | 15131 | { |
| 15163 | | if(TEST_FIELD(region, RegionIndex)) |
| 15132 | if(region < REGION_INVALID) |
| 15164 | 15133 | { |
| 15165 | | if(region >= REGION_INVALID && region < REGION_MAX) |
| 15166 | | return (char *)kRegionNames[EXTRACT_FIELD(region, RegionIndex)]; |
| 15134 | if(VALID_CPU(region)) |
| 15135 | return (char *)kRegionNames[EXTRACT_FIELD(region, CPUIndex) + 1]; |
| 15167 | 15136 | } |
| 15168 | 15137 | else |
| 15169 | 15138 | { |
| 15170 | | if(VALID_CPU(region)) |
| 15171 | | return (char *)kRegionNames[EXTRACT_FIELD(region, CPUIndex) + 1]; |
| 15139 | if(region < REGION_MAX) |
| 15140 | return (char *)kRegionNames[region - REGION_INVALID]; |
| 15172 | 15141 | } |
| 15173 | 15142 | |
| 15174 | 15143 | return (char *)kRegionNames[0]; |