Mercurial > repos > blastem
comparison jagcpu.c @ 1093:4987fddd42a0
Initial stab at jaguar disassemler
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 30 Oct 2016 19:42:48 -0700 |
parents | |
children | 1dba006bad47 |
comparison
equal
deleted
inserted
replaced
1092:f338c950fcef | 1093:4987fddd42a0 |
---|---|
1 #include <stdint.h> | |
2 #include <stdio.h> | |
3 #include "jagcpu.h" | |
4 | |
5 char *gpu_mnemonics[] = { | |
6 "add", | |
7 "addc", | |
8 "addq", | |
9 "addqt", | |
10 "sub", | |
11 "subc", | |
12 "subq", | |
13 "subqt", | |
14 "neg", | |
15 "and", | |
16 "or", | |
17 "xor", | |
18 "not", | |
19 "btst", | |
20 "bset", | |
21 "bclr", | |
22 "mult", | |
23 "imult", | |
24 "imultn", | |
25 "resmac", | |
26 "imacn", | |
27 "div", | |
28 "abs", | |
29 "sh", | |
30 "shlq", | |
31 "shrq", | |
32 "sha", | |
33 "sharq", | |
34 "ror", | |
35 "rorq", | |
36 "cmp", | |
37 "cmpq", | |
38 "sat8", | |
39 "sat16", | |
40 "move", | |
41 "moveq", | |
42 "moveta", | |
43 "movefa", | |
44 "movei", | |
45 "loadb", | |
46 "loadw", | |
47 "load", | |
48 "loadp", | |
49 "load", //r14 relative | |
50 "load", //r15 relative | |
51 "storeb", | |
52 "storew", | |
53 "store", | |
54 "storep", | |
55 "store", //r14 relative | |
56 "store", //r15 relative | |
57 "move", //PC | |
58 "jump", | |
59 "jr", | |
60 "mmult", | |
61 "mtoi", | |
62 "normi", | |
63 "nop", | |
64 "load", //r14 indexed | |
65 "load", //r15 indexed | |
66 "store", //r14 indexed | |
67 "store", //r15 indexed | |
68 "sat24", | |
69 "pack", | |
70 "unpack" | |
71 }; | |
72 | |
73 char *dsp_mnemonics[DSP_ADDQMOD+1] = { | |
74 [DSP_SUBQMOD] = "subqmod", | |
75 [DSP_SAT16S] = "sat16s", | |
76 [DSP_SAT32S] = "sat32s", | |
77 [DSP_MIRROR] = "mirror", | |
78 [DSP_ADDQMOD] = "addqmod" | |
79 }; | |
80 | |
81 void init_dsp_mnemonic_table() | |
82 { | |
83 static uint8_t init_done; | |
84 if (init_done) { | |
85 return; | |
86 } | |
87 for (int i = 0; i < DSP_ADDQMOD; i++) | |
88 { | |
89 if (!dsp_mnemonics[i]) { | |
90 dsp_mnemonics[i] = gpu_mnemonics[i]; | |
91 } | |
92 } | |
93 init_done = 1; | |
94 } | |
95 | |
96 uint16_t jag_opcode(uint16_t inst, uint8_t is_gpu) | |
97 { | |
98 uint16_t opcode = inst >> 11; | |
99 if (is_gpu && opcode == GPU_PACK && (inst & 0x20)) { | |
100 return GPU_UNPACK; | |
101 } | |
102 return opcode; | |
103 } | |
104 | |
105 uint16_t jag_reg2(uint16_t inst) | |
106 { | |
107 return inst & 0x1F; | |
108 } | |
109 | |
110 uint16_t jag_reg1(uint16_t inst) | |
111 { | |
112 return inst >> 5 & 0x1F; | |
113 } | |
114 | |
115 //moveq and bit instructions should just use jag_reg1 instead | |
116 uint32_t jag_quick(uint16_t inst) | |
117 { | |
118 uint32_t val = inst >> 5 & 0x1F; | |
119 return val ? val : 32; | |
120 } | |
121 | |
122 uint8_t is_quick_1_32_opcode(uint16_t opcode, uint8_t is_gpu) | |
123 { | |
124 return opcode == JAG_ADDQ | |
125 || opcode == JAG_ADDQT | |
126 || opcode == JAG_SUBQ | |
127 || opcode == JAG_SUBQT | |
128 || opcode == JAG_SHLQ | |
129 || opcode == JAG_SHRQ | |
130 || opcode == JAG_SHARQ | |
131 || opcode == JAG_RORQ | |
132 || (!is_gpu && ( | |
133 opcode == DSP_SUBQMOD | |
134 || opcode == DSP_ADDQMOD | |
135 )); | |
136 } | |
137 | |
138 uint8_t is_quick_0_31_opcode(uint16_t opcode) | |
139 { | |
140 return opcode == JAG_MOVEQ | |
141 || opcode == JAG_BTST | |
142 || opcode == JAG_BSET | |
143 || opcode == JAG_BCLR; | |
144 } | |
145 | |
146 char * jag_cc_names[] = { | |
147 "t", | |
148 "ne", | |
149 "eq", | |
150 "f", | |
151 "cc", | |
152 "hi", | |
153 "eq_cc", | |
154 "f", | |
155 "cs", | |
156 "ne_cs", | |
157 "eq_cs", | |
158 "f", | |
159 "f", | |
160 "f", | |
161 "f", | |
162 "f" | |
163 "t_alt", | |
164 "ne_alt", | |
165 "eq_alt", | |
166 "f", | |
167 "pl", | |
168 "ne_pl", | |
169 "eq_pl", | |
170 "f", | |
171 "mi", | |
172 "ne_mi", | |
173 "eq_mi" | |
174 }; | |
175 | |
176 char * jag_cc(uint16_t inst) | |
177 { | |
178 uint16_t ccnum = jag_reg2(inst); | |
179 if (ccnum >= sizeof(jag_cc_names)/sizeof(*jag_cc_names)) { | |
180 return jag_cc_names[3]; | |
181 } | |
182 return jag_cc_names[ccnum]; | |
183 } | |
184 | |
185 uint32_t jag_jr_dest(uint16_t inst, uint32_t address) | |
186 { | |
187 uint32_t rel = jag_reg1(inst); | |
188 if (rel & 0x10) { | |
189 rel |= 0xFFFFFFE0; | |
190 } | |
191 return address + 2 + rel; | |
192 } | |
193 | |
194 int jag_cpu_disasm(uint16_t **stream, uint32_t address, char *dst, uint8_t is_gpu, uint8_t labels) | |
195 { | |
196 uint16_t inst = **stream; | |
197 *stream++; | |
198 uint16_t opcode = jag_opcode(inst, is_gpu); | |
199 char **mnemonics; | |
200 if (is_gpu) { | |
201 mnemonics = gpu_mnemonics; | |
202 } else { | |
203 init_dsp_mnemonic_table(); | |
204 mnemonics = dsp_mnemonics; | |
205 } | |
206 switch (opcode) | |
207 { | |
208 case JAG_MOVEI: { | |
209 uint32_t immed = **stream; | |
210 *stream++; | |
211 immed |= **stream << 16; | |
212 *stream++; | |
213 return sprintf("%s $%X, r%d", mnemonics[opcode], immed, jag_reg2(inst)); | |
214 } | |
215 case JAG_JR: | |
216 return sprintf( | |
217 labels ? "%s %s, ADR_%X" : "%s %s, $W%X", | |
218 mnemonics[opcode], jag_cc(inst), jag_jr_dest(inst, address) | |
219 ); | |
220 case JAG_JUMP: | |
221 return sprintf("%s %s, (r%d)", mnemonics[opcode], jag_cc(inst), jag_reg1(inst)); | |
222 default: | |
223 if (is_quick_1_32_opcode(opcode, is_gpu)) { | |
224 return sprintf("%s %d, r%d", mnemonics[opcode], jag_quick(inst), jag_reg2(inst)); | |
225 } else if (is_quick_0_31_opcode(opcode)) { | |
226 return sprintf("%s %d, r%d", mnemonics[opcode], jag_reg1(inst), jag_reg2(inst)); | |
227 } else { | |
228 return sprintf("%s r%d, r%d", mnemonics[opcode], jag_reg1(inst), jag_reg2(inst)); | |
229 } | |
230 } | |
231 } |