1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /******************************************************************************
4 *
5 *   Sony Playstation 2 Vector Unit disassembler
6 *
7 */
8 
9 #include "emu.h"
10 #include "vudasm.h"
11 
12 /*static*/ char const *const sonyvu_disassembler::DEST_STR[] =
13 {
14 	"    ", "w   ", "z   ", "zw  ", "y   ", "yw  ", "yz  ", "yzw ",
15 	"x   ", "xw  ", "xz  ", "xzw ", "xy  ", "xyw ", "xyz ", "xyzw"
16 };
17 
18 /*static*/ char const *const sonyvu_disassembler::DEST_COMMA_STR[] =
19 {
20 	",",  "w,",  "z,",  "zw,",  "y,",  "yw,",  "yz,",  "yzw,",
21 	"x,", "xw,", "xz,", "xzw,", "xy,", "xyw,", "xyz,", "xyzw,"
22 };
23 
24 /*static*/ char const *const sonyvu_disassembler::BC_STR[] = { "x", "y", "z", "w" };
25 /*static*/ char const *const sonyvu_disassembler::BC_COMMA_STR[] = { "x,", "y,", "z,", "w," };
26 
27 /*static*/ char const *const sonyvu_disassembler::VFREG[] =
28 {
29 	"$vf00", "$vf01", "$vf02", "$vf03", "$vf04", "$vf05", "$vf06", "$vf07",
30 	"$vf08", "$vf09", "$vf10", "$vf11", "$vf12", "$vf13", "$vf14", "$vf15",
31 	"$vf16", "$vf17", "$vf18", "$vf19", "$vf20", "$vf21", "$vf22", "$vf23",
32 	"$vf24", "$vf25", "$vf26", "$vf27", "$vf28", "$vf29", "$vf30", "$vf31"
33 };
34 
35 /*static*/ char const *const sonyvu_disassembler::VIREG[] =
36 {
37 	"$vi00",  "$vi01", "$vi02", "$vi03",  "$vi04", "$vi05",    "$vi06", "$vi07",
38 	"$vi08",  "$vi09", "$vi10", "$vi11",  "$vi12", "$vi13",    "$vi14", "$vi15",
39 	"STATUS", "MACF",  "CLIPF", "res19",  "R",     "I",        "Q",     "res23",
40 	"res24",  "res25", "TPC",   "CMSAR0", "FBRST", "VPU_STAT", "res30", "CMSAR1"
41 };
42 
disassemble(std::ostream & stream,offs_t pc,const data_buffer & opcodes,const data_buffer & params)43 offs_t sonyvu_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
44 {
45 	uint64_t op = opcodes.r64(pc & ~7);
46 	if (pc & 4)
47 	{
48 		if (op & 0x8000000000000000ULL)
49 		{
50 			util::stream_format(stream, "loi         %f", *reinterpret_cast<float*>(&op));
51 		}
52 		else
53 		{
54 			dasm_lower(pc, (uint32_t)op, stream);
55 		}
56 	}
57 	else
58 	{
59 		dasm_upper(pc, (uint32_t)(op >> 32), stream);
60 	}
61 	return 4 | SUPPORTED;
62 }
63 
dasm_upper(uint32_t pc,uint32_t op,std::ostream & stream)64 void sonyvu_disassembler::dasm_upper(uint32_t pc, uint32_t op, std::ostream &stream)
65 {
66 	const int rd   = (op >>  6) & 31;
67 	const int rs   = (op >> 11) & 31;
68 	const int rt   = (op >> 16) & 31;
69 	const char* bc = BC_STR[op & 3];
70 	const char* dest = DEST_STR[(op >> 21) & 15];
71 	const char* destc = DEST_COMMA_STR[(op >> 21) & 15];
72 
73 	switch (op & 0x3f)
74 	{
75 		case 0x08: case 0x09: case 0x0a: case 0x0b:
76 			util::stream_format(stream, "madd%s.%s  %s%s %s%s %s%s", bc, dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], bc); break;
77 		case 0x0c: case 0x0d: case 0x0e: case 0x0f:
78 			util::stream_format(stream, "msub%s.%s  %s%s %s%s %s%s", bc, dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], bc); break;
79 		case 0x10: case 0x11: case 0x12: case 0x13:
80 			util::stream_format(stream, "max%s.%s   %s%s %s%s %s%s", bc, dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], bc); break;
81 		case 0x14: case 0x15: case 0x16: case 0x17:
82 			util::stream_format(stream, "mini%s.%s  %s%s %s%s %s%s", bc, dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], bc); break;
83 		case 0x18: case 0x19: case 0x1a: case 0x1b:
84 			util::stream_format(stream, "mul%s.%s   %s%s %s%s %s%s", bc, dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], bc); break;
85 		case 0x1c: util::stream_format(stream, "mulq.%s   %s%s %s%s Q", dest, VFREG[rd], destc, VFREG[rs], destc); break;
86 		case 0x1d: util::stream_format(stream, "maxi.%s   %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
87 		case 0x1e: util::stream_format(stream, "muli.%s   %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
88 		case 0x1f: util::stream_format(stream, "minii.%s  %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
89 		case 0x20: util::stream_format(stream, "addq.%s   %s%s %s%s Q", dest, VFREG[rd], destc, VFREG[rs], destc); break;
90 		case 0x21: util::stream_format(stream, "maddq.%s  %s%s %s%s Q", dest, VFREG[rd], destc, VFREG[rs], destc); break;
91 		case 0x22: util::stream_format(stream, "addi.%s   %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
92 		case 0x23: util::stream_format(stream, "maddi.%s  %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
93 		case 0x24: util::stream_format(stream, "subq.%s   %s%s %s%s Q", dest, VFREG[rd], destc, VFREG[rs], destc); break;
94 		case 0x25: util::stream_format(stream, "msubq.%s  %s%s %s%s Q", dest, VFREG[rd], destc, VFREG[rs], destc); break;
95 		case 0x26: util::stream_format(stream, "subi.%s   %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
96 		case 0x27: util::stream_format(stream, "msubi.%s  %s%s %s%s I", dest, VFREG[rd], destc, VFREG[rs], destc); break;
97 		case 0x28: util::stream_format(stream, "add.%s    %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
98 		case 0x29: util::stream_format(stream, "madd.%s   %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
99 		case 0x2a: util::stream_format(stream, "mul.%s    %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
100 		case 0x2b: util::stream_format(stream, "max.%s    %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
101 		case 0x2c: util::stream_format(stream, "sub.%s    %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
102 		case 0x2d: util::stream_format(stream, "msub.%s   %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
103 		case 0x2e: util::stream_format(stream, "opmsub.xyz  %sxyz, %sxyz, %sxyz", VFREG[rd], VFREG[rs], VFREG[rt]); break;
104 		case 0x2f: util::stream_format(stream, "mini.%s   %s%s %s%s %s%s", dest, VFREG[rd], destc, VFREG[rs], destc, VFREG[rt], dest); break;
105 		case 0x3c: case 0x3d: case 0x3e: case 0x3f:
106 		{
107 			const uint8_t type2_op = ((op & 0x3c0) >> 4) | (op & 3);
108 			switch (type2_op)
109 			{
110 				case 0x00: case 0x01: case 0x02: case 0x03:
111 					util::stream_format(stream, "adda%s.%s  ACC%s %s%s %s%s", bc, dest, destc, VFREG[rs], destc, VFREG[rt], bc); break;
112 				case 0x04: case 0x05: case 0x06: case 0x07:
113 					util::stream_format(stream, "suba%s.%s  ACC%s %s%s %s%s", bc, dest, destc, VFREG[rs], destc, VFREG[rt], bc); break;
114 				case 0x08: case 0x09: case 0x0a: case 0x0b:
115 					util::stream_format(stream, "madda%s.%s ACC%s %s%s %s%s", bc, dest, destc, VFREG[rs], destc, VFREG[rt], bc); break;
116 				case 0x0c: case 0x0d: case 0x0e: case 0x0f:
117 					util::stream_format(stream, "msuba%s.%s ACC%s %s%s %s%s", bc, dest, destc, VFREG[rs], destc, VFREG[rt], bc); break;
118 				case 0x10: util::stream_format(stream, "itof0.%s  %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
119 				case 0x11: util::stream_format(stream, "itof4.%s  %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
120 				case 0x12: util::stream_format(stream, "itof12.%s %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
121 				case 0x13: util::stream_format(stream, "itof15.%s %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
122 				case 0x14: util::stream_format(stream, "ftoi0.%s  %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
123 				case 0x15: util::stream_format(stream, "ftoi4.%s  %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
124 				case 0x16: util::stream_format(stream, "ftoi12.%s %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
125 				case 0x17: util::stream_format(stream, "ftoi15.%s %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
126 				case 0x18: case 0x19: case 0x1a: case 0x1b:
127 					util::stream_format(stream, "mula%s.%s  ACC%s %s%s %s%s", bc, dest, destc, VFREG[rs], destc, VFREG[rt], bc); break;
128 				case 0x1c: util::stream_format(stream, "mulaq.%s  ACC%s %s%s Q", dest, destc, VFREG[rs], destc); break;
129 				case 0x1d: util::stream_format(stream, "abs.%s    %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest); break;
130 				case 0x1e: util::stream_format(stream, "mulai.%s  ACC%s %s%s I", dest, destc, VFREG[rs], destc); break;
131 				case 0x1f: util::stream_format(stream, "clipw.xyz   %sxyz, %sw", VFREG[rs], VFREG[rt]); break;
132 				case 0x20: util::stream_format(stream, "addaq.%s  ACC%s %s%s Q", dest, destc, VFREG[rs], destc); break;
133 				case 0x21: util::stream_format(stream, "maddaq.%s ACC%s %s%s Q", dest, destc, VFREG[rs], destc); break;
134 				case 0x22: util::stream_format(stream, "addai.%s  ACC%s %s%s I", dest, destc, VFREG[rs], destc); break;
135 				case 0x23: util::stream_format(stream, "maddai.%s ACC%s %s%s I", dest, destc, VFREG[rs], destc); break;
136 				case 0x24: util::stream_format(stream, "subaq.%s  ACC%s %s%s Q", dest, destc, VFREG[rs], destc); break;
137 				case 0x25: util::stream_format(stream, "msubaq.%s ACC%s %s%s Q", dest, destc, VFREG[rs], destc); break;
138 				case 0x26: util::stream_format(stream, "subai.%s  ACC%s %s%s I", dest, destc, VFREG[rs], destc); break;
139 				case 0x27: util::stream_format(stream, "msubai.%s ACC%s %s%s I", dest, destc, VFREG[rs], destc); break;
140 				case 0x28: util::stream_format(stream, "adda.%s   ACC%s %s%s %s%s", dest, destc, VFREG[rs], destc, VFREG[rt], dest); break;
141 				case 0x29: util::stream_format(stream, "madda.%s  ACC%s %s%s %s%s", dest, destc, VFREG[rs], destc, VFREG[rt], dest); break;
142 				case 0x2a: util::stream_format(stream, "mula.%s   ACC%s %s%s %s%s", dest, destc, VFREG[rs], destc, VFREG[rt], dest); break;
143 				// 2b?
144 				case 0x2c: util::stream_format(stream, "suba.%s   ACC%s %s%s %s%s", dest, destc, VFREG[rs], destc, VFREG[rt], dest); break;
145 				case 0x2d: util::stream_format(stream, "msuba.%s  ACC%s %s%s %s%s", dest, destc, VFREG[rs], destc, VFREG[rt], dest); break;
146 				case 0x2e: util::stream_format(stream, "opmula.xyz  ACCxyz, %sxyz, %sxyz", VFREG[rs], VFREG[rt]); break;
147 				case 0x2f: util::stream_format(stream, "nop"); break;
148 				default:
149 					util::stream_format(stream, "invalid");
150 					break;
151 			}
152 			break;
153 		}
154 		default:
155 			util::stream_format(stream, "invalid");
156 			break;
157 	}
158 }
159 
dasm_lower(uint32_t pc,uint32_t op,std::ostream & stream)160 void sonyvu_disassembler::dasm_lower(uint32_t pc, uint32_t op, std::ostream &stream)
161 {
162 	const int rd   = (op >>  6) & 31;
163 	const int rs   = (op >> 11) & 31;
164 	const int rt   = (op >> 16) & 31;
165 	const char* dest = DEST_STR[(op >> 21) & 15];
166 	const char* destc = DEST_COMMA_STR[(op >> 21) & 15];
167 	const char* ftf = BC_STR[(op >> 23) & 3];
168 	const char* fsf = BC_STR[(op >> 21) & 3];
169 	const char* fsfc = BC_COMMA_STR[(op >> 21) & 3];
170 
171 	switch ((op >> 25) & 0x7f)
172 	{
173 		case 0x00: // LQ
174 			util::stream_format(stream, "lq.%s     %s%s %s(%s)", dest, VFREG[rt], destc, signed_11bit(op), VIREG[rs]);
175 			break;
176 		case 0x01: // SQ
177 			util::stream_format(stream, "sq.%s     %s%s %s(%s)", dest, VFREG[rs], destc, signed_11bit(op), VIREG[rt]);
178 			break;
179 		case 0x04: // ILW
180 			util::stream_format(stream, "ilw.%s    %s, %s(%s)%s", dest, VIREG[rt], destc, signed_11bit(op), VIREG[rs], dest);
181 			break;
182 		case 0x05: // ISW
183 			util::stream_format(stream, "isw.%s    %s, %s(%s)%s", dest, VIREG[rt], destc, signed_11bit(op), VIREG[rs], dest);
184 			break;
185 		case 0x08: // IADDIU
186 			util::stream_format(stream, "iaddiu      %s, %s, %s", VIREG[rt], VIREG[rs], signed_11bit(op));
187 			break;
188 		case 0x09: // ISUBIU
189 			util::stream_format(stream, "isubiu      %s, %s, %s", VIREG[rt], VIREG[rs], signed_11bit(op));
190 			break;
191 		case 0x10: // FCEQ
192 			util::stream_format(stream, "fceq        $vi01, %06x", op & 0xffffff);
193 			break;
194 		case 0x11: // FCSET
195 			util::stream_format(stream, "fcset       %06x", op & 0xffffff);
196 			break;
197 		case 0x12: // FCAND
198 			util::stream_format(stream, "fcand       $vi01, %06x", op & 0xffffff);
199 			break;
200 		case 0x13: // FCOR
201 			util::stream_format(stream, "fcor        $vi01, %06x", op & 0xffffff);
202 			break;
203 		case 0x14: // FSEQ
204 			util::stream_format(stream, "fseq        %s, %s", VIREG[rt], op & 0xfff);
205 			break;
206 		case 0x15: // FSSET
207 			util::stream_format(stream, "fsset       %03x", op & 0xfff);
208 			break;
209 		case 0x16: // FSAND
210 			util::stream_format(stream, "fsand       %s, %s", VIREG[rt], op & 0xfff);
211 			break;
212 		case 0x17: // FSOR
213 			util::stream_format(stream, "fsor        %s, %s", VIREG[rt], op & 0xfff);
214 			break;
215 		case 0x18: // FMEQ
216 			util::stream_format(stream, "fmeq        %s, %s", VIREG[rt], VIREG[rs]);
217 			break;
218 		case 0x1a: // FMAND
219 			util::stream_format(stream, "fmand       %s, %s", VIREG[rt], VIREG[rs]);
220 			break;
221 		case 0x1b: // FMOR
222 			util::stream_format(stream, "fmor        %s, %s", VIREG[rt], VIREG[rs]);
223 			break;
224 		case 0x1c: // FCGET
225 			util::stream_format(stream, "fcget       %s", VIREG[rt]);
226 			break;
227 		case 0x20: // B
228 			util::stream_format(stream, "b           %s", signed_11bit_x8(op));
229 			break;
230 		case 0x21: // BAL
231 			util::stream_format(stream, "bal         %s, %s", VIREG[rt], signed_11bit_x8(op));
232 			break;
233 		case 0x24: // JR
234 			util::stream_format(stream, "jr          %s", VIREG[rs]);
235 			break;
236 		case 0x25: // JALR
237 			util::stream_format(stream, "jalr        %s, %s", VIREG[rt], VIREG[rs]);
238 			break;
239 		case 0x28: // IBEQ
240 			util::stream_format(stream, "ibeq        %s, %s, %s", VIREG[rt], VIREG[rs], signed_11bit_x8(op));
241 			break;
242 		case 0x29: // IBNE
243 			util::stream_format(stream, "ibne        %s, %s, %s", VIREG[rt], VIREG[rs], signed_11bit_x8(op));
244 			break;
245 		case 0x2c: // IBLTZ
246 			util::stream_format(stream, "ibltz       %s, %s", VIREG[rs], signed_11bit_x8(op));
247 			break;
248 		case 0x2d: // IBGTZ
249 			util::stream_format(stream, "ibgtz       %s, %s", VIREG[rs], signed_11bit_x8(op));
250 			break;
251 		case 0x2e: // IBLEZ
252 			util::stream_format(stream, "iblez       %s, %s", VIREG[rs], signed_11bit_x8(op));
253 			break;
254 		case 0x2f: // IBGEZ
255 			util::stream_format(stream, "ibgez       %s, %s", VIREG[rs], signed_11bit_x8(op));
256 			break;
257 		case 0x40: // SPECIAL
258 		{
259 			if ((op & 0x3c) == 0x3c)
260 			{
261 				uint8_t type4_op = ((op & 0x7c0) >> 4) | (op & 3);
262 				switch (type4_op)
263 				{
264 					case 0x30: // MOVE
265 						if (((op >> 21) & 15) == 0 && rt == 0 && rs == 0)
266 							util::stream_format(stream, "nop");
267 						else
268 							util::stream_format(stream, "move.%s   %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest);
269 						break;
270 					case 0x31: // MR32
271 						util::stream_format(stream, "mr32.%s   %s%s %s%s", dest, VFREG[rt], destc, VFREG[rs], dest);
272 						break;
273 					case 0x34: // LQI
274 						util::stream_format(stream, "lqi.%s    %s%s (%s++)", dest, VFREG[rt], destc, VIREG[rs]);
275 						break;
276 					case 0x35: // SQI
277 						util::stream_format(stream, "sqi.%s    %s%s (%s++)", dest, VFREG[rs], destc, VIREG[rt]);
278 						break;
279 					case 0x36: // LQD
280 						util::stream_format(stream, "lqi.%s    %s%s (--%s)", dest, VFREG[rt], destc, VIREG[rs]);
281 						break;
282 					case 0x37: // SQD
283 						util::stream_format(stream, "sqi.%s    %s%s (--%s)", dest, VFREG[rs], destc, VIREG[rt]);
284 						break;
285 					case 0x38: // DIV
286 						util::stream_format(stream, "div         Q, %s%s %s%s", VFREG[rs], fsfc, VFREG[rt], ftf);
287 						break;
288 					case 0x39: // SQRT
289 						util::stream_format(stream, "sqrt        Q, %s%s", dest, VFREG[rt], ftf);
290 						break;
291 					case 0x3a: // RSQRT
292 						util::stream_format(stream, "rsqrt       Q, %s%s %s%s", VFREG[rs], fsfc, VFREG[rt], ftf);
293 						break;
294 					case 0x3b: // WAITQ
295 						util::stream_format(stream, "waitq");
296 						break;
297 					case 0x3c: // MTIR
298 						util::stream_format(stream, "mtir        %s, %s%s", VIREG[rt], VFREG[rs], fsf);
299 						break;
300 					case 0x3d: // MFIR
301 						util::stream_format(stream, "mtir.%s   %s%s %s", dest, VFREG[rt], destc, VIREG[rs]  );
302 						break;
303 					case 0x3e: // ILWR
304 						util::stream_format(stream, "ilwr.%s   %s, (%s)%s", dest, VIREG[rt], VIREG[rs], dest);
305 						break;
306 					case 0x3f: // ISWR
307 						util::stream_format(stream, "iswr.%s   %s, (%s)%s", dest, VIREG[rt], VIREG[rs], dest);
308 						break;
309 					case 0x40: // RNEXT
310 						util::stream_format(stream, "rnext.%s  %s%s R", dest, VFREG[rt], destc);
311 						break;
312 					case 0x41: // RGET
313 						util::stream_format(stream, "rget.%s   %s%s R", dest, VFREG[rt], destc);
314 						break;
315 					case 0x42: // RINIT
316 						util::stream_format(stream, "rinit       R, %s%s", dest, VFREG[rs], dest);
317 						break;
318 					case 0x43: // RXOR
319 						util::stream_format(stream, "rxor        R, %s%s", dest, VFREG[rs], dest);
320 						break;
321 					case 0x64: // MFP
322 						util::stream_format(stream, "mfp.%s    %s%s P", dest, VFREG[rt], destc);
323 						break;
324 					case 0x68: // XTOP
325 						util::stream_format(stream, "xtop        %s", VIREG[rt]);
326 						break;
327 					case 0x69: // XITOP
328 						util::stream_format(stream, "xitop       %s", VIREG[rt]);
329 						break;
330 					case 0x6c: // XGKICK
331 						util::stream_format(stream, "xgkick      %s", VIREG[rs]);
332 						break;
333 					case 0x70: // ESADD
334 						util::stream_format(stream, "esadd       P, %s", VFREG[rs]);
335 						break;
336 					case 0x71: // ERSADD
337 						util::stream_format(stream, "ersadd      P, %s", VFREG[rs]);
338 						break;
339 					case 0x72: // ELENG
340 						util::stream_format(stream, "eleng       P, %s", VFREG[rs]);
341 						break;
342 					case 0x73: // ERLENG
343 						util::stream_format(stream, "erleng      P, %s", VFREG[rs]);
344 						break;
345 					case 0x74: // EATANxy
346 						util::stream_format(stream, "eatanxy     P, %s", VFREG[rs]);
347 						break;
348 					case 0x75: // EATANxz
349 						util::stream_format(stream, "eatanxz     P, %s", VFREG[rs]);
350 						break;
351 					case 0x76: // ESUM
352 						util::stream_format(stream, "esum        P, %s", VFREG[rs]);
353 						break;
354 					case 0x78: // ESQRT
355 						util::stream_format(stream, "esqrt       P, %s%s", VFREG[rs], fsf);
356 						break;
357 					case 0x79: // ERSQRT
358 						util::stream_format(stream, "ersqrt      P, %s%s", VFREG[rs], fsf);
359 						break;
360 					case 0x7a: // ERCPR
361 						util::stream_format(stream, "ercpr       P, %s%s", VFREG[rs], fsf);
362 						break;
363 					case 0x7b: // WAITP
364 						util::stream_format(stream, "waitp");
365 						break;
366 					case 0x7c: // ESIN
367 						util::stream_format(stream, "esin        P, %s%s", VFREG[rs], fsf);
368 						break;
369 					case 0x7d: // EATAN
370 						util::stream_format(stream, "eatan       P, %s%s", VFREG[rs], fsf);
371 						break;
372 					case 0x7e: // EEXP
373 						util::stream_format(stream, "eexp        P, %s%s", VFREG[rs], fsf);
374 						break;
375 					default:
376 						util::stream_format(stream, "invalid");
377 						break;
378 				}
379 				break;
380 			}
381 			else
382 			{
383 				switch (op & 0x3f)
384 				{
385 					case 0x30: // IADD
386 						util::stream_format(stream, "iadd        %s, %s, %s", VIREG[rd], VIREG[rs], VIREG[rt]);
387 						break;
388 					case 0x31: // ISUB
389 						util::stream_format(stream, "isub        %s, %s, %s", VIREG[rd], VIREG[rs], VIREG[rt]);
390 						break;
391 					case 0x32: // IADDI
392 						util::stream_format(stream, "iaddi       %s, %s, %s", VIREG[rt], VIREG[rs], signed_5bit_rd(op));
393 						break;
394 					case 0x34: // IAND
395 						util::stream_format(stream, "iand        %s, %s, %s", VIREG[rd], VIREG[rs], VIREG[rt]);
396 						break;
397 					case 0x35: // IOR
398 						util::stream_format(stream, "ior         %s, %s, %s", VIREG[rd], VIREG[rs], VIREG[rt]);
399 						break;
400 					default:
401 						util::stream_format(stream, "invalid");
402 						break;
403 				}
404 			}
405 			break;
406 		}
407 		default:
408 			util::stream_format(stream, "invalid");
409 			break;
410 	}
411 }
412 
opcode_alignment() const413 uint32_t sonyvu_disassembler::opcode_alignment() const
414 {
415 	return 4;
416 }
417 
signed_5bit(uint16_t val)418 std::string sonyvu_disassembler::signed_5bit(uint16_t val)
419 {
420 	int16_t sval = (int32_t)val;
421 	sval <<= 11;
422 	sval >>= 11;
423 
424 	if (sval < 0)
425 		return util::string_format("-$%x", -sval);
426 	else
427 		return util::string_format("$%x", sval);
428 }
429 
signed_5bit_rd(uint16_t val)430 std::string sonyvu_disassembler::signed_5bit_rd(uint16_t val)
431 {
432 	int16_t sval = (int32_t)((val >> 6) & 0x1f);
433 	sval <<= 11;
434 	sval >>= 11;
435 
436 	if (sval < 0)
437 		return util::string_format("-$%x", -sval);
438 	else
439 		return util::string_format("$%x", sval);
440 }
441 
unsigned_11bit(uint16_t val)442 std::string sonyvu_disassembler::unsigned_11bit(uint16_t val)
443 {
444 	val <<= 5;
445 	val >>= 5;
446 	return util::string_format("$%x", val);
447 }
448 
signed_11bit(uint16_t val)449 std::string sonyvu_disassembler::signed_11bit(uint16_t val)
450 {
451 	int16_t sval = (int32_t)val;
452 	sval <<= 5;
453 	sval >>= 5;
454 
455 	if (sval < 0)
456 		return util::string_format("-$%x", -sval);
457 	else
458 		return util::string_format("$%x", sval);
459 }
460 
signed_11bit_x8(uint16_t val)461 std::string sonyvu_disassembler::signed_11bit_x8(uint16_t val)
462 {
463 	int16_t sval = (int32_t)val;
464 	sval <<= 5;
465 	sval >>= 5;
466 
467 	if (sval < 0)
468 		return util::string_format("-$%x", -sval * 8);
469 	else
470 		return util::string_format("$%x", sval * 8);
471 }
472