xref: /plan9/sys/src/libmach/vcodas.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <bio.h>
4*219b2ee8SDavid du Colombier #include <mach.h>
5*219b2ee8SDavid du Colombier 
6*219b2ee8SDavid du Colombier 	/* mips native disassembler */
7*219b2ee8SDavid du Colombier 
8*219b2ee8SDavid du Colombier typedef struct {
9*219b2ee8SDavid du Colombier 	long addr;			/* pc of instr */
10*219b2ee8SDavid du Colombier 	uchar op;			/* bits 31-26 */
11*219b2ee8SDavid du Colombier 	uchar rs;			/* bits 25-21 */
12*219b2ee8SDavid du Colombier 	uchar rt;			/* bits 20-16 */
13*219b2ee8SDavid du Colombier 	uchar rd;			/* bits 15-11 */
14*219b2ee8SDavid du Colombier 	uchar sa;			/* bits 10-6 */
15*219b2ee8SDavid du Colombier 	uchar function;			/* bits 5-0 */
16*219b2ee8SDavid du Colombier 	long immediate;			/* bits 15-0 */
17*219b2ee8SDavid du Colombier 	ulong cofun;			/* bits 24-0 */
18*219b2ee8SDavid du Colombier 	ulong target;			/* bits 25-0 */
19*219b2ee8SDavid du Colombier 	long w0;
20*219b2ee8SDavid du Colombier 	char *curr;			/* current fill point */
21*219b2ee8SDavid du Colombier 	char *end;			/* end of buffer */
22*219b2ee8SDavid du Colombier 	char *err;
23*219b2ee8SDavid du Colombier } Instr;
24*219b2ee8SDavid du Colombier 
25*219b2ee8SDavid du Colombier typedef struct {
26*219b2ee8SDavid du Colombier 	char *mnemonic;
27*219b2ee8SDavid du Colombier 	char *mipsco;
28*219b2ee8SDavid du Colombier } Opcode;
29*219b2ee8SDavid du Colombier 
30*219b2ee8SDavid du Colombier static char mipscoload[] = "r%t,%l";
31*219b2ee8SDavid du Colombier static char mipscoalui[] = "r%t,r%s,%i";
32*219b2ee8SDavid du Colombier static char mipscoalu3op[] = "r%d,r%s,r%t";
33*219b2ee8SDavid du Colombier static char mipscoboc[] = "r%s,r%t,%b";
34*219b2ee8SDavid du Colombier static char mipscoboc0[] = "r%s,%b";
35*219b2ee8SDavid du Colombier static char mipscorsrt[] = "r%s,r%t";
36*219b2ee8SDavid du Colombier static char mipscorsi[] = "r%s,%i";
37*219b2ee8SDavid du Colombier static char mipscoxxx[] = "%w";
38*219b2ee8SDavid du Colombier static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
39*219b2ee8SDavid du Colombier static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
40*219b2ee8SDavid du Colombier static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
41*219b2ee8SDavid du Colombier 
42*219b2ee8SDavid du Colombier static Opcode opcodes[64] = {
43*219b2ee8SDavid du Colombier 	0,		0,
44*219b2ee8SDavid du Colombier 	0,		0,
45*219b2ee8SDavid du Colombier 	"j",		"%j",
46*219b2ee8SDavid du Colombier 	"jal",		"%j",
47*219b2ee8SDavid du Colombier 	"beq",		mipscoboc,
48*219b2ee8SDavid du Colombier 	"bne",		mipscoboc,
49*219b2ee8SDavid du Colombier 	"blez",		mipscoboc0,
50*219b2ee8SDavid du Colombier 	"bgtz",		mipscoboc0,
51*219b2ee8SDavid du Colombier 	"addi",		mipscoalui,
52*219b2ee8SDavid du Colombier 	"addiu",	mipscoalui,
53*219b2ee8SDavid du Colombier 	"slti",		mipscoalui,
54*219b2ee8SDavid du Colombier 	"sltiu",	mipscoalui,
55*219b2ee8SDavid du Colombier 	"andi",		mipscoalui,
56*219b2ee8SDavid du Colombier 	"ori",		mipscoalui,
57*219b2ee8SDavid du Colombier 	"xori",		mipscoalui,
58*219b2ee8SDavid du Colombier 	"lui",		"r%t,%u",
59*219b2ee8SDavid du Colombier 	"cop0",		0,
60*219b2ee8SDavid du Colombier 	"cop1",		0,
61*219b2ee8SDavid du Colombier 	"cop2",		0,
62*219b2ee8SDavid du Colombier 	"cop3",		0,
63*219b2ee8SDavid du Colombier 	"beql",		mipscoboc,
64*219b2ee8SDavid du Colombier 	"bnel",		mipscoboc,
65*219b2ee8SDavid du Colombier 	"blezl",	mipscoboc0,
66*219b2ee8SDavid du Colombier 	"bgtzl",	mipscoboc0,
67*219b2ee8SDavid du Colombier 	"instr18",	mipscoxxx,
68*219b2ee8SDavid du Colombier 	"instr19",	mipscoxxx,
69*219b2ee8SDavid du Colombier 	"instr1A",	mipscoxxx,
70*219b2ee8SDavid du Colombier 	"instr1B",	mipscoxxx,
71*219b2ee8SDavid du Colombier 	"instr1C",	mipscoxxx,
72*219b2ee8SDavid du Colombier 	"instr1D",	mipscoxxx,
73*219b2ee8SDavid du Colombier 	"instr1E",	mipscoxxx,
74*219b2ee8SDavid du Colombier 	"instr1F",	mipscoxxx,
75*219b2ee8SDavid du Colombier 	"lb",		mipscoload,
76*219b2ee8SDavid du Colombier 	"lh",		mipscoload,
77*219b2ee8SDavid du Colombier 	"lwl",		mipscoload,
78*219b2ee8SDavid du Colombier 	"lw",		mipscoload,
79*219b2ee8SDavid du Colombier 	"lbu",		mipscoload,
80*219b2ee8SDavid du Colombier 	"lhu",		mipscoload,
81*219b2ee8SDavid du Colombier 	"lwr",		mipscoload,
82*219b2ee8SDavid du Colombier 	"instr27",	mipscoxxx,
83*219b2ee8SDavid du Colombier 	"sb",		mipscoload,
84*219b2ee8SDavid du Colombier 	"sh",		mipscoload,
85*219b2ee8SDavid du Colombier 	"swl",		mipscoload,
86*219b2ee8SDavid du Colombier 	"sw",		mipscoload,
87*219b2ee8SDavid du Colombier 	"instr2C",	mipscoxxx,
88*219b2ee8SDavid du Colombier 	"instr2D",	mipscoxxx,
89*219b2ee8SDavid du Colombier 	"swr",		mipscoload,
90*219b2ee8SDavid du Colombier 	"cache",	"",
91*219b2ee8SDavid du Colombier 	"ll",		mipscoload,
92*219b2ee8SDavid du Colombier 	"lwc1",		mipscoload,
93*219b2ee8SDavid du Colombier 	"lwc2",		mipscoload,
94*219b2ee8SDavid du Colombier 	"lwc3",		mipscoload,
95*219b2ee8SDavid du Colombier 	"instr34",	mipscoxxx,
96*219b2ee8SDavid du Colombier 	"ld",		mipscoload,
97*219b2ee8SDavid du Colombier 	"ld",		mipscoload,
98*219b2ee8SDavid du Colombier 	"ld",		mipscoload,
99*219b2ee8SDavid du Colombier 	"sc",		mipscoload,
100*219b2ee8SDavid du Colombier 	"swc1",		mipscoload,
101*219b2ee8SDavid du Colombier 	"swc2",		mipscoload,
102*219b2ee8SDavid du Colombier 	"swc3",		mipscoload,
103*219b2ee8SDavid du Colombier 	"instr3C",	mipscoxxx,
104*219b2ee8SDavid du Colombier 	"sd",		mipscoload,
105*219b2ee8SDavid du Colombier 	"sd",		mipscoload,
106*219b2ee8SDavid du Colombier 	"sd",		mipscoload,
107*219b2ee8SDavid du Colombier };
108*219b2ee8SDavid du Colombier 
109*219b2ee8SDavid du Colombier static Opcode sopcodes[64] = {
110*219b2ee8SDavid du Colombier 	"sll",		"r%d,r%t,$%a",
111*219b2ee8SDavid du Colombier 	"special01",	mipscoxxx,
112*219b2ee8SDavid du Colombier 	"srl",		"r%d,r%t,$%a",
113*219b2ee8SDavid du Colombier 	"sra",		"r%d,r%t,$%a",
114*219b2ee8SDavid du Colombier 	"sllv",		"r%d,r%t,R%s",
115*219b2ee8SDavid du Colombier 	"special05",	mipscoxxx,
116*219b2ee8SDavid du Colombier 	"srlv",		"r%d,r%t,r%s",
117*219b2ee8SDavid du Colombier 	"srav",		"r%d,r%t,r%s",
118*219b2ee8SDavid du Colombier 	"jr",		"r%s",
119*219b2ee8SDavid du Colombier 	"jalr",		"r%d,r%s",
120*219b2ee8SDavid du Colombier 	"special0A",	mipscoxxx,
121*219b2ee8SDavid du Colombier 	"special0B",	mipscoxxx,
122*219b2ee8SDavid du Colombier 	"syscall",	"",
123*219b2ee8SDavid du Colombier 	"break",	"",
124*219b2ee8SDavid du Colombier 	"special0E",	mipscoxxx,
125*219b2ee8SDavid du Colombier 	"sync",		"",
126*219b2ee8SDavid du Colombier 	"mfhi",		"r%d",
127*219b2ee8SDavid du Colombier 	"mthi",		"r%s",
128*219b2ee8SDavid du Colombier 	"mflo",		"r%d",
129*219b2ee8SDavid du Colombier 	"mtlo",		"r%s",
130*219b2ee8SDavid du Colombier 	"special14",	mipscoxxx,
131*219b2ee8SDavid du Colombier 	"special15",	mipscoxxx,
132*219b2ee8SDavid du Colombier 	"special16",	mipscoxxx,
133*219b2ee8SDavid du Colombier 	"special17",	mipscoxxx,
134*219b2ee8SDavid du Colombier 	"mult",		mipscorsrt,
135*219b2ee8SDavid du Colombier 	"multu",	mipscorsrt,
136*219b2ee8SDavid du Colombier 	"div",		mipscorsrt,
137*219b2ee8SDavid du Colombier 	"divu",		mipscorsrt,
138*219b2ee8SDavid du Colombier 	"special1C",	mipscoxxx,
139*219b2ee8SDavid du Colombier 	"special1D",	mipscoxxx,
140*219b2ee8SDavid du Colombier 	"special1E",	mipscoxxx,
141*219b2ee8SDavid du Colombier 	"special1F",	mipscoxxx,
142*219b2ee8SDavid du Colombier 	"add",		mipscoalu3op,
143*219b2ee8SDavid du Colombier 	"addu",		mipscoalu3op,
144*219b2ee8SDavid du Colombier 	"sub",		mipscoalu3op,
145*219b2ee8SDavid du Colombier 	"subu",		mipscoalu3op,
146*219b2ee8SDavid du Colombier 	"and",		mipscoalu3op,
147*219b2ee8SDavid du Colombier 	"or",		mipscoalu3op,
148*219b2ee8SDavid du Colombier 	"xor",		mipscoalu3op,
149*219b2ee8SDavid du Colombier 	"nor",		mipscoalu3op,
150*219b2ee8SDavid du Colombier 	"special28",	mipscoxxx,
151*219b2ee8SDavid du Colombier 	"special29",	mipscoxxx,
152*219b2ee8SDavid du Colombier 	"slt",		mipscoalu3op,
153*219b2ee8SDavid du Colombier 	"sltu",		mipscoalu3op,
154*219b2ee8SDavid du Colombier 	"special2C",	mipscoxxx,
155*219b2ee8SDavid du Colombier 	"special2D",	mipscoxxx,
156*219b2ee8SDavid du Colombier 	"special2E",	mipscoxxx,
157*219b2ee8SDavid du Colombier 	"special2F",	mipscoxxx,
158*219b2ee8SDavid du Colombier 	"tge",		mipscorsrt,
159*219b2ee8SDavid du Colombier 	"tgeu",		mipscorsrt,
160*219b2ee8SDavid du Colombier 	"tlt",		mipscorsrt,
161*219b2ee8SDavid du Colombier 	"tltu",		mipscorsrt,
162*219b2ee8SDavid du Colombier 	"teq",		mipscorsrt,
163*219b2ee8SDavid du Colombier 	"special35",	mipscoxxx,
164*219b2ee8SDavid du Colombier 	"tne",		mipscorsrt,
165*219b2ee8SDavid du Colombier 	"special37",	mipscoxxx,
166*219b2ee8SDavid du Colombier 	"special38",	mipscoxxx,
167*219b2ee8SDavid du Colombier 	"special39",	mipscoxxx,
168*219b2ee8SDavid du Colombier 	"special3A",	mipscoxxx,
169*219b2ee8SDavid du Colombier 	"special3B",	mipscoxxx,
170*219b2ee8SDavid du Colombier 	"special3C",	mipscoxxx,
171*219b2ee8SDavid du Colombier 	"special3D",	mipscoxxx,
172*219b2ee8SDavid du Colombier 	"special3E",	mipscoxxx,
173*219b2ee8SDavid du Colombier 	"special3F",	mipscoxxx,
174*219b2ee8SDavid du Colombier };
175*219b2ee8SDavid du Colombier 
176*219b2ee8SDavid du Colombier static Opcode ropcodes[32] = {
177*219b2ee8SDavid du Colombier 	"bltz",		mipscoboc0,
178*219b2ee8SDavid du Colombier 	"bgez",		mipscoboc0,
179*219b2ee8SDavid du Colombier 	"bltzl",	mipscoboc0,
180*219b2ee8SDavid du Colombier 	"bgezl",	mipscoboc0,
181*219b2ee8SDavid du Colombier 	"regimm04",	mipscoxxx,
182*219b2ee8SDavid du Colombier 	"regimm05",	mipscoxxx,
183*219b2ee8SDavid du Colombier 	"regimm06",	mipscoxxx,
184*219b2ee8SDavid du Colombier 	"regimm07",	mipscoxxx,
185*219b2ee8SDavid du Colombier 	"tgei",		mipscorsi,
186*219b2ee8SDavid du Colombier 	"tgeiu",	mipscorsi,
187*219b2ee8SDavid du Colombier 	"tlti",		mipscorsi,
188*219b2ee8SDavid du Colombier 	"tltiu",	mipscorsi,
189*219b2ee8SDavid du Colombier 	"teqi",		mipscorsi,
190*219b2ee8SDavid du Colombier 	"regimm0D",	mipscoxxx,
191*219b2ee8SDavid du Colombier 	"tnei",		mipscorsi,
192*219b2ee8SDavid du Colombier 	"regimm0F",	mipscoxxx,
193*219b2ee8SDavid du Colombier 	"bltzal",	mipscoboc0,
194*219b2ee8SDavid du Colombier 	"bgezal",	mipscoboc0,
195*219b2ee8SDavid du Colombier 	"bltzall",	mipscoboc0,
196*219b2ee8SDavid du Colombier 	"bgezall",	mipscoboc0,
197*219b2ee8SDavid du Colombier 	"regimm14",	mipscoxxx,
198*219b2ee8SDavid du Colombier 	"regimm15",	mipscoxxx,
199*219b2ee8SDavid du Colombier 	"regimm16",	mipscoxxx,
200*219b2ee8SDavid du Colombier 	"regimm17",	mipscoxxx,
201*219b2ee8SDavid du Colombier 	"regimm18",	mipscoxxx,
202*219b2ee8SDavid du Colombier 	"regimm19",	mipscoxxx,
203*219b2ee8SDavid du Colombier 	"regimm1A",	mipscoxxx,
204*219b2ee8SDavid du Colombier 	"regimm1B",	mipscoxxx,
205*219b2ee8SDavid du Colombier 	"regimm1C",	mipscoxxx,
206*219b2ee8SDavid du Colombier 	"regimm1D",	mipscoxxx,
207*219b2ee8SDavid du Colombier 	"regimm1E",	mipscoxxx,
208*219b2ee8SDavid du Colombier 	"regimm1F",	mipscoxxx,
209*219b2ee8SDavid du Colombier };
210*219b2ee8SDavid du Colombier 
211*219b2ee8SDavid du Colombier static Opcode fopcodes[64] = {
212*219b2ee8SDavid du Colombier 	"add.%f",	mipscofp3,
213*219b2ee8SDavid du Colombier 	"sub.%f",	mipscofp3,
214*219b2ee8SDavid du Colombier 	"mul.%f",	mipscofp3,
215*219b2ee8SDavid du Colombier 	"div.%f",	mipscofp3,
216*219b2ee8SDavid du Colombier 	"sqrt.%f",	mipscofp2,
217*219b2ee8SDavid du Colombier 	"abs.%f",	mipscofp2,
218*219b2ee8SDavid du Colombier 	"mov.%f",	mipscofp2,
219*219b2ee8SDavid du Colombier 	"neg.%f",	mipscofp2,
220*219b2ee8SDavid du Colombier 	"finstr08",	mipscoxxx,
221*219b2ee8SDavid du Colombier 	"finstr09",	mipscoxxx,
222*219b2ee8SDavid du Colombier 	"finstr0A",	mipscoxxx,
223*219b2ee8SDavid du Colombier 	"finstr0B",	mipscoxxx,
224*219b2ee8SDavid du Colombier 	"round.w.%f",	mipscofp2,
225*219b2ee8SDavid du Colombier 	"trunc.w%f",	mipscofp2,
226*219b2ee8SDavid du Colombier 	"ceil.w%f",	mipscofp2,
227*219b2ee8SDavid du Colombier 	"floor.w%f",	mipscofp2,
228*219b2ee8SDavid du Colombier 	"finstr10",	mipscoxxx,
229*219b2ee8SDavid du Colombier 	"finstr11",	mipscoxxx,
230*219b2ee8SDavid du Colombier 	"finstr12",	mipscoxxx,
231*219b2ee8SDavid du Colombier 	"finstr13",	mipscoxxx,
232*219b2ee8SDavid du Colombier 	"finstr14",	mipscoxxx,
233*219b2ee8SDavid du Colombier 	"finstr15",	mipscoxxx,
234*219b2ee8SDavid du Colombier 	"finstr16",	mipscoxxx,
235*219b2ee8SDavid du Colombier 	"finstr17",	mipscoxxx,
236*219b2ee8SDavid du Colombier 	"finstr18",	mipscoxxx,
237*219b2ee8SDavid du Colombier 	"finstr19",	mipscoxxx,
238*219b2ee8SDavid du Colombier 	"finstr1A",	mipscoxxx,
239*219b2ee8SDavid du Colombier 	"finstr1B",	mipscoxxx,
240*219b2ee8SDavid du Colombier 	"finstr1C",	mipscoxxx,
241*219b2ee8SDavid du Colombier 	"finstr1D",	mipscoxxx,
242*219b2ee8SDavid du Colombier 	"finstr1E",	mipscoxxx,
243*219b2ee8SDavid du Colombier 	"finstr1F",	mipscoxxx,
244*219b2ee8SDavid du Colombier 	"cvt.s.%f",	mipscofp2,
245*219b2ee8SDavid du Colombier 	"cvt.d.%f",	mipscofp2,
246*219b2ee8SDavid du Colombier 	"cvt.e.%f",	mipscofp2,
247*219b2ee8SDavid du Colombier 	"cvt.q.%f",	mipscofp2,
248*219b2ee8SDavid du Colombier 	"cvt.w.%f",	mipscofp2,
249*219b2ee8SDavid du Colombier 	"finstr25",	mipscoxxx,
250*219b2ee8SDavid du Colombier 	"finstr26",	mipscoxxx,
251*219b2ee8SDavid du Colombier 	"finstr27",	mipscoxxx,
252*219b2ee8SDavid du Colombier 	"finstr28",	mipscoxxx,
253*219b2ee8SDavid du Colombier 	"finstr29",	mipscoxxx,
254*219b2ee8SDavid du Colombier 	"finstr2A",	mipscoxxx,
255*219b2ee8SDavid du Colombier 	"finstr2B",	mipscoxxx,
256*219b2ee8SDavid du Colombier 	"finstr2C",	mipscoxxx,
257*219b2ee8SDavid du Colombier 	"finstr2D",	mipscoxxx,
258*219b2ee8SDavid du Colombier 	"finstr2E",	mipscoxxx,
259*219b2ee8SDavid du Colombier 	"finstr2F",	mipscoxxx,
260*219b2ee8SDavid du Colombier 	"c.f.%f",	mipscofpc,
261*219b2ee8SDavid du Colombier 	"c.un.%f",	mipscofpc,
262*219b2ee8SDavid du Colombier 	"c.eq.%f",	mipscofpc,
263*219b2ee8SDavid du Colombier 	"c.ueq.%f",	mipscofpc,
264*219b2ee8SDavid du Colombier 	"c.olt.%f",	mipscofpc,
265*219b2ee8SDavid du Colombier 	"c.ult.%f",	mipscofpc,
266*219b2ee8SDavid du Colombier 	"c.ole.%f",	mipscofpc,
267*219b2ee8SDavid du Colombier 	"c.ule.%f",	mipscofpc,
268*219b2ee8SDavid du Colombier 	"c.sf.%f",	mipscofpc,
269*219b2ee8SDavid du Colombier 	"c.ngle.%f",	mipscofpc,
270*219b2ee8SDavid du Colombier 	"c.seq.%f",	mipscofpc,
271*219b2ee8SDavid du Colombier 	"c.ngl.%f",	mipscofpc,
272*219b2ee8SDavid du Colombier 	"c.lt.%f",	mipscofpc,
273*219b2ee8SDavid du Colombier 	"c.nge.%f",	mipscofpc,
274*219b2ee8SDavid du Colombier 	"c.le.%f",	mipscofpc,
275*219b2ee8SDavid du Colombier 	"c.ngt.%f",	mipscofpc,
276*219b2ee8SDavid du Colombier };
277*219b2ee8SDavid du Colombier 
278*219b2ee8SDavid du Colombier static char fsub[16] = {
279*219b2ee8SDavid du Colombier 	's', 'd', 'e', 'q', 'w', '?', '?', '?',
280*219b2ee8SDavid du Colombier 	'?', '?', '?', '?', '?', '?', '?', '?'
281*219b2ee8SDavid du Colombier };
282*219b2ee8SDavid du Colombier 
283*219b2ee8SDavid du Colombier 
284*219b2ee8SDavid du Colombier static int
285*219b2ee8SDavid du Colombier mkinstr(Instr *i, Map *map, ulong pc)
286*219b2ee8SDavid du Colombier {
287*219b2ee8SDavid du Colombier 	long w;
288*219b2ee8SDavid du Colombier 
289*219b2ee8SDavid du Colombier 	if (get4(map, pc, &w) < 0) {
290*219b2ee8SDavid du Colombier 		werrstr("can't read instruction: %r");
291*219b2ee8SDavid du Colombier 		return -1;
292*219b2ee8SDavid du Colombier 	}
293*219b2ee8SDavid du Colombier 	i->addr = pc;
294*219b2ee8SDavid du Colombier 	i->op = (w >> 26) & 0x3F;
295*219b2ee8SDavid du Colombier 	i->rs = (w >> 21) & 0x1F;
296*219b2ee8SDavid du Colombier 	i->rt = (w >> 16) & 0x1F;
297*219b2ee8SDavid du Colombier 	i->rd = (w >> 11) & 0x1F;
298*219b2ee8SDavid du Colombier 	i->sa = (w >> 6) & 0x1F;
299*219b2ee8SDavid du Colombier 	i->function = w & 0x3F;
300*219b2ee8SDavid du Colombier 	i->immediate = w & 0x0000FFFF;
301*219b2ee8SDavid du Colombier 	if (i->immediate & 0x8000)
302*219b2ee8SDavid du Colombier 		i->immediate |= ~0x0000FFFF;
303*219b2ee8SDavid du Colombier 	i->cofun = w & 0x01FFFFFF;
304*219b2ee8SDavid du Colombier 	i->target = w & 0x03FFFFFF;
305*219b2ee8SDavid du Colombier 	i->w0 = w;
306*219b2ee8SDavid du Colombier 	return 1;
307*219b2ee8SDavid du Colombier }
308*219b2ee8SDavid du Colombier 
309*219b2ee8SDavid du Colombier static void
310*219b2ee8SDavid du Colombier bprint(Instr *i, char *fmt, ...)
311*219b2ee8SDavid du Colombier {
312*219b2ee8SDavid du Colombier 	i->curr = doprint(i->curr, i->end, fmt, (&fmt+1));
313*219b2ee8SDavid du Colombier }
314*219b2ee8SDavid du Colombier 
315*219b2ee8SDavid du Colombier static void
316*219b2ee8SDavid du Colombier format(char *mnemonic, Instr *i, char *f)
317*219b2ee8SDavid du Colombier {
318*219b2ee8SDavid du Colombier 	if (mnemonic)
319*219b2ee8SDavid du Colombier 		format(0, i, mnemonic);
320*219b2ee8SDavid du Colombier 	if (f == 0)
321*219b2ee8SDavid du Colombier 		return;
322*219b2ee8SDavid du Colombier 	if (i->curr < i->end)
323*219b2ee8SDavid du Colombier 		*i->curr++ = '\t';
324*219b2ee8SDavid du Colombier 	for ( ; *f && i->curr < i->end; f++) {
325*219b2ee8SDavid du Colombier 		if (*f != '%') {
326*219b2ee8SDavid du Colombier 			*i->curr++ = *f;
327*219b2ee8SDavid du Colombier 			continue;
328*219b2ee8SDavid du Colombier 		}
329*219b2ee8SDavid du Colombier 		switch (*++f) {
330*219b2ee8SDavid du Colombier 
331*219b2ee8SDavid du Colombier 		case 's':
332*219b2ee8SDavid du Colombier 			bprint(i, "%d", i->rs);
333*219b2ee8SDavid du Colombier 			break;
334*219b2ee8SDavid du Colombier 
335*219b2ee8SDavid du Colombier 		case 't':
336*219b2ee8SDavid du Colombier 			bprint(i, "%d", i->rt);
337*219b2ee8SDavid du Colombier 			break;
338*219b2ee8SDavid du Colombier 
339*219b2ee8SDavid du Colombier 		case 'd':
340*219b2ee8SDavid du Colombier 			bprint(i, "%d", i->rd);
341*219b2ee8SDavid du Colombier 			break;
342*219b2ee8SDavid du Colombier 
343*219b2ee8SDavid du Colombier 		case 'a':
344*219b2ee8SDavid du Colombier 			bprint(i, "%d", i->sa);
345*219b2ee8SDavid du Colombier 			break;
346*219b2ee8SDavid du Colombier 
347*219b2ee8SDavid du Colombier 		case 'l':
348*219b2ee8SDavid du Colombier 			if (i->rs == 30) {
349*219b2ee8SDavid du Colombier 				i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
350*219b2ee8SDavid du Colombier 				bprint(i, "(SB)");
351*219b2ee8SDavid du Colombier 			} else
352*219b2ee8SDavid du Colombier 				bprint(i, "%lx(r%d)", i->immediate, i->rs);
353*219b2ee8SDavid du Colombier 			break;
354*219b2ee8SDavid du Colombier 
355*219b2ee8SDavid du Colombier 		case 'i':
356*219b2ee8SDavid du Colombier 			bprint(i, "$%lx", i->immediate);
357*219b2ee8SDavid du Colombier 			break;
358*219b2ee8SDavid du Colombier 
359*219b2ee8SDavid du Colombier 		case 'u':
360*219b2ee8SDavid du Colombier 			*i->curr++ = '$';
361*219b2ee8SDavid du Colombier 			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
362*219b2ee8SDavid du Colombier 			bprint(i, "(SB)");
363*219b2ee8SDavid du Colombier 			break;
364*219b2ee8SDavid du Colombier 
365*219b2ee8SDavid du Colombier 		case 'j':
366*219b2ee8SDavid du Colombier 			i->curr += symoff(i->curr, i->end-i->curr,
367*219b2ee8SDavid du Colombier 				(i->target<<2)|(i->addr & 0xF0000000), CANY);
368*219b2ee8SDavid du Colombier 			bprint(i, "(SB)");
369*219b2ee8SDavid du Colombier 			break;
370*219b2ee8SDavid du Colombier 
371*219b2ee8SDavid du Colombier 		case 'b':
372*219b2ee8SDavid du Colombier 			i->curr += symoff(i->curr, i->end-i->curr,
373*219b2ee8SDavid du Colombier 				(i->immediate<<2)+i->addr+4, CANY);
374*219b2ee8SDavid du Colombier 			break;
375*219b2ee8SDavid du Colombier 
376*219b2ee8SDavid du Colombier 		case 'c':
377*219b2ee8SDavid du Colombier 			bprint(i, "%lux", i->cofun);
378*219b2ee8SDavid du Colombier 			break;
379*219b2ee8SDavid du Colombier 
380*219b2ee8SDavid du Colombier 		case 'w':
381*219b2ee8SDavid du Colombier 			bprint(i, "[%lux]", i->w0);
382*219b2ee8SDavid du Colombier 			break;
383*219b2ee8SDavid du Colombier 
384*219b2ee8SDavid du Colombier 		case 'f':
385*219b2ee8SDavid du Colombier 			*i->curr++ = fsub[i->rs & 0x0F];
386*219b2ee8SDavid du Colombier 			break;
387*219b2ee8SDavid du Colombier 
388*219b2ee8SDavid du Colombier 		case '\0':
389*219b2ee8SDavid du Colombier 			*i->curr++ = '%';
390*219b2ee8SDavid du Colombier 			return;
391*219b2ee8SDavid du Colombier 
392*219b2ee8SDavid du Colombier 		default:
393*219b2ee8SDavid du Colombier 			bprint(i, "%%%c", *f);
394*219b2ee8SDavid du Colombier 			break;
395*219b2ee8SDavid du Colombier 		}
396*219b2ee8SDavid du Colombier 	}
397*219b2ee8SDavid du Colombier }
398*219b2ee8SDavid du Colombier 
399*219b2ee8SDavid du Colombier static void
400*219b2ee8SDavid du Colombier copz(int cop, Instr *i)
401*219b2ee8SDavid du Colombier {
402*219b2ee8SDavid du Colombier 	char *f, *m, buf[16];
403*219b2ee8SDavid du Colombier 
404*219b2ee8SDavid du Colombier 	m = buf;
405*219b2ee8SDavid du Colombier 	f = "%t,%d";
406*219b2ee8SDavid du Colombier 	switch (i->rs) {
407*219b2ee8SDavid du Colombier 
408*219b2ee8SDavid du Colombier 	case 0:
409*219b2ee8SDavid du Colombier 		sprint(buf, "mfc%d", cop);
410*219b2ee8SDavid du Colombier 		break;
411*219b2ee8SDavid du Colombier 
412*219b2ee8SDavid du Colombier 	case 2:
413*219b2ee8SDavid du Colombier 		sprint(buf, "cfc%d", cop);
414*219b2ee8SDavid du Colombier 		break;
415*219b2ee8SDavid du Colombier 
416*219b2ee8SDavid du Colombier 	case 4:
417*219b2ee8SDavid du Colombier 		sprint(buf, "mtc%d", cop);
418*219b2ee8SDavid du Colombier 		break;
419*219b2ee8SDavid du Colombier 
420*219b2ee8SDavid du Colombier 	case 6:
421*219b2ee8SDavid du Colombier 		sprint(buf, "ctc%d", cop);
422*219b2ee8SDavid du Colombier 		break;
423*219b2ee8SDavid du Colombier 
424*219b2ee8SDavid du Colombier 	case 8:
425*219b2ee8SDavid du Colombier 		f = "%b";
426*219b2ee8SDavid du Colombier 		switch (i->rt) {
427*219b2ee8SDavid du Colombier 
428*219b2ee8SDavid du Colombier 		case 0:
429*219b2ee8SDavid du Colombier 			sprint(buf, "bc%df", cop);
430*219b2ee8SDavid du Colombier 			break;
431*219b2ee8SDavid du Colombier 
432*219b2ee8SDavid du Colombier 		case 1:
433*219b2ee8SDavid du Colombier 			sprint(buf, "bc%dt", cop);
434*219b2ee8SDavid du Colombier 			break;
435*219b2ee8SDavid du Colombier 
436*219b2ee8SDavid du Colombier 		case 2:
437*219b2ee8SDavid du Colombier 			sprint(buf, "bc%dfl", cop);
438*219b2ee8SDavid du Colombier 			break;
439*219b2ee8SDavid du Colombier 
440*219b2ee8SDavid du Colombier 		case 3:
441*219b2ee8SDavid du Colombier 			sprint(buf, "bc%dtl", cop);
442*219b2ee8SDavid du Colombier 			break;
443*219b2ee8SDavid du Colombier 
444*219b2ee8SDavid du Colombier 		default:
445*219b2ee8SDavid du Colombier 			sprint(buf, "cop%d", cop);
446*219b2ee8SDavid du Colombier 			f = mipscoxxx;
447*219b2ee8SDavid du Colombier 			break;
448*219b2ee8SDavid du Colombier 		}
449*219b2ee8SDavid du Colombier 		break;
450*219b2ee8SDavid du Colombier 
451*219b2ee8SDavid du Colombier 	default:
452*219b2ee8SDavid du Colombier 		sprint(buf, "cop%d", cop);
453*219b2ee8SDavid du Colombier 		if (i->rs & 0x10)
454*219b2ee8SDavid du Colombier 			f = "function %c";
455*219b2ee8SDavid du Colombier 		else
456*219b2ee8SDavid du Colombier 			f = mipscoxxx;
457*219b2ee8SDavid du Colombier 		break;
458*219b2ee8SDavid du Colombier 	}
459*219b2ee8SDavid du Colombier 	format(m, i, f);
460*219b2ee8SDavid du Colombier }
461*219b2ee8SDavid du Colombier 
462*219b2ee8SDavid du Colombier static void
463*219b2ee8SDavid du Colombier cop0(Instr *i)
464*219b2ee8SDavid du Colombier {
465*219b2ee8SDavid du Colombier 	char *m = 0;
466*219b2ee8SDavid du Colombier 
467*219b2ee8SDavid du Colombier 	if (i->rs >= 0x10) {
468*219b2ee8SDavid du Colombier 		switch (i->cofun) {
469*219b2ee8SDavid du Colombier 
470*219b2ee8SDavid du Colombier 		case 1:
471*219b2ee8SDavid du Colombier 			m = "tlbr";
472*219b2ee8SDavid du Colombier 			break;
473*219b2ee8SDavid du Colombier 
474*219b2ee8SDavid du Colombier 		case 2:
475*219b2ee8SDavid du Colombier 			m = "tlbwi";
476*219b2ee8SDavid du Colombier 			break;
477*219b2ee8SDavid du Colombier 
478*219b2ee8SDavid du Colombier 		case 6:
479*219b2ee8SDavid du Colombier 			m = "tlbwr";
480*219b2ee8SDavid du Colombier 			break;
481*219b2ee8SDavid du Colombier 
482*219b2ee8SDavid du Colombier 		case 8:
483*219b2ee8SDavid du Colombier 			m = "tlbp";
484*219b2ee8SDavid du Colombier 			break;
485*219b2ee8SDavid du Colombier 
486*219b2ee8SDavid du Colombier 		case 16:
487*219b2ee8SDavid du Colombier 			m = "rfe";
488*219b2ee8SDavid du Colombier 			break;
489*219b2ee8SDavid du Colombier 
490*219b2ee8SDavid du Colombier 		case 32:
491*219b2ee8SDavid du Colombier 			m = "eret";
492*219b2ee8SDavid du Colombier 			break;
493*219b2ee8SDavid du Colombier 		}
494*219b2ee8SDavid du Colombier 		if (m) {
495*219b2ee8SDavid du Colombier 			format(m, i, 0);
496*219b2ee8SDavid du Colombier 			if (i->curr < i->end)
497*219b2ee8SDavid du Colombier 				*i->curr++ = 0;
498*219b2ee8SDavid du Colombier 			return;
499*219b2ee8SDavid du Colombier 		}
500*219b2ee8SDavid du Colombier 	}
501*219b2ee8SDavid du Colombier 	copz(0, i);
502*219b2ee8SDavid du Colombier }
503*219b2ee8SDavid du Colombier 
504*219b2ee8SDavid du Colombier int
505*219b2ee8SDavid du Colombier _mipscoinst(Map *map, ulong pc, char *buf, int n)
506*219b2ee8SDavid du Colombier {
507*219b2ee8SDavid du Colombier 	Instr i;
508*219b2ee8SDavid du Colombier 	Opcode *o;
509*219b2ee8SDavid du Colombier 	uchar op;
510*219b2ee8SDavid du Colombier 
511*219b2ee8SDavid du Colombier 	i.curr = buf;
512*219b2ee8SDavid du Colombier 	i.end = buf+n-1;
513*219b2ee8SDavid du Colombier 	if (mkinstr(&i, map, pc) < 0)
514*219b2ee8SDavid du Colombier 		return -1;
515*219b2ee8SDavid du Colombier 	switch (i.op) {
516*219b2ee8SDavid du Colombier 
517*219b2ee8SDavid du Colombier 	case 0x00:					/* SPECIAL */
518*219b2ee8SDavid du Colombier 		o = sopcodes;
519*219b2ee8SDavid du Colombier 		op = i.function;
520*219b2ee8SDavid du Colombier 		break;
521*219b2ee8SDavid du Colombier 
522*219b2ee8SDavid du Colombier 	case 0x01:					/* REGIMM */
523*219b2ee8SDavid du Colombier 		o = ropcodes;
524*219b2ee8SDavid du Colombier 		op = i.rt;
525*219b2ee8SDavid du Colombier 		break;
526*219b2ee8SDavid du Colombier 
527*219b2ee8SDavid du Colombier 	case 0x10:					/* COP0 */
528*219b2ee8SDavid du Colombier 		cop0(&i);
529*219b2ee8SDavid du Colombier 		return 4;
530*219b2ee8SDavid du Colombier 
531*219b2ee8SDavid du Colombier 	case 0x11:					/* COP1 */
532*219b2ee8SDavid du Colombier 		if (i.rs & 0x10) {
533*219b2ee8SDavid du Colombier 			o = fopcodes;
534*219b2ee8SDavid du Colombier 			op = i.function;
535*219b2ee8SDavid du Colombier 			break;
536*219b2ee8SDavid du Colombier 		}
537*219b2ee8SDavid du Colombier 		/*FALLTHROUGH*/
538*219b2ee8SDavid du Colombier 	case 0x12:					/* COP2 */
539*219b2ee8SDavid du Colombier 	case 0x13:					/* COP3 */
540*219b2ee8SDavid du Colombier 		copz(i.op-0x10, &i);
541*219b2ee8SDavid du Colombier 		return 4;
542*219b2ee8SDavid du Colombier 
543*219b2ee8SDavid du Colombier 	default:
544*219b2ee8SDavid du Colombier 		o = opcodes;
545*219b2ee8SDavid du Colombier 		op = i.op;
546*219b2ee8SDavid du Colombier 		break;
547*219b2ee8SDavid du Colombier 	}
548*219b2ee8SDavid du Colombier 	format(o[op].mnemonic, &i, o[op].mipsco);
549*219b2ee8SDavid du Colombier 	return 4;
550*219b2ee8SDavid du Colombier }
551