00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "alphadis.h"
00022 #include "alphaopc.h"
00023 #include "htdebug.h"
00024 #include "tools.h"
00025
00026 #include <stdlib.h>
00027 #include <string.h>
00028
00029 #define BITS_OPC(opcode) ((opcode >> 26) & 0x3f)
00030 #define BITS_FFUN(opcode) ((opcode >> 5) & 0x7ff)
00031 #define BITS_IFUN(opcode) ((opcode >> 5) & 0x7f)
00032 #define BITS_MFUN(opcode) (opcode & 0xffff)
00033 #define BITS_JFUN(opcode) ((opcode >> 14) & 0x3)
00034 #define BITS_ISLIT(opcode) ((opcode >> 12) & 0x1)
00035 #define BITS_IMMED(opcode) ((opcode >> 13) & 0xff)
00036 #define BITS_REGA(opcode) ((opcode >> 21) & 0x1f)
00037 #define BITS_REGB(opcode) ((opcode >> 16) & 0x1f)
00038 #define BITS_REGC(opcode) (opcode & 0x1f)
00039 #define BITS_BDISP(opcode) (opcode & 0x1fffff)
00040 #define BITS_BSIGN(opcode) (opcode & 0x100000)
00041 #define BITS_MDISP(opcode) (opcode & 0xffff)
00042 #define BITS_MSIGN(opcode) (opcode & 0x8000)
00043 #define BITS_PAL(opcode) (opcode & 0x3ffffff)
00044 #define BITS_HINT(opcode) (opcode & 0x3fff)
00045
00046
00047 #define MAKE_OPC(opcode) ((opcode & 0x3f) << 26)
00048 #define MAKE_FFUN(opcode) ((opcode & 0x7ff) << 5)
00049 #define MAKE_IFUN(opcode) ((opcode & 0x7f) << 5)
00050 #define MAKE_MFUN(opcode) (opcode & 0xffff)
00051 #define MAKE_JFUN(opcode) ((opcode & 0x3) << 14)
00052 #define MAKE_LIT (1<<12)
00053 #define MAKE_IMMED(opcode) ((opcode & 0xff) << 13 )
00054 #define MAKE_REGA(opcode) ((opcode & 0x1f) << 21)
00055 #define MAKE_REGB(opcode) ((opcode & 0x1f) << 16)
00056 #define MAKE_REGC(opcode) (opcode & 0x1f)
00057 #define MAKE_BDISP(opcode) (opcode & 0x1fffff)
00058 #define MAKE_MDISP(opcode) (opcode & 0xffff)
00059 #define MAKE_PAL(opcode) (opcode & 0x3ffffff)
00060 #define MAKE_HINT(opcode) (opcode & 0x3fff)
00061
00062 Alphadis::Alphadis():Disassembler()
00063 {
00064 insn.valid = false;
00065 }
00066
00067 Alphadis::~Alphadis()
00068 {
00069 }
00070
00071 int Alphadis::load(ht_object_stream *f)
00072 {
00073 return Disassembler::load(f);
00074 }
00075
00076 int find_alpha_instruction(alpha_opcode_tab_entry *table, int f)
00077 {
00078 int i=0;
00079 while (f > (table+i)->fcode) i++;
00080 return i;
00081 }
00082
00083 dis_insn *Alphadis::decode(byte *code, int maxlen, CPU_ADDR addr)
00084 {
00085
00086 if (maxlen < 4) {
00087
00088 insn.valid = false;
00089 insn.size = maxlen;
00090 insn.table = 0;
00091
00092 UNALIGNED_MOVE(insn.data, *(dword *)code);
00093 } else {
00094 insn.valid = true;
00095 insn.size = 4;
00096 insn.table = &alpha_instr_tbl[0];
00097 dword opcode = *((dword *)code);
00098 int idx = BITS_OPC(opcode);
00099 switch (alpha_instr_tbl[idx].type) {
00100 case ALPHA_EXTENSION_10:
00101 idx = find_alpha_instruction(&alpha_instr_tbl_ext10[0], BITS_IFUN(opcode));
00102 insn.table = &alpha_instr_tbl_ext10[0];
00103 break;
00104 case ALPHA_EXTENSION_11:
00105 idx = find_alpha_instruction(&alpha_instr_tbl_ext11[0], BITS_IFUN(opcode));
00106 insn.table = &alpha_instr_tbl_ext11[0];
00107 break;
00108 case ALPHA_EXTENSION_12:
00109 idx = find_alpha_instruction(&alpha_instr_tbl_ext12[0], BITS_IFUN(opcode));
00110 insn.table = &alpha_instr_tbl_ext12[0];
00111 break;
00112 case ALPHA_EXTENSION_13:
00113 idx = find_alpha_instruction(&alpha_instr_tbl_ext13[0], BITS_IFUN(opcode));
00114 insn.table = &alpha_instr_tbl_ext13[0];
00115 break;
00116 case ALPHA_EXTENSION_14:
00117 idx = find_alpha_instruction(&alpha_instr_tbl_ext14[0], BITS_FFUN(opcode));
00118 insn.table = &alpha_instr_tbl_ext14[0];
00119 break;
00120 case ALPHA_EXTENSION_15:
00121 idx = find_alpha_instruction(&alpha_instr_tbl_ext15[0], BITS_FFUN(opcode));
00122 insn.table = &alpha_instr_tbl_ext15[0];
00123 break;
00124 case ALPHA_EXTENSION_16:
00125 idx = find_alpha_instruction(&alpha_instr_tbl_ext16[0], BITS_FFUN(opcode));
00126 insn.table = &alpha_instr_tbl_ext16[0];
00127 break;
00128 case ALPHA_EXTENSION_17:
00129 idx = find_alpha_instruction(&alpha_instr_tbl_ext17[0], BITS_FFUN(opcode));
00130 insn.table = &alpha_instr_tbl_ext17[0];
00131 break;
00132 case ALPHA_EXTENSION_18:
00133 idx = find_alpha_instruction(&alpha_instr_tbl_ext18[0], BITS_MFUN(opcode));
00134 insn.table = &alpha_instr_tbl_ext18[0];
00135 break;
00136 case ALPHA_EXTENSION_1A:
00137 idx = find_alpha_instruction(&alpha_instr_tbl_ext1a[0], BITS_JFUN(opcode));
00138 insn.table = &alpha_instr_tbl_ext1a[0];
00139 break;
00140 case ALPHA_EXTENSION_1C:
00141 idx = find_alpha_instruction(&alpha_instr_tbl_ext1c[0], BITS_IFUN(opcode));
00142 insn.table = &alpha_instr_tbl_ext1c[0];
00143 break;
00144 }
00145
00146 insn.code = idx;
00147
00148 switch ((insn.table+idx)->type) {
00149 case ALPHA_GROUP1:
00150 insn.regA = BITS_REGA(opcode);
00151 insn.regC = BITS_REGC(opcode);
00152 if (BITS_ISLIT(opcode)) {
00153 insn.regB = REG_LIT;
00154 insn.data = BITS_IMMED(opcode);
00155 } else {
00156 insn.regB = BITS_REGB(opcode);
00157 insn.data = 0;
00158 }
00159 break;
00160 case ALPHA_GROUP2:
00161 insn.regA = BITS_REGA(opcode) + REG_FLOAT;
00162 insn.regB = BITS_REGB(opcode) + REG_FLOAT;
00163 insn.regC = BITS_REGC(opcode) + REG_FLOAT;
00164 insn.data = 0;
00165 break;
00166 case ALPHA_GROUP3:
00167 insn.regA = BITS_REGA(opcode);
00168 insn.regB = BITS_REGB(opcode);
00169 insn.regC = REG_ZERO;
00170 insn.data = BITS_MDISP(opcode);
00171 if (BITS_MSIGN(insn.data)) insn.data |= -1 ^ 0xffff;
00172 break;
00173 case ALPHA_GROUP_FLD:
00174 insn.regA = BITS_REGA(opcode) + REG_FLOAT;
00175 insn.regB = BITS_REGB(opcode);
00176 insn.regC = REG_ZERO;
00177 insn.data = BITS_MDISP(opcode);
00178 if (BITS_MSIGN(insn.data)) insn.data |= -1 ^ 0xffff;
00179 break;
00180 case ALPHA_GROUP4:
00181 insn.regA = BITS_REGA(opcode);
00182 insn.regB = BITS_REGB(opcode);
00183 insn.regC = REG_ZERO;
00184 insn.data = BITS_MDISP(opcode);
00185 if (BITS_MSIGN(insn.data)) insn.data |= -1 ^ 0xffff;
00186 break;
00187 case ALPHA_GROUP_FST:
00188 insn.regA = BITS_REGA(opcode) + REG_FLOAT;
00189 insn.regB = BITS_REGB(opcode);
00190 insn.regC = REG_ZERO;
00191 insn.data = BITS_MDISP(opcode);
00192 if (BITS_MSIGN(insn.data)) insn.data |= -1 ^ 0xffff;
00193 break;
00194 case ALPHA_GROUP_F2I:
00195 insn.regA = BITS_REGA(opcode) + REG_FLOAT;
00196 insn.regB = REG_ZERO;
00197 insn.regC = BITS_REGC(opcode);
00198 insn.data = 0;
00199 break;
00200 case ALPHA_GROUP_I2F:
00201 insn.regA = BITS_REGA(opcode);
00202 insn.regB = REG_ZERO;
00203 insn.regC = BITS_REGC(opcode) + REG_FLOAT;
00204 insn.data = 0;
00205 break;
00206 case ALPHA_GROUP_BRA:
00207 insn.regA = BITS_REGA(opcode);
00208 insn.regB = REG_ZERO;
00209 insn.regC = REG_ZERO;
00210 insn.data = BITS_BDISP(opcode);
00211 if (BITS_BSIGN(insn.data)) insn.data |= -1 ^ 0x1fffff;
00212 insn.data += 1;
00213 insn.data *= 4;
00214 insn.data += addr.addr32.offset;
00215 break;
00216 case ALPHA_GROUP_FBR:
00217 insn.regA = BITS_REGA(opcode) + REG_FLOAT;
00218 insn.regB = REG_ZERO;
00219 insn.regC = REG_ZERO;
00220 insn.data = BITS_BDISP(opcode);
00221 if (BITS_BSIGN(insn.data)) insn.data |= -1 ^ 0x1fffff;
00222 insn.data += 1;
00223 insn.data *= 4;
00224 insn.data += addr.addr32.offset;
00225 break;
00226 case ALPHA_GROUP_JMP:
00227 insn.regA = BITS_REGA(opcode);
00228 insn.regB = BITS_REGB(opcode);
00229 insn.regC = REG_ZERO;
00230 insn.data = BITS_HINT(opcode);
00231 break;
00232 case ALPHA_GROUP_PAL:
00233 insn.regA = REG_ZERO;
00234 insn.regB = REG_ZERO;
00235 insn.regC = REG_ZERO;
00236 insn.data = BITS_PAL(opcode);
00237 break;
00238 default:
00239 insn.valid = false;
00240 insn.data = *(dword *)code;
00241 break;
00242 }
00243 }
00244 return &insn;
00245 }
00246
00247 dis_insn *Alphadis::duplicateInsn(dis_insn *disasm_insn)
00248 {
00249 alphadis_insn *insn = (alphadis_insn *)malloc(sizeof (alphadis_insn));
00250 *insn = *(alphadis_insn *)disasm_insn;
00251 return insn;
00252 }
00253
00254 void Alphadis::getOpcodeMetrics(int &min_length, int &max_length, int &min_look_ahead, int &avg_look_ahead, int &addr_align)
00255 {
00256 min_length = 4;
00257 max_length = 4;
00258 min_look_ahead = 4;
00259 avg_look_ahead = 4;
00260 addr_align = 4;
00261 }
00262
00263 char *Alphadis::getName()
00264 {
00265 return "alpha/disassembler";
00266 }
00267
00268 byte Alphadis::getSize(dis_insn *disasm_insn)
00269 {
00270 return ((alphadis_insn*)disasm_insn)->size;
00271 }
00272
00273 OBJECT_ID Alphadis::object_id() const
00274 {
00275 return ATOM_DISASM_ALPHA;
00276 }
00277
00278 void Alphadis::store(ht_object_stream *f)
00279 {
00280 Disassembler::store(f);
00281 }
00282
00283 char *Alphadis::str(dis_insn *disasm_insn, int style)
00284 {
00285 return strf(disasm_insn, style, "");
00286 }
00287
00288 #define A_REG_A alpha_reg_names[alpha_insn->regA]
00289 #define A_REG_B alpha_reg_names[alpha_insn->regB]
00290 #define A_REG_C alpha_reg_names[alpha_insn->regC]
00291 #define A_NAME (alpha_insn->table+alpha_insn->code)->name
00292
00293 char *Alphadis::strf(dis_insn *disasm_insn, int style, char *format)
00294 {
00295 if (style & DIS_STYLE_HIGHLIGHT) enable_highlighting();
00296
00297 const char *cs_default = get_cs(e_cs_default);
00298 const char *cs_number = get_cs(e_cs_number);
00299 const char *cs_symbol = get_cs(e_cs_symbol);
00300
00301 alphadis_insn *alpha_insn = (alphadis_insn *) disasm_insn;
00302
00303 if (!alpha_insn->valid) {
00304 is_invalid:
00305 switch (alpha_insn->size) {
00306 case 1:
00307 strcpy(insnstr, "db ?");
00308 break;
00309 case 2:
00310 strcpy(insnstr, "dw ?");
00311 break;
00312 case 3:
00313 strcpy(insnstr, "db ? * 3");
00314 break;
00315 case 4:
00316 sprintf(insnstr, "dd %s0x%08lx", cs_number, alpha_insn->data);
00317 break;
00318 default: {
00319 assert(0);
00320 }
00321 }
00322 } else switch ((alpha_insn->table+alpha_insn->code)->type) {
00323 case ALPHA_GROUP1:
00324 case ALPHA_GROUP2:
00325 if (alpha_insn->regB != REG_LIT)
00326 sprintf(insnstr, "%-10s %s%s,%s %s%s,%s %s", A_NAME, A_REG_A, cs_symbol, cs_default, A_REG_B, cs_symbol, cs_default, A_REG_C);
00327 else
00328 sprintf(insnstr, "%-10s %s%s,%s %s0x%lx%s,%s %s", A_NAME, A_REG_A, cs_symbol, cs_default, cs_number, alpha_insn->data, cs_symbol, cs_default, A_REG_C);
00329 break;
00330 case ALPHA_GROUP3:
00331 case ALPHA_GROUP_FLD:
00332 case ALPHA_GROUP4:
00333 case ALPHA_GROUP_FST: {
00334 short sdata = (short)(alpha_insn->data&0xffff);
00335 char c;
00336 if (sdata<0) {
00337 c = '-';
00338 sdata = -sdata;
00339 } else {
00340 c = '+';
00341 }
00342 sprintf(insnstr, "%-10s %s%s, [%s%s%s%c%s0x%x%s]", A_NAME, A_REG_A, cs_symbol, cs_default, A_REG_B, cs_symbol, c, cs_number, sdata, cs_symbol);
00343 break;
00344 }
00345 case ALPHA_GROUP_I2F:
00346 case ALPHA_GROUP_F2I:
00347 sprintf(insnstr, "%-10s %s%s,%s %s", A_NAME, A_REG_A, cs_symbol, cs_default, A_REG_C);
00348 break;
00349 case ALPHA_GROUP_BRA:
00350 case ALPHA_GROUP_FBR: {
00351 CPU_ADDR caddr;
00352 caddr.addr32.offset = (dword)alpha_insn->data;
00353 int slen;
00354 char *p;
00355 char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
00356 if (s) {
00357 p = insnstr+sprintf(insnstr, "%-10s %s%s,%s ", A_NAME, A_REG_A, cs_symbol, cs_default);
00358 memmove(p, s, slen);
00359 p[slen] = 0;
00360 } else {
00361 sprintf(insnstr, "%-10s %s%s, %s0x%x", A_NAME, A_REG_A, cs_symbol, cs_number, (dword)alpha_insn->data);
00362 }
00363 break;
00364 }
00365 case ALPHA_GROUP_JMP: {
00366 CPU_ADDR caddr;
00367 caddr.addr32.offset = (dword)alpha_insn->data;
00368 int slen;
00369 char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
00370 if (s) {
00371 char *p = insnstr + sprintf(insnstr, "%-10s %s %s(%s%s%s),%s ", A_NAME, A_REG_A, cs_symbol, cs_default, A_REG_B, cs_symbol, cs_default);
00372 memmove(p, s, slen);
00373 p[slen] = 0;
00374 } else {
00375 sprintf(insnstr, "%-10s %s %s(%s%s%s), %s0x%x", A_NAME, A_REG_A, cs_symbol, cs_default, A_REG_B, cs_symbol, cs_number, (dword)alpha_insn->data);
00376 }
00377 break;
00378 }
00379 case ALPHA_GROUP_PAL:
00380 sprintf(insnstr, "%-10s %s0x%08lx", A_NAME, cs_number, alpha_insn->data);
00381 break;
00382 default:
00383 goto is_invalid;
00384 }
00385 disable_highlighting();
00386 return insnstr;
00387 }
00388
00389 bool Alphadis::validInsn(dis_insn *disasm_insn)
00390 {
00391 return ((alphadis_insn *)disasm_insn)->valid;
00392 }
00393