+ else if ((pc & 0xfffff000) == 0xc0000000) {
+ // data array
+ ret = sh2s[is_slave].data_array;
+ mask = 0xfff;
+ }
+ else if ((pc & 0xc6000000) == 0x06000000) {
+ // SDRAM
+ ret = Pico32xMem->sdram;
+ mask = 0x03ffff;
+ }
+ else if ((pc & 0xc6000000) == 0x02000000) {
+ // ROM
+ if ((pc & 0x3fffff) < Pico.romsize)
+ ret = Pico.rom;
+ mask = 0x3fffff;
+ }
+
+ if (ret == NULL)
+ return (void *)-1; // NULL is valid value
+
+ return (char *)ret - (pc & ~mask);
+}
+
+void scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out,
+ u32 *end_literals_out)
+{
+ u16 *dr_pc_base;
+ u32 pc, op, tmp;
+ u32 end_pc, end_literals = 0;
+ u32 lowest_mova = 0;
+ struct op_data *opd;
+ int next_is_delay = 0;
+ int end_block = 0;
+ int i, i_end;
+
+ memset(op_flags, 0, BLOCK_INSN_LIMIT);
+
+ dr_pc_base = dr_get_pc_base(base_pc, is_slave);
+
+ // 1st pass: disassemble
+ for (i = 0, pc = base_pc; ; i++, pc += 2) {
+ // we need an ops[] entry after the last one initialized,
+ // so do it before end_block checks
+ opd = &ops[i];
+ opd->op = OP_UNHANDLED;
+ opd->rm = -1;
+ opd->source = opd->dest = 0;
+ opd->cycles = 1;
+ opd->imm = 0;
+
+ if (next_is_delay) {
+ op_flags[i] |= OF_DELAY_OP;
+ next_is_delay = 0;
+ }
+ else if (end_block || i >= BLOCK_INSN_LIMIT - 2)
+ break;
+
+ op = FETCH_OP(pc);
+ switch ((op & 0xf000) >> 12)
+ {
+ /////////////////////////////////////////////
+ case 0x00:
+ switch (op & 0x0f)
+ {
+ case 0x02:
+ switch (GET_Fx())
+ {
+ case 0: // STC SR,Rn 0000nnnn00000010
+ tmp = SHR_SR;
+ break;
+ case 1: // STC GBR,Rn 0000nnnn00010010
+ tmp = SHR_GBR;
+ break;
+ case 2: // STC VBR,Rn 0000nnnn00100010
+ tmp = SHR_VBR;
+ break;
+ default:
+ goto undefined;
+ }
+ opd->op = OP_MOVE;
+ opd->source = BITMASK1(tmp);
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x03:
+ CHECK_UNHANDLED_BITS(0xd0, undefined);
+ // BRAF Rm 0000mmmm00100011
+ // BSRF Rm 0000mmmm00000011
+ opd->op = OP_BRANCH_RF;
+ opd->rm = GET_Rn();
+ opd->source = BITMASK1(opd->rm);
+ opd->dest = BITMASK1(SHR_PC);
+ if (!(op & 0x20))
+ opd->dest |= BITMASK1(SHR_PR);
+ opd->cycles = 2;
+ next_is_delay = 1;
+ end_block = 1;
+ break;
+ case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
+ case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
+ case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
+ opd->source = BITMASK3(GET_Rm(), SHR_R0, GET_Rn());
+ break;
+ case 0x07:
+ // MUL.L Rm,Rn 0000nnnnmmmm0111
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(SHR_MACL);
+ opd->cycles = 2;
+ break;
+ case 0x08:
+ CHECK_UNHANDLED_BITS(0xf00, undefined);
+ switch (GET_Fx())
+ {
+ case 0: // CLRT 0000000000001000
+ opd->op = OP_SETCLRT;
+ opd->dest = BITMASK1(SHR_T);
+ opd->imm = 0;
+ break;
+ case 1: // SETT 0000000000011000
+ opd->op = OP_SETCLRT;
+ opd->dest = BITMASK1(SHR_T);
+ opd->imm = 1;
+ break;
+ case 2: // CLRMAC 0000000000101000
+ opd->dest = BITMASK3(SHR_T, SHR_MACL, SHR_MACH);
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x09:
+ switch (GET_Fx())
+ {
+ case 0: // NOP 0000000000001001
+ CHECK_UNHANDLED_BITS(0xf00, undefined);
+ break;
+ case 1: // DIV0U 0000000000011001
+ CHECK_UNHANDLED_BITS(0xf00, undefined);
+ opd->dest = BITMASK2(SHR_SR, SHR_T);
+ break;
+ case 2: // MOVT Rn 0000nnnn00101001
+ opd->source = BITMASK1(SHR_T);
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x0a:
+ switch (GET_Fx())
+ {
+ case 0: // STS MACH,Rn 0000nnnn00001010
+ tmp = SHR_MACH;
+ break;
+ case 1: // STS MACL,Rn 0000nnnn00011010
+ tmp = SHR_MACL;
+ break;
+ case 2: // STS PR,Rn 0000nnnn00101010
+ tmp = SHR_PR;
+ break;
+ default:
+ goto undefined;
+ }
+ opd->op = OP_MOVE;
+ opd->source = BITMASK1(tmp);
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x0b:
+ CHECK_UNHANDLED_BITS(0xf00, undefined);
+ switch (GET_Fx())
+ {
+ case 0: // RTS 0000000000001011
+ opd->op = OP_BRANCH_R;
+ opd->rm = SHR_PR;
+ opd->source = BITMASK1(opd->rm);
+ opd->dest = BITMASK1(SHR_PC);
+ opd->cycles = 2;
+ next_is_delay = 1;
+ end_block = 1;
+ break;
+ case 1: // SLEEP 0000000000011011
+ opd->op = OP_SLEEP;
+ end_block = 1;
+ break;
+ case 2: // RTE 0000000000101011
+ opd->op = OP_RTE;
+ opd->source = BITMASK1(SHR_SP);
+ opd->dest = BITMASK2(SHR_SR, SHR_PC);
+ opd->cycles = 4;
+ next_is_delay = 1;
+ end_block = 1;
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
+ case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
+ case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
+ opd->source = BITMASK2(GET_Rm(), SHR_R0);
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
+ opd->source = BITMASK5(GET_Rm(), GET_Rn(), SHR_SR, SHR_MACL, SHR_MACH);
+ opd->dest = BITMASK4(GET_Rm(), GET_Rn(), SHR_MACL, SHR_MACH);
+ opd->cycles = 3;
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x01:
+ // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
+ opd->source = BITMASK1(GET_Rm());
+ opd->source = BITMASK1(GET_Rn());
+ opd->imm = (op & 0x0f) * 4;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x02:
+ switch (op & 0x0f)
+ {
+ case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
+ case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
+ case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
+ opd->source = BITMASK1(GET_Rm());
+ opd->source = BITMASK1(GET_Rn());
+ break;
+ case 0x04: // MOV.B Rm,@-Rn 0010nnnnmmmm0100
+ case 0x05: // MOV.W Rm,@-Rn 0010nnnnmmmm0101
+ case 0x06: // MOV.L Rm,@-Rn 0010nnnnmmmm0110
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(SHR_SR);
+ break;
+ case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(SHR_T);
+ break;
+ case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
+ case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
+ case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(SHR_T);
+ break;
+ case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
+ case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(SHR_MACL);
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x03:
+ switch (op & 0x0f)
+ {
+ case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
+ case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
+ case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
+ case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
+ case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(SHR_T);
+ break;
+ case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
+ opd->source = BITMASK3(GET_Rm(), GET_Rn(), SHR_SR);
+ opd->dest = BITMASK2(GET_Rn(), SHR_SR);
+ break;
+ case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
+ case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK2(SHR_MACL, SHR_MACH);
+ opd->cycles = 2;
+ break;
+ case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
+ case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
+ case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
+ opd->source = BITMASK3(GET_Rm(), GET_Rn(), SHR_T);
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
+ case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
+ opd->source = BITMASK2(GET_Rm(), GET_Rn());
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x04:
+ switch (op & 0x0f)
+ {
+ case 0x00:
+ switch (GET_Fx())
+ {
+ case 0: // SHLL Rn 0100nnnn00000000
+ case 2: // SHAL Rn 0100nnnn00100000
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ case 1: // DT Rn 0100nnnn00010000
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x01:
+ switch (GET_Fx())
+ {
+ case 0: // SHLR Rn 0100nnnn00000001
+ case 2: // SHAR Rn 0100nnnn00100001
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ case 1: // CMP/PZ Rn 0100nnnn00010001
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK1(SHR_T);
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x02:
+ case 0x03:
+ switch (op & 0x3f)
+ {
+ case 0x02: // STS.L MACH,@-Rn 0100nnnn00000010
+ tmp = SHR_MACH;
+ break;
+ case 0x12: // STS.L MACL,@-Rn 0100nnnn00010010
+ tmp = SHR_MACL;
+ break;
+ case 0x22: // STS.L PR,@-Rn 0100nnnn00100010
+ tmp = SHR_PR;
+ break;
+ case 0x03: // STC.L SR,@-Rn 0100nnnn00000011
+ tmp = SHR_SR;
+ opd->cycles = 2;
+ break;
+ case 0x13: // STC.L GBR,@-Rn 0100nnnn00010011
+ tmp = SHR_GBR;
+ opd->cycles = 2;
+ break;
+ case 0x23: // STC.L VBR,@-Rn 0100nnnn00100011
+ tmp = SHR_VBR;
+ opd->cycles = 2;
+ break;
+ default:
+ goto undefined;
+ }
+ opd->source = BITMASK2(GET_Rn(), tmp);
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x04:
+ case 0x05:
+ switch (op & 0x3f)
+ {
+ case 0x04: // ROTL Rn 0100nnnn00000100
+ case 0x05: // ROTR Rn 0100nnnn00000101
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ case 0x24: // ROTCL Rn 0100nnnn00100100
+ case 0x25: // ROTCR Rn 0100nnnn00100101
+ opd->source = BITMASK2(GET_Rn(), SHR_T);
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ case 0x15: // CMP/PL Rn 0100nnnn00010101
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK1(SHR_T);
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x06:
+ case 0x07:
+ switch (op & 0x3f)
+ {
+ case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
+ tmp = SHR_MACH;
+ break;
+ case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
+ tmp = SHR_MACL;
+ break;
+ case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
+ tmp = SHR_PR;
+ break;
+ case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
+ tmp = SHR_SR;
+ opd->cycles = 3;
+ break;
+ case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
+ tmp = SHR_GBR;
+ opd->cycles = 3;
+ break;
+ case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
+ tmp = SHR_VBR;
+ opd->cycles = 3;
+ break;
+ default:
+ goto undefined;
+ }
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK2(GET_Rn(), tmp);
+ break;
+ case 0x08:
+ case 0x09:
+ switch (GET_Fx())
+ {
+ case 0:
+ // SHLL2 Rn 0100nnnn00001000
+ // SHLR2 Rn 0100nnnn00001001
+ break;
+ case 1:
+ // SHLL8 Rn 0100nnnn00011000
+ // SHLR8 Rn 0100nnnn00011001
+ break;
+ case 2:
+ // SHLL16 Rn 0100nnnn00101000
+ // SHLR16 Rn 0100nnnn00101001
+ break;
+ default:
+ goto undefined;
+ }
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ case 0x0a:
+ switch (GET_Fx())
+ {
+ case 0: // LDS Rm,MACH 0100mmmm00001010
+ tmp = SHR_MACH;
+ break;
+ case 1: // LDS Rm,MACL 0100mmmm00011010
+ tmp = SHR_MACL;
+ break;
+ case 2: // LDS Rm,PR 0100mmmm00101010
+ tmp = SHR_PR;
+ break;
+ default:
+ goto undefined;
+ }
+ opd->op = OP_MOVE;
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK1(tmp);
+ break;
+ case 0x0b:
+ switch (GET_Fx())
+ {
+ case 0: // JSR @Rm 0100mmmm00001011
+ opd->dest = BITMASK1(SHR_PR);
+ case 2: // JMP @Rm 0100mmmm00101011
+ opd->op = OP_BRANCH_R;
+ opd->rm = GET_Rn();
+ opd->source = BITMASK1(opd->rm);
+ opd->dest |= BITMASK1(SHR_PC);
+ opd->cycles = 2;
+ next_is_delay = 1;
+ end_block = 1;
+ break;
+ case 1: // TAS.B @Rn 0100nnnn00011011
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK1(SHR_T);
+ opd->cycles = 4;
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+ case 0x0e:
+ switch (GET_Fx())
+ {
+ case 0: // LDC Rm,SR 0100mmmm00001110
+ tmp = SHR_SR;
+ break;
+ case 1: // LDC Rm,GBR 0100mmmm00011110
+ tmp = SHR_GBR;
+ break;
+ case 2: // LDC Rm,VBR 0100mmmm00101110
+ tmp = SHR_VBR;
+ break;
+ default:
+ goto undefined;
+ }
+ opd->op = OP_MOVE;
+ opd->source = BITMASK1(GET_Rn());
+ opd->dest = BITMASK1(tmp);
+ break;
+ case 0x0f:
+ // MAC.W @Rm+,@Rn+ 0100nnnnmmmm1111
+ opd->source = BITMASK5(GET_Rm(), GET_Rn(), SHR_SR, SHR_MACL, SHR_MACH);
+ opd->dest = BITMASK4(GET_Rm(), GET_Rn(), SHR_MACL, SHR_MACH);
+ opd->cycles = 3;
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x05:
+ // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
+ opd->source = BITMASK1(GET_Rm());
+ opd->dest = BITMASK1(GET_Rn());
+ opd->imm = (op & 0x0f) * 4;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x06:
+ switch (op & 0x0f)
+ {
+ case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
+ case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
+ case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
+ opd->dest = BITMASK1(GET_Rm());
+ case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
+ case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
+ case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
+ opd->source = BITMASK1(GET_Rm());
+ opd->dest |= BITMASK1(GET_Rn());
+ break;
+ case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
+ opd->source = BITMASK2(GET_Rm(), SHR_T);
+ opd->dest = BITMASK2(GET_Rn(), SHR_T);
+ break;
+ case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
+ opd->op = OP_MOVE;
+ goto arith_rmrn;
+ case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
+ case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
+ case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
+ case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
+ case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
+ case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
+ case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
+ case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
+ arith_rmrn:
+ opd->source = BITMASK1(GET_Rm());
+ opd->dest = BITMASK1(GET_Rn());
+ break;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x07:
+ // ADD #imm,Rn 0111nnnniiiiiiii
+ opd->source = opd->dest = BITMASK1(GET_Rn());
+ opd->imm = (int)(signed char)op;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x08:
+ switch (op & 0x0f00)
+ {
+ case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
+ opd->source = BITMASK2(GET_Rm(), SHR_R0);
+ opd->imm = (op & 0x0f);
+ break;
+ case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
+ opd->source = BITMASK2(GET_Rm(), SHR_R0);
+ opd->imm = (op & 0x0f) * 2;
+ break;
+ case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
+ opd->source = BITMASK1(GET_Rm());
+ opd->dest = BITMASK1(SHR_R0);
+ opd->imm = (op & 0x0f);
+ break;
+ case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
+ opd->source = BITMASK1(GET_Rm());
+ opd->dest = BITMASK1(SHR_R0);
+ opd->imm = (op & 0x0f) * 2;
+ break;
+ case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
+ opd->source = BITMASK1(SHR_R0);
+ opd->dest = BITMASK1(SHR_T);
+ opd->imm = (int)(signed char)op;
+ break;
+ case 0x0d00: // BT/S label 10001101dddddddd
+ case 0x0f00: // BF/S label 10001111dddddddd
+ next_is_delay = 1;
+ // fallthrough
+ case 0x0900: // BT label 10001001dddddddd
+ case 0x0b00: // BF label 10001011dddddddd
+ opd->op = (op & 0x0200) ? OP_BRANCH_CF : OP_BRANCH_CT;
+ opd->source = BITMASK1(SHR_T);
+ opd->dest = BITMASK1(SHR_PC);
+ opd->imm = ((signed int)(op << 24) >> 23);
+ opd->imm += pc + 4;
+ if (base_pc <= opd->imm && opd->imm < base_pc + BLOCK_INSN_LIMIT * 2)
+ op_flags[(opd->imm - base_pc) / 2] |= OF_BTARGET;
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x09:
+ // MOV.W @(disp,PC),Rn 1001nnnndddddddd
+ opd->op = OP_LOAD_POOL;
+ tmp = pc + 2;
+ if (op_flags[i] & OF_DELAY_OP) {
+ if (ops[i-1].op == OP_BRANCH)
+ tmp = ops[i-1].imm;
+ else
+ tmp = 0;
+ }
+ opd->source = BITMASK1(SHR_PC);
+ opd->dest = BITMASK1(GET_Rn());
+ if (tmp)
+ opd->imm = tmp + 2 + (op & 0xff) * 2;
+ opd->size = 1;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x0b:
+ // BSR label 1011dddddddddddd
+ opd->dest = BITMASK1(SHR_PR);
+ case 0x0a:
+ // BRA label 1010dddddddddddd
+ opd->op = OP_BRANCH;
+ opd->dest |= BITMASK1(SHR_PC);
+ opd->imm = ((signed int)(op << 20) >> 19);
+ opd->imm += pc + 4;
+ opd->cycles = 2;
+ next_is_delay = 1;
+ end_block = 1;
+ if (base_pc <= opd->imm && opd->imm < base_pc + BLOCK_INSN_LIMIT * 2)
+ op_flags[(opd->imm - base_pc) / 2] |= OF_BTARGET;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x0c:
+ switch (op & 0x0f00)
+ {
+ case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
+ case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
+ case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
+ opd->source = BITMASK2(SHR_GBR, SHR_R0);
+ opd->size = (op & 0x300) >> 8;
+ opd->imm = (op & 0xff) << opd->size;
+ break;
+ case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
+ case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
+ case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
+ opd->source = BITMASK1(SHR_GBR);
+ opd->dest = BITMASK1(SHR_R0);
+ opd->size = (op & 0x300) >> 8;
+ opd->imm = (op & 0xff) << opd->size;
+ break;
+ case 0x0300: // TRAPA #imm 11000011iiiiiiii
+ opd->source = BITMASK2(SHR_PC, SHR_SR);
+ opd->dest = BITMASK1(SHR_PC);
+ opd->imm = (op & 0xff) * 4;
+ opd->cycles = 8;
+ end_block = 1; // FIXME
+ break;
+ case 0x0700: // MOVA @(disp,PC),R0 11000111dddddddd
+ opd->op = OP_MOVA;
+ tmp = pc + 2;
+ if (op_flags[i] & OF_DELAY_OP) {
+ if (ops[i-1].op == OP_BRANCH)
+ tmp = ops[i-1].imm;
+ else
+ tmp = 0;
+ }
+ opd->dest = BITMASK1(SHR_R0);
+ if (tmp) {
+ opd->imm = (tmp + 2 + (op & 0xff) * 4) & ~3;
+ if (opd->imm >= base_pc) {
+ if (lowest_mova == 0 || opd->imm < lowest_mova)
+ lowest_mova = opd->imm;
+ }
+ }
+ break;
+ case 0x0800: // TST #imm,R0 11001000iiiiiiii
+ opd->source = BITMASK1(SHR_R0);
+ opd->dest = BITMASK1(SHR_T);
+ opd->imm = op & 0xff;
+ break;
+ case 0x0900: // AND #imm,R0 11001001iiiiiiii
+ opd->source = opd->dest = BITMASK1(SHR_R0);
+ opd->imm = op & 0xff;
+ break;
+ case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
+ opd->source = opd->dest = BITMASK1(SHR_R0);
+ opd->imm = op & 0xff;
+ break;
+ case 0x0b00: // OR #imm,R0 11001011iiiiiiii
+ opd->source = opd->dest = BITMASK1(SHR_R0);
+ opd->imm = op & 0xff;
+ break;
+ case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
+ opd->source = BITMASK2(SHR_GBR, SHR_R0);
+ opd->dest = BITMASK1(SHR_T);
+ opd->imm = op & 0xff;
+ opd->cycles = 3;
+ break;
+ case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
+ case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
+ case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
+ opd->source = BITMASK2(SHR_GBR, SHR_R0);
+ opd->imm = op & 0xff;
+ opd->cycles = 3;
+ break;
+ default:
+ goto undefined;
+ }
+ break;
+
+ /////////////////////////////////////////////
+ case 0x0d:
+ // MOV.L @(disp,PC),Rn 1101nnnndddddddd
+ opd->op = OP_LOAD_POOL;
+ tmp = pc + 2;
+ if (op_flags[i] & OF_DELAY_OP) {
+ if (ops[i-1].op == OP_BRANCH)
+ tmp = ops[i-1].imm;
+ else
+ tmp = 0;
+ }
+ opd->source = BITMASK1(SHR_PC);
+ opd->dest = BITMASK1(GET_Rn());
+ if (tmp)
+ opd->imm = (tmp + 2 + (op & 0xff) * 4) & ~3;
+ opd->size = 2;
+ break;
+
+ /////////////////////////////////////////////
+ case 0x0e:
+ // MOV #imm,Rn 1110nnnniiiiiiii
+ opd->dest = BITMASK1(GET_Rn());
+ opd->imm = (u32)(signed int)(signed char)op;
+ break;
+
+ default:
+ undefined:
+ elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
+ is_slave ? 's' : 'm', op, pc);
+ break;
+ }
+
+ if (op_flags[i] & OF_DELAY_OP) {
+ switch (opd->op) {
+ case OP_BRANCH:
+ case OP_BRANCH_CT:
+ case OP_BRANCH_CF:
+ case OP_BRANCH_R:
+ case OP_BRANCH_RF:
+ elprintf(EL_ANOMALY, "%csh2 drc: branch in DS @ %08x",
+ is_slave ? 's' : 'm', pc);
+ opd->op = OP_UNHANDLED;
+ op_flags[i] |= OF_B_IN_DS;
+ next_is_delay = 0;
+ break;
+ }
+ }
+ }
+ i_end = i;
+ end_pc = pc;
+
+ // 2nd pass: some analysis
+ for (i = 0; i < i_end; i++) {
+ opd = &ops[i];
+
+ // propagate T (TODO: DIV0U)
+ if ((opd->op == OP_SETCLRT && !opd->imm) || opd->op == OP_BRANCH_CT)
+ op_flags[i + 1] |= OF_T_CLEAR;
+ else if ((opd->op == OP_SETCLRT && opd->imm) || opd->op == OP_BRANCH_CF)
+ op_flags[i + 1] |= OF_T_SET;
+
+ if ((op_flags[i] & OF_BTARGET) || (opd->dest & BITMASK1(SHR_T)))
+ op_flags[i] &= ~(OF_T_SET | OF_T_CLEAR);
+ else
+ op_flags[i + 1] |= op_flags[i] & (OF_T_SET | OF_T_CLEAR);
+
+ if ((opd->op == OP_BRANCH_CT && (op_flags[i] & OF_T_SET))
+ || (opd->op == OP_BRANCH_CF && (op_flags[i] & OF_T_CLEAR)))
+ {
+ opd->op = OP_BRANCH;
+ opd->cycles = 3;
+ i_end = i + 1;
+ if (op_flags[i + 1] & OF_DELAY_OP) {
+ opd->cycles = 2;
+ i_end++;
+ }
+ }
+ else if (opd->op == OP_LOAD_POOL)
+ {
+ if (opd->imm < end_pc + MAX_LITERAL_OFFSET) {
+ if (end_literals < opd->imm + opd->size * 2)
+ end_literals = opd->imm + opd->size * 2;
+ }
+ }
+ }
+ end_pc = base_pc + i_end * 2;
+ if (end_literals < end_pc)
+ end_literals = end_pc;
+
+ // end_literals is used to decide to inline a literal or not
+ // XXX: need better detection if this actually is used in write
+ if (lowest_mova >= base_pc) {
+ if (lowest_mova < end_literals) {
+ dbg(1, "mova for %08x, block %08x", lowest_mova, base_pc);
+ end_literals = end_pc;
+ }
+ if (lowest_mova < end_pc) {
+ dbg(1, "warning: mova inside of blk for %08x, block %08x",
+ lowest_mova, base_pc);
+ end_literals = end_pc;
+ }
+ }
+
+ *end_pc_out = end_pc;
+ if (end_literals_out != NULL)
+ *end_literals_out = end_literals;