Mercurial > repos > blastem
comparison 68kinst.c @ 13:168b1a873895
Improve disassembly. FIx some decoding bugs.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 15 Nov 2012 22:15:43 -0800 |
parents | db60ed283d8d |
children | c0f339564819 |
comparison
equal
deleted
inserted
replaced
12:db60ed283d8d | 13:168b1a873895 |
---|---|
401 } | 401 } |
402 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); | 402 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); |
403 decoded->dst.addr_mode = MODE_REG; | 403 decoded->dst.addr_mode = MODE_REG; |
404 decoded->dst.addr_mode = m68K_reg_quick_field(*istream); | 404 decoded->dst.addr_mode = m68K_reg_quick_field(*istream); |
405 } else { | 405 } else { |
406 if ((*istream & 0xB80) == 0x880) { | 406 opmode = (*istream >> 3) & 0x7; |
407 if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG && opmode != MODE_AREG_POSTINC) { | |
407 decoded->op = M68K_MOVEM; | 408 decoded->op = M68K_MOVEM; |
408 decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD; | 409 decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD; |
410 reg = *istream & 0x7; | |
409 immed = *(++istream); | 411 immed = *(++istream); |
410 opmode = (*istream >> 3) & 0x7; | |
411 reg = *istream & 0x7; | |
412 if(*istream & 0x400) { | 412 if(*istream & 0x400) { |
413 decoded->dst.addr_mode = MODE_REG; | 413 decoded->dst.addr_mode = MODE_REG; |
414 decoded->dst.params.u16 = immed; | 414 decoded->dst.params.u16 = immed; |
415 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src)); | 415 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src)); |
416 } else { | 416 } else { |
519 default: | 519 default: |
520 if (!(*istream & 0x1C0)) { | 520 if (!(*istream & 0x1C0)) { |
521 decoded->op = M68K_NBCD; | 521 decoded->op = M68K_NBCD; |
522 decoded->extra.size = OPSIZE_BYTE; | 522 decoded->extra.size = OPSIZE_BYTE; |
523 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); | 523 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); |
524 } else if(*istream & 0x1C0 == 0x40) { | 524 } else if((*istream & 0x1C0) == 0x40) { |
525 decoded->op = M68K_PEA; | 525 decoded->op = M68K_PEA; |
526 decoded->extra.size = OPSIZE_LONG; | 526 decoded->extra.size = OPSIZE_LONG; |
527 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst)); | 527 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst)); |
528 } | 528 } |
529 } | 529 } |
580 decoded->op = M68K_LINK; | 580 decoded->op = M68K_LINK; |
581 decoded->extra.size = OPSIZE_WORD; | 581 decoded->extra.size = OPSIZE_WORD; |
582 decoded->src.addr_mode = MODE_AREG; | 582 decoded->src.addr_mode = MODE_AREG; |
583 decoded->src.params.regs.pri = *istream & 0x7; | 583 decoded->src.params.regs.pri = *istream & 0x7; |
584 decoded->dst.addr_mode = MODE_IMMEDIATE; | 584 decoded->dst.addr_mode = MODE_IMMEDIATE; |
585 decoded->dst.params.u16 = immed; | 585 decoded->dst.params.u16 = *(++istream); |
586 break; | 586 break; |
587 case 3: | 587 case 3: |
588 //UNLK | 588 //UNLK |
589 decoded->op = M68K_UNLK; | 589 decoded->op = M68K_UNLK; |
590 decoded->extra.size = OPSIZE_UNSIZED; | 590 decoded->extra.size = OPSIZE_UNSIZED; |
1047 char * mnemonics[] = { | 1047 char * mnemonics[] = { |
1048 "abcd", | 1048 "abcd", |
1049 "add", | 1049 "add", |
1050 "addx", | 1050 "addx", |
1051 "and", | 1051 "and", |
1052 "andi_ccr", | 1052 "andi",//ccr |
1053 "andi_sr", | 1053 "andi",//sr |
1054 "asl", | 1054 "asl", |
1055 "asr", | 1055 "asr", |
1056 "bcc", | 1056 "bcc", |
1057 "bchg", | 1057 "bchg", |
1058 "bclr", | 1058 "bclr", |
1064 "cmp", | 1064 "cmp", |
1065 "dbcc", | 1065 "dbcc", |
1066 "divs", | 1066 "divs", |
1067 "divu", | 1067 "divu", |
1068 "eor", | 1068 "eor", |
1069 "eori_ccr", | 1069 "eori",//ccr |
1070 "eori_sr", | 1070 "eori",//sr |
1071 "exg", | 1071 "exg", |
1072 "ext", | 1072 "ext", |
1073 "illegal", | 1073 "illegal", |
1074 "jmp", | 1074 "jmp", |
1075 "jsr", | 1075 "jsr", |
1076 "lea", | 1076 "lea", |
1077 "link", | 1077 "link", |
1078 "lsl", | 1078 "lsl", |
1079 "lsr", | 1079 "lsr", |
1080 "move", | 1080 "move", |
1081 "move_ccr", | 1081 "move",//ccr |
1082 "move_from_sr", | 1082 "move",//from_sr |
1083 "move_sr", | 1083 "move",//sr |
1084 "move_usp", | 1084 "move_usp", |
1085 "movem", | 1085 "movem", |
1086 "movep", | 1086 "movep", |
1087 "muls", | 1087 "muls", |
1088 "mulu", | 1088 "mulu", |
1090 "neg", | 1090 "neg", |
1091 "negx", | 1091 "negx", |
1092 "nop", | 1092 "nop", |
1093 "not", | 1093 "not", |
1094 "or", | 1094 "or", |
1095 "ori_ccr", | 1095 "ori",//ccr |
1096 "ori_sr", | 1096 "ori",//sr |
1097 "pea", | 1097 "pea", |
1098 "reset", | 1098 "reset", |
1099 "rol", | 1099 "rol", |
1100 "ror", | 1100 "ror", |
1101 "roxl", | 1101 "roxl", |
1134 "lt", | 1134 "lt", |
1135 "gt", | 1135 "gt", |
1136 "le" | 1136 "le" |
1137 }; | 1137 }; |
1138 | 1138 |
1139 int m68K_disasm_op(m68k_op_info *decoded, uint8_t size, char *dst, int need_comma) | 1139 int m68k_disasm_op(m68k_op_info *decoded, uint8_t size, char *dst, int need_comma) |
1140 { | 1140 { |
1141 char * c = need_comma ? "," : ""; | 1141 char * c = need_comma ? "," : ""; |
1142 switch(decoded->addr_mode) | 1142 switch(decoded->addr_mode) |
1143 { | 1143 { |
1144 case MODE_REG: | 1144 case MODE_REG: |
1149 return sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); | 1149 return sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); |
1150 case MODE_AREG_POSTINC: | 1150 case MODE_AREG_POSTINC: |
1151 return sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri); | 1151 return sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri); |
1152 case MODE_AREG_PREDEC: | 1152 case MODE_AREG_PREDEC: |
1153 return sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri); | 1153 return sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri); |
1154 case MODE_AREG_DISPLACE: | |
1155 return sprintf(dst, "%s (a%d, %d)", c, decoded->params.regs.pri, decoded->params.regs.displacement); | |
1154 case MODE_IMMEDIATE: | 1156 case MODE_IMMEDIATE: |
1155 return sprintf(dst, "%s #%d", c, (size == OPSIZE_LONG || size == OPSIZE_UNSIZED) ? decoded->params.u32 : (size == OPSIZE_WORD ? decoded->params.u16 : decoded->params.u8)); | 1157 return sprintf(dst, "%s #%d", c, (size == OPSIZE_LONG || size == OPSIZE_UNSIZED) ? decoded->params.u32 : (size == OPSIZE_WORD ? decoded->params.u16 : decoded->params.u8)); |
1158 case MODE_ABSOLUTE_SHORT: | |
1159 return sprintf(dst, "%s $%X.w", c, decoded->params.u32); | |
1160 case MODE_ABSOLUTE: | |
1161 return sprintf(dst, "%s $%X", c, decoded->params.u32); | |
1162 case MODE_PC_DISPLACE: | |
1163 return sprintf(dst, "%s (pc, %d)", c, decoded->params.regs.displacement); | |
1156 default: | 1164 default: |
1157 return 0; | 1165 return 0; |
1166 } | |
1167 } | |
1168 | |
1169 int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, uint8_t size, char *dst, int need_comma) | |
1170 { | |
1171 int8_t dir, reg, bit, regnum, last=-1, lastreg, first=-1; | |
1172 char *rtype, *last_rtype; | |
1173 int oplen; | |
1174 if (decoded->addr_mode == MODE_REG) { | |
1175 if (other->addr_mode == MODE_AREG_PREDEC) { | |
1176 bit = 15; | |
1177 dir = -1; | |
1178 } else { | |
1179 reg = 0; | |
1180 bit = 1; | |
1181 } | |
1182 strcat(dst, " "); | |
1183 for (oplen = 1, reg=0; bit < 16 && bit > -1; bit += dir, reg++) { | |
1184 if (decoded->params.u16 & (1 << bit)) { | |
1185 if (reg > 7) { | |
1186 rtype = "a"; | |
1187 regnum = reg - 8; | |
1188 } else { | |
1189 rtype = "d"; | |
1190 regnum = reg; | |
1191 } | |
1192 if (last >= 0 && last == regnum - 1 && lastreg == reg - 1) { | |
1193 last = regnum; | |
1194 lastreg = reg; | |
1195 } else if(last >= 0) { | |
1196 if (first != last) { | |
1197 oplen += sprintf(dst + oplen, "-%s%d/%s%d",last_rtype, last, rtype, regnum); | |
1198 } else { | |
1199 oplen += sprintf(dst + oplen, "/%s%d", rtype, regnum); | |
1200 } | |
1201 first = last = regnum; | |
1202 last_rtype = rtype; | |
1203 lastreg = reg; | |
1204 } else { | |
1205 oplen += sprintf(dst + oplen, "%s%d", rtype, regnum); | |
1206 first = last = regnum; | |
1207 last_rtype = rtype; | |
1208 lastreg = reg; | |
1209 } | |
1210 } | |
1211 } | |
1212 if (last >= 0 && last != first) { | |
1213 oplen += sprintf(dst + oplen, "-%s%d", last_rtype, last); | |
1214 } | |
1215 return oplen; | |
1216 } else { | |
1217 return m68k_disasm_op(decoded, size, dst, need_comma); | |
1158 } | 1218 } |
1159 } | 1219 } |
1160 | 1220 |
1161 int m68k_disasm(m68kinst * decoded, char * dst) | 1221 int m68k_disasm(m68kinst * decoded, char * dst) |
1162 { | 1222 { |
1163 int ret,op1len; | 1223 int ret,op1len; |
1164 uint8_t size; | 1224 uint8_t size; |
1165 if (decoded->op == M68K_BCC || decoded->op == M68K_DBCC || decoded->op == M68K_SCC) { | 1225 char * special_op = "CCR"; |
1226 switch (decoded->op) | |
1227 { | |
1228 case M68K_BCC: | |
1229 case M68K_DBCC: | |
1230 case M68K_SCC: | |
1166 ret = strlen(mnemonics[decoded->op]) - 2; | 1231 ret = strlen(mnemonics[decoded->op]) - 2; |
1167 memcpy(dst, mnemonics[decoded->op], ret); | 1232 memcpy(dst, mnemonics[decoded->op], ret); |
1168 dst[ret] = 0; | 1233 dst[ret] = 0; |
1169 strcat(dst, cond_mnem[decoded->extra.cond]); | 1234 strcat(dst, cond_mnem[decoded->extra.cond]); |
1170 ret = strlen(dst); | 1235 ret = strlen(dst); |
1171 size = decoded->op = M68K_BCC ? OPSIZE_LONG : OPSIZE_WORD; | 1236 size = decoded->op = M68K_BCC ? OPSIZE_LONG : OPSIZE_WORD; |
1172 } else if (decoded->op == M68K_BSR) { | 1237 break; |
1238 case M68K_BSR: | |
1173 size = OPSIZE_LONG; | 1239 size = OPSIZE_LONG; |
1174 ret = sprintf(dst, "bsr%s", decoded->variant == VAR_BYTE ? ".s" : ""); | 1240 ret = sprintf(dst, "bsr%s", decoded->variant == VAR_BYTE ? ".s" : ""); |
1175 } else { | 1241 break; |
1242 case M68K_MOVE_FROM_SR: | |
1243 ret = sprintf(dst, "%s", mnemonics[decoded->op]); | |
1244 ret += sprintf(dst + ret, " SR"); | |
1245 ret += m68k_disasm_op(&(decoded->dst), decoded->extra.size, dst + ret, 1); | |
1246 return ret; | |
1247 case M68K_ANDI_SR: | |
1248 case M68K_EORI_SR: | |
1249 case M68K_MOVE_SR: | |
1250 case M68K_ORI_SR: | |
1251 special_op = "SR"; | |
1252 case M68K_ANDI_CCR: | |
1253 case M68K_EORI_CCR: | |
1254 case M68K_MOVE_CCR: | |
1255 case M68K_ORI_CCR: | |
1256 ret = sprintf(dst, "%s", mnemonics[decoded->op]); | |
1257 ret += m68k_disasm_op(&(decoded->src), decoded->extra.size, dst + ret, 0); | |
1258 ret += sprintf(dst + ret, ", %s", special_op); | |
1259 return ret; | |
1260 default: | |
1176 size = decoded->extra.size; | 1261 size = decoded->extra.size; |
1177 ret = sprintf(dst, "%s%s.%s", | 1262 ret = sprintf(dst, "%s%s%s", |
1178 mnemonics[decoded->op], | 1263 mnemonics[decoded->op], |
1179 decoded->variant == VAR_QUICK ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""), | 1264 decoded->variant == VAR_QUICK ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""), |
1180 size == OPSIZE_BYTE ? "b" : (size == OPSIZE_WORD ? "w" : (size == OPSIZE_LONG ? "l" : ""))); | 1265 size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : ""))); |
1181 } | 1266 } |
1182 op1len = m68K_disasm_op(&(decoded->src), size, dst + ret, 0); | 1267 if (decoded->op == M68K_MOVEM) { |
1183 ret += op1len; | 1268 op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), size, dst + ret, 0); |
1184 ret += m68K_disasm_op(&(decoded->dst), size, dst + ret, op1len); | 1269 ret += op1len; |
1270 ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), size, dst + ret, op1len); | |
1271 } else { | |
1272 op1len = m68k_disasm_op(&(decoded->src), size, dst + ret, 0); | |
1273 ret += op1len; | |
1274 ret += m68k_disasm_op(&(decoded->dst), size, dst + ret, op1len); | |
1275 } | |
1185 return ret; | 1276 return ret; |
1186 } | 1277 } |
1187 | 1278 |