1 // license:BSD-3-Clause
2 // copyright-holders:smf
3 /*
4 * PSXCPU disassembler for the MAME project written by smf
5 *
6 */
7
8 #include "emu.h"
9 #include "psx.h"
10 #include "gte.h"
11
12 #include "psxdefs.h"
13 #include "psxdasm.h"
14
15
make_signed_hex_str_16(uint32_t value)16 std::string psxcpu_disassembler::make_signed_hex_str_16( uint32_t value )
17 {
18 if( value & 0x8000 )
19 {
20 return util::string_format("-$%x", -value & 0xffff );
21 }
22 else
23 {
24 return util::string_format("$%x", value & 0xffff );
25 }
26 }
27
28 const char *const psxcpu_disassembler::s_cpugenreg[] =
29 {
30 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
31 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
32 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
33 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
34 };
35
36 const char *const psxcpu_disassembler::s_cp0genreg[] =
37 {
38 "!Index", "!Random", "!EntryLo", "BPC", "!Context", "BDA", "TAR", "DCIC",
39 "BadA", "BDAM", "!EntryHi", "BPCM", "SR", "Cause", "EPC", "PRId",
40 "cp0r16", "cp0r17", "cp0r18", "cp0r19", "cp0r20", "cp0r21", "cp0r22", "cp0r23",
41 "cp0r24", "cp0r25", "cp0r26", "cp0r27", "cp0r28", "cp0r29", "cp0r30", "cp0r31"
42 };
43
44 const char *const psxcpu_disassembler::s_cp0ctlreg[] =
45 {
46 "cp0cr0", "cp0cr1", "cp0cr2", "cp0cr3", "cp0cr4", "cp0cr5", "cp0cr6", "cp0cr7",
47 "cp0cr8", "cp0cr9", "cp0cr10", "cp0cr11", "cp0cr12", "cp0cr13", "cp0cr14", "cp0cr15",
48 "cp0cr16", "cp0cr17", "cp0cr18", "cp0cr19", "cp0cr20", "cp0cr21", "cp0cr22", "cp0cr23",
49 "cp0cr24", "cp0cr25", "cp0cr26", "cp0cr27", "cp0cr28", "cp0cr29", "cp0cr30", "cp0cr31"
50 };
51
52 const char *const psxcpu_disassembler::s_cp1genreg[] =
53 {
54 "cp1r0", "cp1r1", "cp1r2", "cp1r3", "cp1r4", "cp1r5", "cp1r6", "cp1r7",
55 "cp1r8", "cp1r9", "cp1r10", "cp1r11", "cp1r12", "cp1r13", "cp1r14", "cp1r15",
56 "cp1r16", "cp1r17", "cp1r18", "cp1r19", "cp1r20", "cp1r21", "cp1r22", "cp1r22",
57 "cp1r23", "cp1r24", "cp1r25", "cp1r26", "cp1r27", "cp1r28", "cp1r29", "cp1r30"
58 };
59
60 const char *const psxcpu_disassembler::s_cp1ctlreg[] =
61 {
62 "cp1cr0", "cp1cr1", "cp1cr2", "cp1cr3", "cp1cr4", "cp1cr5", "cp1cr6", "cp1cr7",
63 "cp1cr8", "cp1cr9", "cp1cr10", "cp1cr11", "cp1cr12", "cp1cr13", "cp1cr14", "cp1cr15",
64 "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "cp1cr21", "cp1cr22", "cp1cr23",
65 "cp1cr24", "cp1cr25", "cp1cr26", "cp1cr27", "cp1cr28", "cp1cr29", "cp1cr30", "cp1cr31"
66 };
67
68 const char *const psxcpu_disassembler::s_cp2genreg[] =
69 {
70 "vxy0", "vz0", "vxy1", "vz1", "vxy2", "vz2", "rgb", "otz",
71 "ir0", "ir1", "ir2", "ir3", "sxy0", "sxy1", "sxy2", "sxyp",
72 "sz0", "sz1", "sz2", "sz3", "rgb0", "rgb1", "rgb2", "cp2cr23",
73 "mac0", "mac1", "mac2", "mac3", "irgb", "orgb", "lzcs", "lzcr"
74 };
75
76 const char *const psxcpu_disassembler::s_cp2ctlreg[] =
77 {
78 "r11r12", "r13r21", "r22r23", "r31r32", "r33", "trx", "try", "trz",
79 "l11l12", "l13l21", "l22l23", "l31l32", "l33", "rbk", "gbk", "bbk",
80 "lr1lr2", "lr3lg1", "lg2lg3", "lb1lb2", "lb3", "rfc", "gfc", "bfc",
81 "ofx", "ofy", "h", "dqa", "dqb", "zsf3", "zsf4", "flag"
82 };
83
84 const char *const psxcpu_disassembler::s_cp3genreg[] =
85 {
86 "cp3r0", "cp3r1", "cp3r2", "cp3r3", "cp3r4", "cp3r5", "cp3r6", "cp3r7",
87 "cp3r8", "cp3r9", "cp3r10", "cp3r11", "cp3r12", "cp3r13", "cp3r14", "cp3r15",
88 "cp3r16", "cp3r17", "cp3r18", "cp3r19", "cp3r20", "cp3r21", "cp3r22", "cp3r22",
89 "cp3r23", "cp3r24", "cp3r25", "cp3r26", "cp3r27", "cp3r28", "cp3r29", "cp3r30"
90 };
91
92 const char *const psxcpu_disassembler::s_cp3ctlreg[] =
93 {
94 "cp3cr0", "cp3cr1", "cp3cr2", "cp3cr3", "cp3cr4", "cp3cr5", "cp3cr6", "cp3cr7",
95 "cp3cr8", "cp3cr9", "cp3cr10", "cp3cr11", "cp3cr12", "cp3cr13", "cp3cr14", "cp3cr15",
96 "cp3cr16", "cp3cr17", "cp3cr18", "cp3cr19", "cp3cr20", "cp3cr21", "cp3cr22", "cp3cr23",
97 "cp3cr24", "cp3cr25", "cp3cr26", "cp3cr27", "cp3cr28", "cp3cr29", "cp3cr30", "cp3cr31"
98 };
99
100 const char *const psxcpu_disassembler::s_gtesf[] =
101 {
102 " sf=0", " sf=12"
103 };
104
105 const char *const psxcpu_disassembler::s_gtemx[] =
106 {
107 "rm", "lm", "cm", "0"
108 };
109
110 const char *const psxcpu_disassembler::s_gtev[] =
111 {
112 "v0", "v1", "v2", "ir"
113 };
114
115 const char *const psxcpu_disassembler::s_gtecv[] =
116 {
117 "tr", "bk", "fc", "0"
118 };
119
120 const char *const psxcpu_disassembler::s_gtelm[] =
121 {
122 " lm=s16", " lm=u15"
123 };
124
effective_address(uint32_t pc,uint32_t op)125 std::string psxcpu_disassembler::effective_address( uint32_t pc, uint32_t op )
126 {
127 if( m_config && m_config->pc() == pc )
128 {
129 return util::string_format("%s(%s) ; 0x%08x", make_signed_hex_str_16( INS_IMMEDIATE( op ) ), s_cpugenreg[ INS_RS( op ) ],
130 (uint32_t)( m_config->r( INS_RS( op ) ) + (int16_t)INS_IMMEDIATE( op ) ) );
131 }
132 return util::string_format("%s(%s)", make_signed_hex_str_16( INS_IMMEDIATE( op ) ), s_cpugenreg[ INS_RS( op ) ] );
133 }
134
relative_address(uint32_t pc,uint32_t op)135 uint32_t psxcpu_disassembler::relative_address( uint32_t pc, uint32_t op )
136 {
137 uint32_t nextpc = pc + 4;
138 if( m_config && m_config->pc() == pc && m_config->delayr() == PSXCPU_DELAYR_PC )
139 {
140 nextpc = m_config->delayv();
141 }
142
143 return nextpc + ( PSXCPU_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 );
144 }
145
jump_address(uint32_t pc,uint32_t op)146 uint32_t psxcpu_disassembler::jump_address( uint32_t pc, uint32_t op )
147 {
148 uint32_t nextpc = pc + 4;
149 if( m_config && m_config->pc() == pc && m_config->delayr() == PSXCPU_DELAYR_PC )
150 {
151 nextpc = m_config->delayv();
152 }
153 return ( nextpc & 0xf0000000 ) + ( INS_TARGET( op ) << 2 );
154 }
155
upper_address(uint32_t op,offs_t pos,const data_buffer & opcodes)156 std::string psxcpu_disassembler::upper_address( uint32_t op, offs_t pos, const data_buffer &opcodes )
157 {
158 uint32_t nextop = opcodes.r32( pos );
159
160 if( INS_OP( nextop ) == OP_ORI && INS_RT( op ) == INS_RS( nextop ) )
161 {
162 return util::string_format("$%04x ; 0x%08x", INS_IMMEDIATE( op ), ( INS_IMMEDIATE( op ) << 16 ) | INS_IMMEDIATE( nextop ) );
163 }
164 else if( INS_OP( nextop ) == OP_ADDIU && INS_RT( op ) == INS_RS( nextop ) )
165 {
166 return util::string_format("$%04x ; 0x%08x", INS_IMMEDIATE( op ), ( INS_IMMEDIATE( op ) << 16 ) + (int16_t) INS_IMMEDIATE( nextop ) );
167 }
168 else
169 {
170 return util::string_format("$%04x", INS_IMMEDIATE( op ) );
171 }
172 }
173
psxcpu_disassembler(config * conf)174 psxcpu_disassembler::psxcpu_disassembler(config *conf) : m_config(conf)
175 {
176 }
177
opcode_alignment() const178 u32 psxcpu_disassembler::opcode_alignment() const
179 {
180 return 4;
181 }
182
disassemble(std::ostream & stream,offs_t pc,const data_buffer & opcodes,const data_buffer & params)183 offs_t psxcpu_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms)
184 {
185 uint32_t op;
186 uint32_t flags = 0;
187 offs_t pos = pc;
188 op = opcodes.r32( pos );
189 pos += 4;
190
191 std::streampos current_pos = stream.tellp();
192
193 switch( INS_OP( op ) )
194 {
195 case OP_SPECIAL:
196 switch( INS_FUNCT( op ) )
197 {
198 case FUNCT_SLL:
199 if( op == 0 )
200 {
201 /* the standard nop is "sll zero,zero,$0000" */
202 util::stream_format( stream, "nop" );
203 }
204 else
205 {
206 util::stream_format( stream, "sll %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) );
207 }
208 break;
209 case FUNCT_SRL:
210 util::stream_format( stream, "srl %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) );
211 break;
212 case FUNCT_SRA:
213 util::stream_format( stream, "sra %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) );
214 break;
215 case FUNCT_SLLV:
216 util::stream_format( stream, "sllv %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] );
217 break;
218 case FUNCT_SRLV:
219 util::stream_format( stream, "srlv %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] );
220 break;
221 case FUNCT_SRAV:
222 util::stream_format( stream, "srav %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] );
223 break;
224 case FUNCT_JR:
225 util::stream_format( stream, "jr %s", s_cpugenreg[ INS_RS( op ) ] );
226 if( INS_RS( op ) == 31 )
227 {
228 flags = STEP_OUT;
229 }
230 break;
231 case FUNCT_JALR:
232 util::stream_format( stream, "jalr %s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ] );
233 flags = STEP_OVER | step_over_extra( 1 );
234 break;
235 case FUNCT_SYSCALL:
236 util::stream_format( stream, "syscall $%05x", INS_CODE( op ) );
237 flags = STEP_OVER;
238 break;
239 case FUNCT_BREAK:
240 util::stream_format( stream, "break $%05x", INS_CODE( op ) );
241 flags = STEP_OVER;
242 break;
243 case FUNCT_MFHI:
244 util::stream_format( stream, "mfhi %s", s_cpugenreg[ INS_RD( op ) ] );
245 break;
246 case FUNCT_MTHI:
247 util::stream_format( stream, "mthi %s", s_cpugenreg[ INS_RS( op ) ] );
248 break;
249 case FUNCT_MFLO:
250 util::stream_format( stream, "mflo %s", s_cpugenreg[ INS_RD( op ) ] );
251 break;
252 case FUNCT_MTLO:
253 util::stream_format( stream, "mtlo %s", s_cpugenreg[ INS_RS( op ) ] );
254 break;
255 case FUNCT_MULT:
256 util::stream_format( stream, "mult %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
257 break;
258 case FUNCT_MULTU:
259 util::stream_format( stream, "multu %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
260 break;
261 case FUNCT_DIV:
262 util::stream_format( stream, "div %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
263 break;
264 case FUNCT_DIVU:
265 util::stream_format( stream, "divu %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
266 break;
267 case FUNCT_ADD:
268 util::stream_format( stream, "add %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
269 break;
270 case FUNCT_ADDU:
271 util::stream_format( stream, "addu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
272 break;
273 case FUNCT_SUB:
274 util::stream_format( stream, "sub %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
275 break;
276 case FUNCT_SUBU:
277 util::stream_format( stream, "subu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
278 break;
279 case FUNCT_AND:
280 util::stream_format( stream, "and %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
281 break;
282 case FUNCT_OR:
283 util::stream_format( stream, "or %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
284 break;
285 case FUNCT_XOR:
286 util::stream_format( stream, "xor %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
287 break;
288 case FUNCT_NOR:
289 util::stream_format( stream, "nor %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
290 break;
291 case FUNCT_SLT:
292 util::stream_format( stream, "slt %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
293 break;
294 case FUNCT_SLTU:
295 util::stream_format( stream, "sltu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] );
296 break;
297 }
298 break;
299 case OP_REGIMM:
300 switch( INS_RT_REGIMM( op ) )
301 {
302 case RT_BLTZ:
303 if( INS_RT( op ) == RT_BLTZAL )
304 {
305 util::stream_format( stream, "bltzal %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( pc, op ) );
306 flags = STEP_OVER | step_over_extra( 1 );
307 }
308 else
309 {
310 util::stream_format( stream, "bltz %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( pc, op ) );
311 }
312 break;
313 case RT_BGEZ:
314 if( INS_RT( op ) == RT_BGEZAL )
315 {
316 util::stream_format( stream, "bgezal %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( pc, op ) );
317 flags = STEP_OVER | step_over_extra( 1 );
318 }
319 else
320 {
321 util::stream_format( stream, "bgez %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( pc, op ) );
322 }
323 break;
324 }
325 break;
326 case OP_J:
327 util::stream_format( stream, "j $%08x", jump_address( pc, op ) );
328 break;
329 case OP_JAL:
330 util::stream_format( stream, "jal $%08x", jump_address( pc, op ) );
331 flags = STEP_OVER | step_over_extra( 1 );
332 break;
333 case OP_BEQ:
334 util::stream_format( stream, "beq %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( pc, op ) );
335 break;
336 case OP_BNE:
337 util::stream_format( stream, "bne %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( pc, op ) );
338 break;
339 case OP_BLEZ:
340 util::stream_format( stream, "blez %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( pc, op ) );
341 break;
342 case OP_BGTZ:
343 util::stream_format( stream, "bgtz %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( pc, op ) );
344 break;
345 case OP_ADDI:
346 util::stream_format( stream, "addi %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
347 break;
348 case OP_ADDIU:
349 util::stream_format( stream, "addiu %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
350 break;
351 case OP_SLTI:
352 util::stream_format( stream, "slti %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
353 break;
354 case OP_SLTIU:
355 util::stream_format( stream, "sltiu %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) );
356 break;
357 case OP_ANDI:
358 util::stream_format( stream, "andi %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) );
359 break;
360 case OP_ORI:
361 util::stream_format( stream, "ori %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) );
362 break;
363 case OP_XORI:
364 util::stream_format( stream, "xori %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) );
365 break;
366 case OP_LUI:
367 util::stream_format( stream, "lui %s,%s", s_cpugenreg[ INS_RT( op ) ], upper_address( op, pos, opcodes ) );
368 break;
369 case OP_COP0:
370 switch( INS_RS( op ) )
371 {
372 case RS_MFC:
373 util::stream_format( stream, "mfc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0genreg[ INS_RD( op ) ] );
374 break;
375 case RS_CFC:
376 util::stream_format( stream, "!cfc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0ctlreg[ INS_RD( op ) ] );
377 break;
378 case RS_MTC:
379 util::stream_format( stream, "mtc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0genreg[ INS_RD( op ) ] );
380 break;
381 case RS_CTC:
382 util::stream_format( stream, "!ctc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0ctlreg[ INS_RD( op ) ] );
383 break;
384 case RS_BC:
385 case RS_BC_ALT:
386 switch( INS_BC( op ) )
387 {
388 case BC_BCF:
389 util::stream_format( stream, "bc0f $%08x", relative_address( pc, op ) );
390 break;
391 case BC_BCT:
392 util::stream_format( stream, "bc0t $%08x", relative_address( pc, op ) );
393 break;
394 }
395 break;
396 default:
397 switch( INS_CO( op ) )
398 {
399 case 1:
400 switch( INS_CF( op ) )
401 {
402 case CF_TLBR:
403 util::stream_format( stream, "!tlbr" );
404 break;
405 case CF_TLBWI:
406 util::stream_format( stream, "!tlbwi" );
407 break;
408 case CF_TLBWR:
409 util::stream_format( stream, "!tlbwr" );
410 break;
411 case CF_TLBP:
412 util::stream_format( stream, "!tlbp" );
413 break;
414 case CF_RFE:
415 util::stream_format( stream, "rfe" );
416 break;
417 default:
418 util::stream_format(stream, "cop0 $%07x", INS_COFUN(op));
419 break;
420 }
421 break;
422 }
423 break;
424 }
425 break;
426 case OP_COP1:
427 switch( INS_RS( op ) )
428 {
429 case RS_MFC:
430 util::stream_format( stream, "mfc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1genreg[ INS_RD( op ) ] );
431 break;
432 case RS_CFC:
433 util::stream_format( stream, "cfc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1ctlreg[ INS_RD( op ) ] );
434 break;
435 case RS_MTC:
436 util::stream_format( stream, "mtc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1genreg[ INS_RD( op ) ] );
437 break;
438 case RS_CTC:
439 util::stream_format( stream, "ctc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1ctlreg[ INS_RD( op ) ] );
440 break;
441 case RS_BC:
442 case RS_BC_ALT:
443 switch( INS_BC( op ) )
444 {
445 case BC_BCF:
446 util::stream_format( stream, "bc1f $%08x", relative_address( pc, op ) );
447 break;
448 case BC_BCT:
449 util::stream_format( stream, "bc1t $%08x", relative_address( pc, op ) );
450 break;
451 }
452 break;
453 default:
454 switch( INS_CO( op ) )
455 {
456 case 1:
457 util::stream_format( stream, "cop1 $%07x", INS_COFUN( op ) );
458 break;
459 }
460 break;
461 }
462 break;
463 case OP_COP2:
464 switch( INS_RS( op ) )
465 {
466 case RS_MFC:
467 util::stream_format( stream, "mfc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2genreg[ INS_RD( op ) ] );
468 break;
469 case RS_CFC:
470 util::stream_format( stream, "cfc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2ctlreg[ INS_RD( op ) ] );
471 break;
472 case RS_MTC:
473 util::stream_format( stream, "mtc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2genreg[ INS_RD( op ) ] );
474 break;
475 case RS_CTC:
476 util::stream_format( stream, "ctc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2ctlreg[ INS_RD( op ) ] );
477 break;
478 case RS_BC:
479 case RS_BC_ALT:
480 switch( INS_BC( op ) )
481 {
482 case BC_BCF:
483 util::stream_format( stream, "bc2f $%08x", relative_address( pc, op ) );
484 break;
485 case BC_BCT:
486 util::stream_format( stream, "bc2t $%08x", relative_address( pc, op ) );
487 break;
488 }
489 break;
490 default:
491 switch( INS_CO( op ) )
492 {
493 case 1:
494 switch( GTE_FUNCT( op ) )
495 {
496 case 0x00: // drop through to RTPS
497 case 0x01:
498 util::stream_format( stream, "rtps%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
499 break;
500 case 0x06:
501 util::stream_format( stream, "nclip" );
502 break;
503 case 0x0c:
504 util::stream_format( stream, "op%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
505 break;
506 case 0x10:
507 util::stream_format( stream, "dpcs%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
508 break;
509 case 0x11:
510 util::stream_format( stream, "intpl%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
511 break;
512 case 0x12:
513 util::stream_format( stream, "mvmva%s%s %s + %s * %s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ],
514 s_gtecv[ GTE_CV( op ) ], s_gtemx[ GTE_MX( op ) ], s_gtev[ GTE_V( op ) ] );
515 break;
516 case 0x13:
517 util::stream_format( stream, "ncds%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
518 break;
519 case 0x14:
520 util::stream_format( stream, "cdp%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
521 break;
522 case 0x16:
523 util::stream_format( stream, "ncdt%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
524 break;
525 case 0x1b:
526 util::stream_format( stream, "nccs%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
527 break;
528 case 0x1c:
529 util::stream_format( stream, "cc%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
530 break;
531 case 0x1e:
532 util::stream_format( stream, "ncs%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
533 break;
534 case 0x20:
535 util::stream_format( stream, "nct%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
536 break;
537 case 0x28:
538 util::stream_format( stream, "sqr%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
539 break;
540 case 0x1a: // end of NCDT
541 case 0x29:
542 util::stream_format( stream, "dpcl%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
543 break;
544 case 0x2a:
545 util::stream_format( stream, "dpct%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
546 break;
547 case 0x2d:
548 util::stream_format( stream, "avsz3" );
549 break;
550 case 0x2e:
551 util::stream_format( stream, "avsz4" );
552 break;
553 case 0x30:
554 util::stream_format( stream, "rtpt%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
555 break;
556 case 0x3d:
557 util::stream_format( stream, "gpf%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
558 break;
559 case 0x3e:
560 util::stream_format( stream, "gpl%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
561 break;
562 case 0x3f:
563 util::stream_format( stream, "ncct%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] );
564 break;
565 default:
566 util::stream_format(stream, "cop2 $%07x", INS_COFUN(op));
567 break;
568 }
569 }
570 break;
571 }
572 break;
573 case OP_COP3:
574 switch( INS_RS( op ) )
575 {
576 case RS_MFC:
577 util::stream_format( stream, "mfc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3genreg[ INS_RD( op ) ] );
578 break;
579 case RS_CFC:
580 util::stream_format( stream, "cfc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3ctlreg[ INS_RD( op ) ] );
581 break;
582 case RS_MTC:
583 util::stream_format( stream, "mtc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3genreg[ INS_RD( op ) ] );
584 break;
585 case RS_CTC:
586 util::stream_format( stream, "ctc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3ctlreg[ INS_RD( op ) ] );
587 break;
588 case RS_BC:
589 case RS_BC_ALT:
590 switch( INS_BC( op ) )
591 {
592 case BC_BCF:
593 util::stream_format( stream, "bc3f $%08x", relative_address( pc, op ) );
594 break;
595 case BC_BCT:
596 util::stream_format( stream, "bc3t $%08x", relative_address( pc, op ) );
597 break;
598 }
599 break;
600 default:
601 switch( INS_CO( op ) )
602 {
603 case 1:
604 util::stream_format( stream, "cop3 $%07x", INS_COFUN( op ) );
605 break;
606 }
607 break;
608 }
609 break;
610 case OP_LB:
611 util::stream_format( stream, "lb %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
612 break;
613 case OP_LH:
614 util::stream_format( stream, "lh %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
615 break;
616 case OP_LWL:
617 util::stream_format( stream, "lwl %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
618 break;
619 case OP_LW:
620 util::stream_format( stream, "lw %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
621 break;
622 case OP_LBU:
623 util::stream_format( stream, "lbu %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
624 break;
625 case OP_LHU:
626 util::stream_format( stream, "lhu %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
627 break;
628 case OP_LWR:
629 util::stream_format( stream, "lwr %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
630 break;
631 case OP_SB:
632 util::stream_format( stream, "sb %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
633 break;
634 case OP_SH:
635 util::stream_format( stream, "sh %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
636 break;
637 case OP_SWL:
638 util::stream_format( stream, "swl %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
639 break;
640 case OP_SW:
641 util::stream_format( stream, "sw %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
642 break;
643 case OP_SWR:
644 util::stream_format( stream, "swr %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( pc, op ) );
645 break;
646 case OP_LWC0:
647 util::stream_format( stream, "lwc0 %s,%s", s_cp0genreg[ INS_RT( op ) ], effective_address( pc, op ) );
648 break;
649 case OP_LWC1:
650 util::stream_format( stream, "lwc1 %s,%s", s_cp1genreg[ INS_RT( op ) ], effective_address( pc, op ) );
651 break;
652 case OP_LWC2:
653 util::stream_format( stream, "lwc2 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( pc, op ) );
654 break;
655 case OP_LWC3:
656 util::stream_format( stream, "lwc3 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( pc, op ) );
657 break;
658 case OP_SWC0:
659 util::stream_format( stream, "swc0 %s,%s", s_cp0genreg[ INS_RT( op ) ], effective_address( pc, op ) );
660 break;
661 case OP_SWC1:
662 util::stream_format( stream, "swc1 %s,%s", s_cp1genreg[ INS_RT( op ) ], effective_address( pc, op ) );
663 break;
664 case OP_SWC2:
665 util::stream_format( stream, "swc2 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( pc, op ) );
666 break;
667 case OP_SWC3:
668 util::stream_format( stream, "swc3 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( pc, op ) );
669 break;
670 }
671
672 // fall back if we have not emitted anything
673 if (current_pos == stream.tellp())
674 {
675 util::stream_format(stream, "dw $%08x", op);
676 }
677
678 return ( pos - pc ) | flags | SUPPORTED;
679 }
680