diff options
Diffstat (limited to 'src/devices/cpu/arm/armdasm.cpp')
-rw-r--r-- | src/devices/cpu/arm/armdasm.cpp | 258 |
1 files changed, 157 insertions, 101 deletions
diff --git a/src/devices/cpu/arm/armdasm.cpp b/src/devices/cpu/arm/armdasm.cpp index b56e60161af..209eddde078 100644 --- a/src/devices/cpu/arm/armdasm.cpp +++ b/src/devices/cpu/arm/armdasm.cpp @@ -14,7 +14,7 @@ uint32_t arm_disassembler::ExtractImmediateOperand(uint32_t opcode) const // rrrrbbbbbbbb uint32_t imm = opcode & 0xff; uint8_t r = ((opcode >> 8) & 0xf) * 2; - return (imm >> r) | (r ? (imm << (32 - r)) : 0); + return rotr_32(imm, r); } void arm_disassembler::WriteDataProcessingOperand(std::ostream &stream, uint32_t opcode, bool printOp0, bool printOp1, offs_t pc) const @@ -31,13 +31,7 @@ void arm_disassembler::WriteDataProcessingOperand(std::ostream &stream, uint32_t if (opcode & 0x02000000) { uint32_t imm = ExtractImmediateOperand(opcode); - util::stream_format(stream, "#$%x", imm); - - // Calculate result of ADD/SUB Rn, R15, #imm - if ((opcode & 0x01ef0000) == 0x008f0000) - util::stream_format(stream, " ; =$%x", pc + 8 + imm); - else if ((opcode & 0x01ef0000) == 0x004f0000) - util::stream_format(stream, " ; =$%x", pc + 8 - imm); + util::stream_format(stream, "#&%X", imm); } else { @@ -58,6 +52,11 @@ void arm_disassembler::WriteDataProcessingOperand(std::ostream &stream, uint32_t { if (shiftop == 0) return; + else if (shiftop == 3) + { + util::stream_format(stream, ", RRX"); + return; + } c = 32; } util::stream_format(stream, ", %s #%d", pRegOp[shiftop], c); @@ -70,15 +69,19 @@ void arm_disassembler::WriteRegisterOperand1(std::ostream &stream, uint32_t opco /* ccccctttmmmm */ static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; + util::stream_format(stream, ", "); + if((opcode & 0x00800000) == 0) + util::stream_format(stream, "-"); + int shiftop = (opcode >> 5) & 3; util::stream_format( stream, - ", R%d", /* Operand 1 register, Operand 2 register */ + "R%d", /* Operand 1 register, Operand 2 register */ (opcode >> 0) & 0xf); if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ { - util::stream_format(stream, " %s R%d", pRegOp[shiftop], (opcode >> 7) & 0xf); + util::stream_format(stream, ", %s R%d", pRegOp[shiftop], (opcode >> 8) & 0xf); } else /* Shift amount immediate 5 bit unsigned integer */ { @@ -87,22 +90,22 @@ void arm_disassembler::WriteRegisterOperand1(std::ostream &stream, uint32_t opco { if (shiftop == 0) return; + else if (shiftop == 3) + { + util::stream_format(stream, ", RRX"); + return; + } c = 32; } - util::stream_format(stream, " %s #%d", pRegOp[shiftop], c); + util::stream_format(stream, ", %s #%d", pRegOp[shiftop], c); } } /* WriteRegisterOperand */ void arm_disassembler::WriteBranchAddress(std::ostream &stream, uint32_t pc, uint32_t opcode) const { - opcode &= 0x00ffffff; - if( opcode&0x00800000 ) - { - opcode |= 0xff000000; /* sign-extend */ - } - pc += 8+4*opcode; - util::stream_format( stream, "$%x", pc ); + pc += 8+4*util::sext(opcode, 24); + util::stream_format( stream, "&%07X", pc & 0x03ffffff ); } /* WriteBranchAddress */ void arm_disassembler::WritePadding(std::ostream &stream, std::streampos start_position) const @@ -142,13 +145,13 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data /* xxxx0000 00ASdddd nnnnssss 1001mmmm */ if( opcode&0x00200000 ) { - util::stream_format( stream, "MLA" ); + stream << "MLA"; } else { - util::stream_format( stream, "MUL" ); + stream << "MUL"; } - util::stream_format( stream, "%s", pConditionCode ); + stream << pConditionCode; if ((opcode & 0x00100000) != 0) stream << 'S'; @@ -173,13 +176,21 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */ /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */ + // ADR Rn, offset = ADD/SUB Rn, R15, #imm + bool adr = (op == 0x02 || op == 0x04) && (opcode & 0x020f0000) == 0x020f0000; + util::stream_format(stream, "%s%s", - pOperation[op], + adr ? "ADR" : pOperation[op], pConditionCode); if ((opcode & 0x00100000) != 0) - stream << 'S'; + { + if ((op & 0x0c) != 0x08) + stream << 'S'; + else if (((opcode >> 12) & 0xf) == 0xf) + stream << 'P'; + } WritePadding(stream, start_position); @@ -194,7 +205,13 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data case 0x07: case 0x0c: case 0x0e: - WriteDataProcessingOperand(stream, opcode, true, true, pc); + if (adr) + { + uint32_t imm = ExtractImmediateOperand(opcode); + util::stream_format(stream, "R%d, &%07X", (opcode >> 12) & 0xf, (op == 0x02) ? pc + 8 - imm : pc + 8 + imm); + } + else + WriteDataProcessingOperand(stream, opcode, true, true, pc); break; case 0x08: case 0x09: @@ -204,8 +221,14 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data break; case 0x0d: /* look for mov pc,lr */ - if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) - dasmflags = STEP_OUT; + if (((opcode >> 12) & 0x0f) == 15) + { + if (((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) + dasmflags = STEP_OUT; + if (opcode < 0xe0000000) + dasmflags |= STEP_COND; + } + [[fallthrough]]; case 0x0f: WriteDataProcessingOperand(stream, opcode, true, false, pc); break; @@ -219,60 +242,83 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */ if( opcode&0x00100000 ) { - util::stream_format( stream, "LDR" ); + stream << "LDR"; } else { - util::stream_format( stream, "STR" ); + stream << "STR"; } - util::stream_format( stream, "%s", pConditionCode ); + stream << pConditionCode; if( opcode&0x00400000 ) { - util::stream_format( stream, "B" ); + stream << 'B'; } - if( opcode&0x00200000 ) + if(( opcode&0x01200000 ) == 0x00200000 ) { - /* writeback addr */ - if( opcode&0x01000000 ) - { - /* pre-indexed addressing */ - util::stream_format( stream, "!" ); - } - else - { - /* post-indexed addressing */ - util::stream_format( stream, "T" ); - } + stream << 'T'; } int memreg = (opcode >> 16) & 0xf; WritePadding(stream, start_position); - util::stream_format(stream, "R%d, [R%d", (opcode >> 12) & 0xf, memreg); + util::stream_format(stream, "R%d, ", (opcode >> 12) & 0xf); - if( opcode&0x02000000 ) + if ((memreg == 15) && ( opcode&0x03200000 ) == 0x01000000) { - /* register form */ - WriteRegisterOperand1(stream, opcode); - util::stream_format(stream, "]"); + uint16_t displacement = opcode & 0xfff; + + if( opcode&0x00800000 ) + { + util::stream_format(stream, "&%07X", pc + 8 + displacement); + } + else + { + util::stream_format(stream, "&%07X", pc + 8 - displacement); + } } else { - /* immediate form */ - util::stream_format(stream, "]"); - uint16_t displacement = opcode & 0xfff; - if( opcode&0x00800000 ) + util::stream_format(stream, "[R%d", memreg); + + if(( opcode&0x01000000 ) == 0) + { + /* post-indexed addressing */ + stream << ']'; + } + + if( opcode&0x02000000 ) { - util::stream_format(stream, ", #$%x", displacement); - if (memreg == 15) - util::stream_format(stream, " ; [$%x]", pc + 8 + displacement); + /* register form */ + WriteRegisterOperand1(stream, opcode); } else { - util::stream_format(stream, ", -#$%x", displacement); - if (memreg == 15) - util::stream_format(stream, " ; [$%x]", pc + 8 - displacement); + /* immediate form */ + uint16_t displacement = opcode & 0xfff; + if( displacement != 0 ) + { + if( opcode&0x00800000 ) + { + util::stream_format(stream, ", #&%X", displacement); + } + else + { + util::stream_format(stream, ", -#&%X", displacement); + } + } + } + + if( opcode&0x01000000 ) + { + /* pre-indexed addressing */ + stream << ']'; + + /* writeback addr */ + if( opcode&0x00200000 ) + { + stream << '!'; + } } } } @@ -281,59 +327,66 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data /* xxxx100P USWLnnnn llllllll llllllll */ /* Block Data Transfer */ + uint8_t d = (opcode >> 16) & 0xf; if( opcode&0x00100000 ) { - util::stream_format( stream, "LDM" ); + util::stream_format( stream, "LDM%s", pConditionCode ); + if (d == 13) + util::stream_format( stream, "%c%c", ( opcode&0x01000000 ) ? 'E' : 'F', ( opcode&0x00800000 ) ? 'D' : 'A'); + else + util::stream_format( stream, "%c%c", ( opcode&0x00800000 ) ? 'I' : 'D', ( opcode&0x01000000 ) ? 'B' : 'A'); + + if( opcode & 0x00008000 ) + { + dasmflags = STEP_OUT; + if (opcode < 0xe0000000) + dasmflags |= STEP_COND; + } } else { - util::stream_format( stream, "STM" ); + util::stream_format( stream, "STM%s", pConditionCode ); + if (d == 13) + util::stream_format( stream, "%c%c", ( opcode&0x01000000 ) ? 'F' : 'E', ( opcode&0x00800000 ) ? 'A' : 'D'); + else + util::stream_format( stream, "%c%c", ( opcode&0x00800000 ) ? 'I' : 'D', ( opcode&0x01000000 ) ? 'B' : 'A'); } - util::stream_format( stream, "%s", pConditionCode ); - if( opcode&0x01000000 ) - { - util::stream_format( stream, "P" ); - } - if( opcode&0x00800000 ) - { - util::stream_format( stream, "U" ); - } - if( opcode&0x00400000 ) - { - util::stream_format( stream, "^" ); - } + WritePadding(stream, start_position); + util::stream_format( stream, "R%d", d ); if( opcode&0x00200000 ) { - util::stream_format( stream, "W" ); + stream << '!'; } - - WritePadding(stream, start_position); - util::stream_format( stream, "[R%d], {",(opcode>>16)&0xf); + stream << ", {"; { - int j=0,last=0,found=0; - for (j=0; j<16; j++) { + int last=0,found=0; + for (int j=0; j<16; j++) { if (opcode&(1<<j) && found==0) { + if ((opcode&((1<<j)-1)) != 0) + stream << ", "; found=1; last=j; } else if ((opcode&(1<<j))==0 && found) { - if (last==j-1) - util::stream_format( stream, " R%d,",last); - else - util::stream_format( stream, " R%d-R%d,",last,j-1); + util::stream_format( stream, "R%d",last); + if (last!=j-1) + util::stream_format( stream, "-R%d",j-1); found=0; } } if (found && last==15) - util::stream_format( stream, " R15,"); + util::stream_format( stream, "R15"); else if (found) - util::stream_format( stream, " R%d-R%d,",last,15); + util::stream_format( stream, "R%d-R%d",last,15); } - stream.seekp(-1, std::ios_base::cur); - util::stream_format( stream, " }"); + stream << '}'; + if( opcode&0x00400000 ) + { + stream << '^'; + } } else if( (opcode&0x0e000000)==0x0a000000 ) { @@ -341,15 +394,17 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data /* xxxx101L oooooooo oooooooo oooooooo */ if( opcode&0x01000000 ) { - util::stream_format( stream, "BL" ); + stream << "BL"; dasmflags = STEP_OVER; } else { - util::stream_format( stream, "B" ); + stream << "B"; } + if (opcode < 0xe0000000) + dasmflags |= STEP_COND; - util::stream_format( stream, "%s", pConditionCode ); + stream << pConditionCode; WritePadding(stream, start_position); @@ -363,45 +418,46 @@ offs_t arm_disassembler::disassemble(std::ostream &stream, offs_t pc, const data { if( (opcode&0x0f100010)==0x0e100010 ) { - util::stream_format( stream, "MRC" ); + stream << "MRC"; } else if( (opcode&0x0f100010)==0x0e000010 ) { - util::stream_format( stream, "MCR" ); + stream << "MCR"; } else { - util::stream_format( stream, "???" ); + stream << "???"; } - util::stream_format( stream, "%s", pConditionCode ); + stream << pConditionCode; WritePadding(stream, start_position); util::stream_format( stream, "R%d, CR%d {CRM%d, q%d}",(opcode>>12)&0xf, (opcode>>16)&0xf, (opcode>>0)&0xf, (opcode>>5)&0x7); /* Nb: full form should be o, p, R, CR, CRM, q */ } else if( (opcode&0x0f000010)==0x0e000000 ) { - util::stream_format( stream, "CDP" ); - util::stream_format( stream, "%s", pConditionCode ); + util::stream_format( stream, "CDP%s", pConditionCode ); WritePadding(stream, start_position); - util::stream_format( stream, "%08x", opcode ); + util::stream_format( stream, "R%d, CR%d {CRM%d, q%d}",(opcode>>12)&0xf, (opcode>>16)&0xf, (opcode>>0)&0xf, (opcode>>5)&0x7); } else { - util::stream_format( stream, "???" ); + stream << "???"; } } else if( (opcode&0x0f000000) == 0x0f000000 ) { /* Software Interrupt */ - util::stream_format( stream, "SWI%s $%x", - pConditionCode, - opcode&0x00ffffff ); + util::stream_format( stream, "SWI%s", pConditionCode ); + WritePadding(stream, start_position); + util::stream_format( stream, "&%X", opcode&0x00ffffff ); dasmflags = STEP_OVER; + if (opcode < 0xe0000000) + dasmflags |= STEP_COND; } else { - util::stream_format( stream, "Undefined" ); + stream << "Undefined"; } return 4 | dasmflags | SUPPORTED; |