📄 disasm.c
字号:
/*
* File: src/cpu/coldfire/mcf5xxx/disasm.c
* Purpose: MCF5206 definitions
*
* Notes: This file contains the routines necessary to disassemble
* MC680x0 and MCF52xx compatible instructions. This file
* is a standalone, and the main entry point is cpu_disasm().
*/
/********************************************************************/
#include "src/include/dbug.h"
#include "src/uif/uif.h"
#include "src/cpu/coldfire/mcf5xxx/ea.h"
/********************************************************************/
#define SYMBOL_TABLE
#define SIZE_BYTE SIZE_8
#define SIZE_WORD SIZE_16
#define SIZE_LONG SIZE_32
#define ADDRESS_REGISTER -2
#define DATA_REGISTER -3
/********************************************************************/
/********************************************************************/
static char
dstr[80];
static ADDRESS
disasm_pc;
static int
disasm_op_size;
static int
valid_instruction;
/********************************************************************/
static void
inc_disasm_pc (unsigned int num)
{
disasm_pc = (ADDRESS)((unsigned int)disasm_pc +
(unsigned int)num);
}
/********************************************************************/
static void
append_instruction (char *buf, char *instruction)
{
sprintf(buf,"%-10s",instruction);
}
/********************************************************************/
#define append_string(a,b) strcat(a,b)
/********************************************************/
static void
append_value (char *buf, int value, int size)
{
/*
* This routine appends a value in hex notation.
*/
char buffer[11];
buffer[0] = '\0';
switch (size)
{
case SIZE_BYTE:
sprintf(buffer,"0x%02X",value & 0x000000FF);
break;
case SIZE_WORD:
sprintf(buffer,"0x%04X",value & 0x0000FFFF);
break;
case SIZE_LONG:
sprintf(buffer,"0x%08X",value);
break;
}
strcat(buf,buffer);
}
/********************************************************************/
static int
append_size2 (char *buf, int opword, int size_offset, int instr_size)
{
/*
* This field accepts `opword' and then determines according
* to the offset which size is specified.
*
* The `offset' are given by the bit number as listed in the
* M68000 Family Programmer's Reference, Chapter 8. [15 .. 0]
*/
int i, j, mask;
mask = 0x3; /* 2 bits */
for (i = 1; i < size_offset; i++)
mask = mask << 1;
i = (opword & mask) >> (size_offset - 1);
if (instr_size)
{
for (j = 0; *(char *)((int)buf +j) != ' '; ++j)
;
buf[j] = '.';
switch (i)
{
case 1:
buf[++j] = 'B';
disasm_op_size = SIZE_BYTE;
break;
case 2:
buf[++j] = 'L';
disasm_op_size = SIZE_LONG;
break;
case 3:
buf[++j] = 'W';
disasm_op_size = SIZE_WORD;
break;
default:
valid_instruction = FALSE;
break;
}
}
else
{
switch (i)
{
case 1:
strcat(buf,".B");
break;
case 2:
strcat(buf,".L");
break;
case 3:
strcat(buf,".W");
break;
default:
valid_instruction = FALSE;
break;
}
}
return i;
}
/********************************************************************/
static int
append_size (char *buf, int opword, int size_offset, int instr_size)
{
/*
* This field accepts `opword' and then determines according
* to the offset which size is specified.
*
* The `offset' are given by the bit number as listed in the
* M68000 Family Programmer's Reference, Chapter 8. [15 .. 0]
*/
int i, j, mask;
mask = 0x3; /* 2 bits */
for (i = 1; i < size_offset; i++)
mask = mask << 1;
i = (opword & mask) >> (size_offset - 1);
disasm_op_size = -1;
if (instr_size)
{
for (j = 0; *(char *)((int)buf +j) != ' '; ++j)
;
buf[j] = '.';
switch (i)
{
case 0:
buf[++j] = 'B';
disasm_op_size = SIZE_BYTE;
break;
case 1:
buf[++j] = 'W';
disasm_op_size = SIZE_WORD;
break;
case 2:
buf[++j] = 'L';
disasm_op_size = SIZE_LONG;
break;
default:
valid_instruction = FALSE;
break;
}
}
else
{
switch (i)
{
case 0:
strcat(buf,".B");
break;
case 1:
strcat(buf,".W");
break;
case 2:
strcat(buf,".L");
break;
default:
valid_instruction = FALSE;
break;
}
}
return i;
}
/********************************************************************/
static void
append_register (char *buf, int opword, int reg_offset, int reg_num_offset)
{
/*
* This field accepts `opword' and then determines according
* to the offsets which register (A0..A7,D0..D7) is specified.
* The register name is then concatenated to the end of the
* disasm_stmt.
*
* The `offsets' are given by the bit number as listed in the
* M68000 Family Programmer's Reference, Chapter 8. [15 .. 0]
*/
int i, mask;
char regnum[3];
/* Determine what kind of register */
if (reg_offset == ADDRESS_REGISTER)
{
strcat(buf,"A");
}
else
{
if (reg_offset == DATA_REGISTER)
{
strcat(buf,"D");
}
else
{
mask = 1;
for (i = 0; i < reg_offset; i++)
mask = mask << 1;
if (opword & mask)
strcat(buf,"A");
else
strcat(buf,"D");
}
}
/* determine register number */
/* The offset given is the msb of the 3 bit field containing */
/* the register number. */
mask = 0x7; /* 3 bits */
for (i = 2; i < reg_num_offset; i++)
mask = mask << 1;
i = (opword & mask) >> (reg_num_offset - 2);
sprintf(regnum,"%d",i);
strcat(buf,regnum);
}
/********************************************************************/
static void
append_displacement (char *buf, int extension, int disp_offset)
{
/*
* This function determines and appends a 16 or 32 bit disp.
* The `offsets' are given by the bit number as listed in the
* M68000 Family Programmer's Reference, Chapter 2. [15 .. 0]
*/
int i, mask, disp;
mask = 0x3; /* 2 bits */
for (i = 1; i < disp_offset; i++)
mask = mask << 1;
i = (extension & mask) >> (disp_offset - 1);
switch (i)
{
case 0:
case 1:
break;
case 2:
disp = (int)((int16)cpu_read_data(disasm_pc, SIZE_16));
inc_disasm_pc(2);
append_value(buf, disp, SIZE_16);
break;
case 3:
disp = (int)((int32)cpu_read_data(disasm_pc, SIZE_32));
inc_disasm_pc(4);
append_value(buf, disp, SIZE_32);
break;
}
}
/********************************************************************/
static void
append_size_scale (char *buf, int extension, int size_offset, int scale_offset)
{
/*
* This function determines the size and scale information
* for addressing modes that require it.
*
* The `offsets' are given by the bit number as listed in the
* M68000 Family Programmer's Reference, Chapter 2. [15 .. 0]
*/
int i, mask, size, scale;
mask = 0x1; /* 1 bits */
for (i = 0; i < size_offset; i++)
mask = mask << 1;
size = (extension & mask) >> size_offset;
mask = 0x3; /* 2 bits */
for (i = 1; i < scale_offset; i++)
mask = mask << 1;
scale = (extension & mask) >> (scale_offset - 1);
if (size)
append_string(buf,".L");
else
append_string(buf,".W");
switch (scale)
{
case 0:
append_string(buf,"*1");
break;
case 1:
append_string(buf,"*2");
break;
case 2:
append_string(buf,"*4");
break;
case 3:
/* valid_instruction = FALSE; */
append_string(buf,"*8");
break;
}
}
/********************************************************************/
static int
append_ea (char *buf, int opword, int offset, int ea_mask)
{
/*
* This routine creates the addressing mode. The
* extensions for the addressing mode, if necessary,
* start at disasm_pc
*/
int i, mask, mode, reg, ea;
char buffer[9];
#if (defined(SYMBOL_TABLE))
char tstr[100];
#endif
ea = EA_NONE;
/* get addressing mode */
mask = 0x7; /* 3 bits */
for (i = 2; i < offset; i++)
mask = mask << 1;
mode = (opword & mask) >> (offset - 2);
/* get register */
mask = 0x7; /* 3 bits */
for (i = 2; i < (offset - 3); i++)
mask = mask << 1;
reg = (opword & mask) >> (offset -3 - 2);
switch (mode)
{
case 0: /* data register direct mode */
append_register(buf,reg,DATA_REGISTER,2);
ea = DRD;
break;
case 1: /* address register direct mode */
append_register(buf,reg,ADDRESS_REGISTER,2);
ea = ARD;
break;
case 2: /* address register indirect mode (ARI) */
append_string(buf,"(");
append_register(buf,reg,ADDRESS_REGISTER,2);
append_string(buf,")");
ea = ARI;
break;
case 3: /* ARI with postincrement mode */
append_string(buf,"(");
append_register(buf,reg,ADDRESS_REGISTER,2);
append_string(buf,")+");
ea = ARIPO;
break;
case 4: /* ARI with predecrement mode */
append_string(buf,"-(");
append_register(buf,reg,ADDRESS_REGISTER,2);
append_string(buf,")");
ea = ARIPR;
break;
case 5: /* ARI with displacement mode */
{
int disp;
disp = (int)((int16)cpu_read_data((ADDRESS)disasm_pc,16));
inc_disasm_pc(2);
sprintf(buffer,"%d",disp);
append_string(buf,buffer);
append_string(buf,"(");
append_register(buf,reg,ADDRESS_REGISTER,2);
append_string(buf,")");
ea = ARID;
}
break;
case 6:
{
/* this mode is overloaded. the encoding in the */
/* extension byte indicate which of the 4 modes */
/* */
/* [xxxxxxx0xxxx0000] ARI 8bit displacement */
/* [xxxxxxx1xxxx0000] ARI base displacement */
/* [xxxxxxx1xxxx00xx] memory indirect pre index */
/* [xxxxxxx1xxxx01xx] memory indirect post index */
/* */
int extension;
extension = (int)*(uint16 *)disasm_pc;
inc_disasm_pc(2);
if (extension & 0x0100)
{
/* ARI base or memory indirects */
if (extension & 0x0007)
{
/* memory indirects */
if (extension & 0x0004)
{
/* memory indirect post index */
append_string(buf,"(");
append_string(buf,"[");
append_displacement(buf,extension,5);
append_string(buf,",");
append_register(buf,reg,ADDRESS_REGISTER,2);
append_string(buf,"]");
append_string(buf,",");
append_register(buf,extension,15,14);
append_size_scale(buf,extension,11,10);
append_string(buf,",");
append_displacement(buf,extension,1);
ea = MIPO;
}
else
{
/* memory indirect pre index */
append_string(buf,"(");
append_string(buf,"[");
append_displacement(buf,extension,5);
append_string(buf,",");
append_register(buf,reg,ADDRESS_REGISTER,2);
append_string(buf,",");
append_register(buf,extension,15,14);
append_size_scale(buf,extension,11,10);
append_string(buf,"]");
append_string(buf,",");
append_displacement(buf,extension,1);
ea = MIPR;
}
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -