Changed the ARM disassembler to use 'std::ostream &' internally

This commit is contained in:
Nathan Woods 2016-11-11 11:21:29 -05:00
parent a9d260cf14
commit 2f77abbe78

View File

@ -9,7 +9,7 @@
#include "emu.h" #include "emu.h"
#include "arm.h" #include "arm.h"
static char *WriteImmediateOperand( char *pBuf, uint32_t opcode ) static void WriteImmediateOperand( std::ostream &stream, uint32_t opcode )
{ {
/* rrrrbbbbbbbb */ /* rrrrbbbbbbbb */
uint32_t imm; uint32_t imm;
@ -18,69 +18,70 @@ static char *WriteImmediateOperand( char *pBuf, uint32_t opcode )
imm = opcode&0xff; imm = opcode&0xff;
r = ((opcode>>8)&0xf)*2; r = ((opcode>>8)&0xf)*2;
imm = (imm>>r)|(r?(imm<<(32-r)):0); imm = (imm>>r)|(r?(imm<<(32-r)):0);
pBuf += sprintf( pBuf, ", #$%x", imm ); util::stream_format( stream, ", #$%x", imm );
return pBuf;
} }
static char *WriteDataProcessingOperand( char *pBuf, uint32_t opcode, int printOp0, int printOp1, int printOp2 ) static void WriteDataProcessingOperand( std::ostream &stream, uint32_t opcode, int printOp0, int printOp1, int printOp2 )
{ {
/* ccccctttmmmm */ /* ccccctttmmmm */
static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" };
if (printOp0) if (printOp0)
pBuf += sprintf(pBuf,"R%d, ", (opcode>>12)&0xf); util::stream_format(stream, "R%d, ", (opcode>>12)&0xf);
if (printOp1) if (printOp1)
pBuf += sprintf(pBuf,"R%d, ", (opcode>>16)&0xf); util::stream_format(stream, "R%d, ", (opcode>>16)&0xf);
/* Immediate Op2 */ /* Immediate Op2 */
if( opcode&0x02000000 ) if (opcode & 0x02000000)
return WriteImmediateOperand(pBuf-2,opcode); {
stream.seekp(-2, std::ios_base::cur);
WriteImmediateOperand(stream, opcode);
return;
}
/* Register Op2 */ /* Register Op2 */
if (printOp2) if (printOp2)
pBuf += sprintf(pBuf,"R%d, ", (opcode>>0)&0xf); util::stream_format(stream, "R%d, ", (opcode>>0)&0xf);
pBuf += sprintf(pBuf, "%s ", pRegOp[(opcode>>5)&3] ); util::stream_format(stream, "%s ", pRegOp[(opcode>>5)&3]);
if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */
{ {
pBuf += sprintf( pBuf, "R%d", (opcode>>8)&0xf ); util::stream_format( stream, "R%d", (opcode>>8)&0xf );
} }
else /* Shift amount immediate 5 bit unsigned integer */ else /* Shift amount immediate 5 bit unsigned integer */
{ {
int c=(opcode>>7)&0x1f; int c=(opcode>>7)&0x1f;
if( c==0 ) c = 32; if( c==0 ) c = 32;
pBuf += sprintf( pBuf, "#%d", c ); util::stream_format( stream, "#%d", c );
} }
return pBuf;
} }
static char *WriteRegisterOperand1( char *pBuf, uint32_t opcode ) static void WriteRegisterOperand1( std::ostream &stream, uint32_t opcode )
{ {
/* ccccctttmmmm */ /* ccccctttmmmm */
static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" };
pBuf += sprintf( util::stream_format(
pBuf, stream,
", R%d %s ", /* Operand 1 register, Operand 2 register, shift type */ ", R%d %s ", /* Operand 1 register, Operand 2 register, shift type */
(opcode>> 0)&0xf, (opcode>> 0)&0xf,
pRegOp[(opcode>>5)&3] ); pRegOp[(opcode>>5)&3]);
if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */
{ {
pBuf += sprintf( pBuf, "R%d", (opcode>>7)&0xf ); util::stream_format( stream, "R%d", (opcode>>7)&0xf );
} }
else /* Shift amount immediate 5 bit unsigned integer */ else /* Shift amount immediate 5 bit unsigned integer */
{ {
int c=(opcode>>7)&0x1f; int c=(opcode>>7)&0x1f;
if( c==0 ) c = 32; if( c==0 ) c = 32;
pBuf += sprintf( pBuf, "#%d", c ); util::stream_format( stream, "#%d", c );
} }
return pBuf;
} /* WriteRegisterOperand */ } /* WriteRegisterOperand */
static char *WriteBranchAddress( char *pBuf, uint32_t pc, uint32_t opcode ) static void WriteBranchAddress( std::ostream &stream, uint32_t pc, uint32_t opcode )
{ {
opcode &= 0x00ffffff; opcode &= 0x00ffffff;
if( opcode&0x00800000 ) if( opcode&0x00800000 )
@ -88,24 +89,18 @@ static char *WriteBranchAddress( char *pBuf, uint32_t pc, uint32_t opcode )
opcode |= 0xff000000; /* sign-extend */ opcode |= 0xff000000; /* sign-extend */
} }
pc += 8+4*opcode; pc += 8+4*opcode;
sprintf( pBuf, "$%x", pc ); util::stream_format( stream, "$%x", pc );
return pBuf;
} /* WriteBranchAddress */ } /* WriteBranchAddress */
static char *WritePadding( char *pBuf, const char *pBuf0 ) static void WritePadding(std::ostream &stream, std::streampos start_position)
{ {
pBuf0 += 8; std::streamoff difference = stream.tellp() - start_position;
while( pBuf<pBuf0 ) for (std::streamoff i = difference; i < 8; i++)
{ stream << ' ';
*pBuf++ = ' ';
}
return pBuf;
} }
static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode ) static uint32_t arm_disasm( std::ostream &stream, uint32_t pc, uint32_t opcode )
{ {
const char *pBuf0;
static const char *const pConditionCodeTable[16] = static const char *const pConditionCodeTable[16] =
{ {
"EQ","NE","CS","CC", "EQ","NE","CS","CC",
@ -122,9 +117,9 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
}; };
const char *pConditionCode; const char *pConditionCode;
uint32_t dasmflags = 0; uint32_t dasmflags = 0;
std::streampos start_position = stream.tellp();
pConditionCode= pConditionCodeTable[opcode>>28]; pConditionCode= pConditionCodeTable[opcode>>28];
pBuf0 = pBuf;
if( (opcode&0x0fc000f0)==0x00000090u ) if( (opcode&0x0fc000f0)==0x00000090u )
{ {
@ -132,28 +127,28 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
/* xxxx0000 00ASdddd nnnnssss 1001mmmm */ /* xxxx0000 00ASdddd nnnnssss 1001mmmm */
if( opcode&0x00200000 ) if( opcode&0x00200000 )
{ {
pBuf += sprintf( pBuf, "MLA" ); util::stream_format( stream, "MLA" );
} }
else else
{ {
pBuf += sprintf( pBuf, "MUL" ); util::stream_format( stream, "MUL" );
} }
pBuf += sprintf( pBuf, "%s", pConditionCode ); util::stream_format( stream, "%s", pConditionCode );
if( opcode&0x00100000 ) if( opcode&0x00100000 )
{ {
*pBuf++ = 'S'; stream << 'S';
} }
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
pBuf += sprintf( pBuf, util::stream_format(stream,
"R%d, R%d, R%d", "R%d, R%d, R%d",
(opcode>>16)&0xf, (opcode>>16)&0xf,
(opcode&0xf), (opcode&0xf),
(opcode>>8)&0xf ); (opcode>>8)&0xf);
if( opcode&0x00200000 ) if( opcode&0x00200000 )
{ {
pBuf += sprintf( pBuf, ", R%d", (opcode>>12)&0xf ); util::stream_format( stream, ", R%d", (opcode>>12)&0xf );
} }
} }
else if( (opcode&0x0c000000)==0 ) else if( (opcode&0x0c000000)==0 )
@ -164,17 +159,17 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
/* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */ /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */
/* xxxx000a aaaSnnnn ddddcccc ctttmmmm */ /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */
pBuf += sprintf( util::stream_format(stream,
pBuf, "%s%s", "%s%s",
pOperation[op], pOperation[op],
pConditionCode ); pConditionCode);
if( (opcode&0x01000000) ) if( (opcode&0x01000000) )
{ {
*pBuf++ = 'S'; stream << 'S';
} }
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
switch (op) { switch (op) {
case 0x00: case 0x00:
@ -187,20 +182,20 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
case 0x07: case 0x07:
case 0x0c: case 0x0c:
case 0x0e: case 0x0e:
WriteDataProcessingOperand(pBuf, opcode, 1, 1, 1); WriteDataProcessingOperand(stream, opcode, 1, 1, 1);
break; break;
case 0x08: case 0x08:
case 0x09: case 0x09:
case 0x0a: case 0x0a:
case 0x0b: case 0x0b:
WriteDataProcessingOperand(pBuf, opcode, 0, 1, 1); WriteDataProcessingOperand(stream, opcode, 0, 1, 1);
break; break;
case 0x0d: case 0x0d:
/* look for mov pc,lr */ /* look for mov pc,lr */
if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0)
dasmflags = DASMFLAG_STEP_OUT; dasmflags = DASMFLAG_STEP_OUT;
case 0x0f: case 0x0f:
WriteDataProcessingOperand(pBuf, opcode, 1, 0, 1); WriteDataProcessingOperand(stream, opcode, 1, 0, 1);
break; break;
} }
} }
@ -212,17 +207,17 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
/* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */ /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */
if( opcode&0x00100000 ) if( opcode&0x00100000 )
{ {
pBuf += sprintf( pBuf, "LDR" ); util::stream_format( stream, "LDR" );
} }
else else
{ {
pBuf += sprintf( pBuf, "STR" ); util::stream_format( stream, "STR" );
} }
pBuf += sprintf( pBuf, "%s", pConditionCode ); util::stream_format( stream, "%s", pConditionCode );
if( opcode&0x00400000 ) if( opcode&0x00400000 )
{ {
pBuf += sprintf( pBuf, "B" ); util::stream_format( stream, "B" );
} }
if( opcode&0x00200000 ) if( opcode&0x00200000 )
@ -231,36 +226,36 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
if( opcode&0x01000000 ) if( opcode&0x01000000 )
{ {
/* pre-indexed addressing */ /* pre-indexed addressing */
pBuf += sprintf( pBuf, "!" ); util::stream_format( stream, "!" );
} }
else else
{ {
/* post-indexed addressing */ /* post-indexed addressing */
pBuf += sprintf( pBuf, "T" ); util::stream_format( stream, "T" );
} }
} }
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
pBuf += sprintf( pBuf, "R%d, [R%d", util::stream_format( stream, "R%d, [R%d",
(opcode>>12)&0xf, (opcode>>16)&0xf ); (opcode>>12)&0xf, (opcode>>16)&0xf );
if( opcode&0x02000000 ) if( opcode&0x02000000 )
{ {
/* register form */ /* register form */
pBuf = WriteRegisterOperand1( pBuf, opcode ); WriteRegisterOperand1( stream, opcode );
pBuf += sprintf( pBuf, "]" ); util::stream_format( stream, "]" );
} }
else else
{ {
/* immediate form */ /* immediate form */
pBuf += sprintf( pBuf, "]" ); util::stream_format( stream, "]" );
if( opcode&0x00800000 ) if( opcode&0x00800000 )
{ {
pBuf += sprintf( pBuf, ", #$%x", opcode&0xfff ); util::stream_format( stream, ", #$%x", opcode&0xfff );
} }
else else
{ {
pBuf += sprintf( pBuf, ", -#$%x", opcode&0xfff ); util::stream_format( stream, ", -#$%x", opcode&0xfff );
} }
} }
} }
@ -271,33 +266,33 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
if( opcode&0x00100000 ) if( opcode&0x00100000 )
{ {
pBuf += sprintf( pBuf, "LDM" ); util::stream_format( stream, "LDM" );
} }
else else
{ {
pBuf += sprintf( pBuf, "STM" ); util::stream_format( stream, "STM" );
} }
pBuf += sprintf( pBuf, "%s", pConditionCode ); util::stream_format( stream, "%s", pConditionCode );
if( opcode&0x01000000 ) if( opcode&0x01000000 )
{ {
pBuf += sprintf( pBuf, "P" ); util::stream_format( stream, "P" );
} }
if( opcode&0x00800000 ) if( opcode&0x00800000 )
{ {
pBuf += sprintf( pBuf, "U" ); util::stream_format( stream, "U" );
} }
if( opcode&0x00400000 ) if( opcode&0x00400000 )
{ {
pBuf += sprintf( pBuf, "^" ); util::stream_format( stream, "^" );
} }
if( opcode&0x00200000 ) if( opcode&0x00200000 )
{ {
pBuf += sprintf( pBuf, "W" ); util::stream_format( stream, "W" );
} }
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
pBuf += sprintf( pBuf, "[R%d], {",(opcode>>16)&0xf); util::stream_format( stream, "[R%d], {",(opcode>>16)&0xf);
{ {
int j=0,last=0,found=0; int j=0,last=0,found=0;
@ -308,20 +303,20 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
} }
else if ((opcode&(1<<j))==0 && found) { else if ((opcode&(1<<j))==0 && found) {
if (last==j-1) if (last==j-1)
pBuf += sprintf( pBuf, " R%d,",last); util::stream_format( stream, " R%d,",last);
else else
pBuf += sprintf( pBuf, " R%d-R%d,",last,j-1); util::stream_format( stream, " R%d-R%d,",last,j-1);
found=0; found=0;
} }
} }
if (found && last==15) if (found && last==15)
pBuf += sprintf( pBuf, " R15,"); util::stream_format( stream, " R15,");
else if (found) else if (found)
pBuf += sprintf( pBuf, " R%d-R%d,",last,15); util::stream_format( stream, " R%d-R%d,",last,15);
} }
pBuf--; stream.seekp(-1, std::ios_base::cur);
pBuf += sprintf( pBuf, " }"); util::stream_format( stream, " }");
} }
else if( (opcode&0x0e000000)==0x0a000000 ) else if( (opcode&0x0e000000)==0x0a000000 )
{ {
@ -329,19 +324,19 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
/* xxxx101L oooooooo oooooooo oooooooo */ /* xxxx101L oooooooo oooooooo oooooooo */
if( opcode&0x01000000 ) if( opcode&0x01000000 )
{ {
pBuf += sprintf( pBuf, "BL" ); util::stream_format( stream, "BL" );
dasmflags = DASMFLAG_STEP_OVER; dasmflags = DASMFLAG_STEP_OVER;
} }
else else
{ {
pBuf += sprintf( pBuf, "B" ); util::stream_format( stream, "B" );
} }
pBuf += sprintf( pBuf, "%s", pConditionCode ); util::stream_format( stream, "%s", pConditionCode );
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
pBuf = WriteBranchAddress( pBuf, pc, opcode ); WriteBranchAddress( stream, pc, opcode );
} }
else if( (opcode&0x0f000000) == 0x0e000000 ) else if( (opcode&0x0f000000) == 0x0e000000 )
{ {
@ -351,50 +346,59 @@ static uint32_t arm_disasm( char *pBuf, uint32_t pc, uint32_t opcode )
{ {
if( (opcode&0x0f100010)==0x0e100010 ) if( (opcode&0x0f100010)==0x0e100010 )
{ {
pBuf += sprintf( pBuf, "MRC" ); util::stream_format( stream, "MRC" );
} }
else if( (opcode&0x0f100010)==0x0e000010 ) else if( (opcode&0x0f100010)==0x0e000010 )
{ {
pBuf += sprintf( pBuf, "MCR" ); util::stream_format( stream, "MCR" );
} }
else else
{ {
pBuf += sprintf( pBuf, "???" ); util::stream_format( stream, "???" );
} }
pBuf += sprintf( pBuf, "%s", pConditionCode ); util::stream_format( stream, "%s", pConditionCode );
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
pBuf += sprintf( pBuf, "R%d, CR%d {CRM%d, q%d}",(opcode>>12)&0xf, (opcode>>16)&0xf, (opcode>>0)&0xf, (opcode>>5)&0x7); 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 */ /* Nb: full form should be o, p, R, CR, CRM, q */
} }
else if( (opcode&0x0f000010)==0x0e000000 ) else if( (opcode&0x0f000010)==0x0e000000 )
{ {
pBuf += sprintf( pBuf, "CDP" ); util::stream_format( stream, "CDP" );
pBuf += sprintf( pBuf, "%s", pConditionCode ); util::stream_format( stream, "%s", pConditionCode );
pBuf = WritePadding( pBuf, pBuf0 ); WritePadding(stream, start_position);
pBuf += sprintf( pBuf, "%08x", opcode ); util::stream_format( stream, "%08x", opcode );
} }
else else
{ {
pBuf += sprintf( pBuf, "???" ); util::stream_format( stream, "???" );
} }
} }
else if( (opcode&0x0f000000) == 0x0f000000 ) else if( (opcode&0x0f000000) == 0x0f000000 )
{ {
/* Software Interrupt */ /* Software Interrupt */
pBuf += sprintf( pBuf, "SWI%s $%x", util::stream_format( stream, "SWI%s $%x",
pConditionCode, pConditionCode,
opcode&0x00ffffff ); opcode&0x00ffffff );
dasmflags = DASMFLAG_STEP_OVER; dasmflags = DASMFLAG_STEP_OVER;
} }
else else
{ {
pBuf += sprintf( pBuf, "Undefined" ); util::stream_format( stream, "Undefined" );
} }
return dasmflags | DASMFLAG_SUPPORTED; return dasmflags | DASMFLAG_SUPPORTED;
} }
static uint32_t arm_disasm(char *buffer, uint32_t pc, uint32_t opcode)
{
std::ostringstream stream;
uint32_t result = arm_disasm(stream, pc, opcode);
std::string stream_str = stream.str();
strcpy(buffer, stream_str.c_str());
return result;
}
CPU_DISASSEMBLE( arm ) CPU_DISASSEMBLE( arm )
{ {
uint32_t opcode = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24); uint32_t opcode = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);