/* Hey EMACS -*- linux-c -*- */ /* $Id: error.c 680 2004-10-11 16:45:27Z roms $ */ /* TiEmu - an TI emulator * * Copyright (c) 2000-2001, Thomas Corvazier, Romain Lievin * Copyright (c) 2001-2003, Romain Lievin * Copyright (c) 2003, Julien Blache * Copyright (c) 2004, Romain Liévin * Copyright (c) 2005, Romain Liévin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* A pseudo-FPU disassembler. Many informations comes from the TI's BCD artihmetic package: */ #include #include #include typedef struct { uint16_t code; char* name; } TUPLE; // 6 chars max TUPLE operators[9] = { { 0x0000, "FCMP" }, { 0x1000, "FADD" }, { 0x2000, "FDIV" }, { 0x3000, "FMUL" }, { 0x4000, "FSUB" }, { 0x5000, "FINTRZ" }, { 0x6000, "FMOVE" }, { 0x7000, "FNEG" }, { 0x8000, "FTST" }, }; // 7 chars max TUPLE sizes[6] = { { 0x0000, "BYTE"}, { 0x0200, "WORD"}, { 0x0400, "LONG"}, { 0x0600, "SINGLE"}, { 0x0800, "DOUBLE"}, { 0x0a00, "UNSGNED"}, }; // 11 chars max TUPLE srcs[21] = { { 0x0000, "FP0"}, { 0x0010, "FP1"}, { 0x0020, "FP2"}, { 0x0030, "FP3"}, { 0x0040, "FP4"}, { 0x0050, "FP5"}, { 0x0060, "FP6"}, { 0x0070, "FP7"}, { 0x0080, "D0"}, { 0x0090, "D1"}, { 0x00a0, "D2"}, { 0x00b0, "D3"}, { 0x00c0, "D4"}, { 0x00d0, "D5"}, { 0x00e0, "D6"}, { 0x00f0, "D7"}, { 0x0100, "IMMED_LONG"}, { 0x0110, "IMMED_SHORT"}, { 0x0120, "FRAME_OFF"}, { 0x0130, "EFFECT_ADDR"}, { 0x0140, "IMMED_ZERO"}, }; // 11 chars max TUPLE dsts[11] = { { 0x0000, "R0"}, { 0x0001, "R1"}, { 0x0002, "R2"}, { 0x0003, "R3"}, { 0x0004, "R4"}, { 0x0005, "R5"}, { 0x0006, "R6"}, { 0x0007, "R7"}, { 0x0008, "FRAME_OFF"}, { 0x0009, "EFFECT_ADDR"}, { 0x000a, "RETURN_REG"}, }; #define GET_OPERATOR(x) ((x) & 0xf000) #define GET_SIZE(x) ((x) & 0x0e00) #define GET_SRC(x) ((x) & 0x01f0) #define GET_DST(x) ((x) & 0x000f) /* ; BCD arithmetic package *************************************************************************** * OPERATOR / OPERAND WORD * * * * | 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * * +---------------+-----------+-------------------+---------------+ * * | OPERATOR | SIZE | SRC OPERAND | DEST OPERAND | * * +---------------+-----------+-------------------+---------------+ * * FCMP 0 BYTE 0 FP0 0 R0 (FP or D) 0 * * FADD 1 WORD 1 | | * * FDIV 2 LONG 2 FP7 7 R7 (FP or D) 7 * * FMUL 3 SINGLE 3 D0 8 FRAME_OFF 8 * * FSUB 4 DOUBLE 4 | EFFECT_ADDR 9 * * FINTRZ 5 UNSGNED 5 D7 15 RETURN_REG 10 * * FMOVE 6 IMMED_LONG 16 * * FNEG 7 IMMED_SHORT 17 * * FTST 8 FRAME_OFF 18 * * EFFECT_ADDR 19 * * IMMED_ZERO 20 * *************************************************************************** bcdCmp = 0x0000 bcdAdd = 0x1000 bcdDiv = 0x2000 bcdMul = 0x3000 bcdSub = 0x4000 bcdIntz = 0x5000 bcdMove = 0x6000 bcdNeg = 0x7000 bcdTst = 0x8000 bcdByte = 0x0000 bcdWord = 0x0200 bcdLong = 0x0400 bcdSingle = 0x0600 bcdDouble = 0x0800 bcdUnsigned = 0x0A00 ; Source operand bcdFP0 = 0x0000 bcdFP1 = 0x0010 bcdFP2 = 0x0020 bcdFP3 = 0x0030 bcdFP4 = 0x0040 bcdFP5 = 0x0050 bcdFP6 = 0x0060 bcdFP7 = 0x0070 bcdD0 = 0x0080 bcdD1 = 0x0090 bcdD2 = 0x00A0 bcdD3 = 0x00B0 bcdD4 = 0x00C0 bcdD5 = 0x00D0 bcdD6 = 0x00E0 bcdD7 = 0x00F0 bcdLongImm = 0x0100 bcdShortImm = 0x0110 bcdFrameSrc = 0x0120 bcdAbsSrc = 0x0130 bcdZeroImm = 0x0140 ; Destination operand bcdR0 = 0x0000 bcdR1 = 0x0001 bcdR2 = 0x0002 bcdR3 = 0x0003 bcdR4 = 0x0004 bcdR5 = 0x0005 bcdR6 = 0x0006 bcdR7 = 0x0007 bcdFrameDest = 0x0008 bcdAbsDest = 0x0009 bcdRetReg = 0x000A */ /* Input: FPU opcode in 'code' Output: FPU disassembled in 'buf'. sizeof(buf) >= 6+1+7+1+11+1+11 = 38 */ int DasmFPU(uint16_t code, char *buf) { int operator = GET_OPERATOR(code); int size = GET_SIZE(code); int src = GET_SRC(code); int dst = GET_DST(code); int idx[4] = { 0 }; int i; int j = 0; for(i = 0; i < sizeof(operators) / sizeof(TUPLE); i++) { if(operators[i].code == operator) { idx[j++] = i; break; } } for(i = 0; i < sizeof(sizes) / sizeof(TUPLE); i++) { if(sizes[i].code == size) { idx[j++] = i; break; } } for(i = 0; i < sizeof(srcs) / sizeof(TUPLE); i++) { if(srcs[i].code == src) { idx[j++] = i; break; } } for(i = 0; i < sizeof(dsts) / sizeof(TUPLE); i++) { if(dsts[i].code == dst) { idx[j++] = i; break; } } sprintf(buf, "%s.%s %s,%s", operators[idx[0]].name, sizes[idx[1]].name, srcs[idx[2]].name, dsts[idx[3]].name); return 0; } /* Et sinon, il y a un autre cas particulier bizarre, je ne sais pas s'il vaut le coup de le traîter, mais _bcd_math est un ROM_CALL qui s'appelle comme ça: - n'importe quelle méthode d'appel d'un ROM_CALL (jsr, F-Line etc.) - 2 octets: opcode FPU et le ROM_CALL saute ces 2 octets en retournant, donc retourne à next_pc+2. Si tu veux gérer ça, tu devrais regarder le target du jsr ou F-Line et comparer avec l'adresse de _bcd_math. Précisions: - la "FPU" est purement émulée en logiciel par _bcd_math, et les opcodes ne correspondent à aucune FPU réelle - Pour le F-Line, tu peux comparer l'opcode avec 0xF8B5, mais pour les appels par jsr, tu n'as pas d'autre choix que de tester le target du saut pour savoir si on saute vers _bcd_math ou aillers Il y en a un dans TIGCCLIB: __floatunssibf: link.w %a6,#-36 pea.l 8(%a6) move.l 0xC8,%a0 move.l 0xB5*4(%a0),%a0 // _bcd_math jsr (%a0) .word 0x6B30 // bcdMove | bcdUnsigned | bcdAbsSrc | bcdR0 move.l -10(%a6),%d0 move.l -6(%a6),%d1 move.w -2(%a6),%d2 unlk %a6 rts Le .word 0x6B30 est le code de la pseudo-FPU dont je parle. Et ce n'est pas exécuté par le processeur, _bcd_math rajoute 2 octets à l'adresse de retour. */