xref: /netbsd/usr.sbin/gspa/gspa/gsp_inst.c (revision 6550d01e)
1 /*	$NetBSD: gsp_inst.c,v 1.11 2009/04/15 08:26:35 lukem Exp $	*/
2 /*
3  * TMS34010 GSP assembler - Instruction encoding
4  *
5  * Copyright (c) 1993 Paul Mackerras.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Paul Mackerras.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: gsp_inst.c,v 1.11 2009/04/15 08:26:35 lukem Exp $");
37 #endif
38 
39 #include <string.h>
40 #include <assert.h>
41 #include "gsp_ass.h"
42 #include "gsp_code.h"
43 
44 struct inst {
45 	const char *opname;
46 	u_int16_t opcode;
47 	u_char	class;		/* instruction class + flags */
48 	u_char	optypes[4];	/* permissible operand classes */
49 };
50 
51 /* Values for flags in class field */
52 #define NOIMM16	0x80		/* can't have 16-bit immediate */
53 #define K32	0x40		/* values 1..32 for K-type constant */
54 #define IMMCOM	0x20		/* immediate value is complemented */
55 #define IMMNEG	0x80		/* immediate value is negated */
56 #define NODSJS	0x80		/* can't use 5-bit branch offset */
57 #define DSHORT	0x40		/* must use 5-bit offset */
58 
59 #define CLASS	0x1F
60 
61 /* Values for class */
62 #define NOP	0		/* no operands */
63 #define ONEREG	1		/* reg */
64 #define TWOREG	2		/* reg, reg */
65 #define DYADIC	3		/* immediate or reg, reg */
66 #define ADD	(DYADIC|K32)
67 #define SUB	(DYADIC|IMMCOM|K32)
68 #define CMP	(DYADIC|IMMCOM)
69 #define AND	(DYADIC|NOIMM16|IMMCOM)
70 #define OR	(DYADIC|NOIMM16)
71 #define IMMREG	4		/* immediate, reg */
72 #define IMMREGC	(IMMREG|IMMCOM)
73 #define LIMREG	(IMMREG|NOIMM16)
74 #define LIMREGC	(LIMREG|IMMCOM)
75 #define KREG	5		/* short immediate, reg */
76 #define K32REG	(KREG|K32)
77 #define SRA	(KREG|IMMNEG)
78 #define BTST	(KREG|IMMCOM)
79 #define CALL	6		/* reg or address */
80 #define JUMP	7
81 #define CLR	8		/* reg appears twice in encoding */
82 #define DSJ	9
83 #define DSJEQ	(DSJ|NODSJS)
84 #define DSJS	(DSJ|DSHORT)
85 #define EXGF	10
86 #define SETF	11
87 #define FILL	12
88 #define LINE	13
89 #define PIXBLT	14
90 #define PIXT	15
91 #define MMFM	16
92 #define MOVB	17
93 #define MOVE	18
94 #define MOVEK	(MOVE|K32)
95 #define RETS	19
96 #define PSEUDO	20
97 
98 /* Composite operand classes */
99 #define EXREG	(REG|EXPR)
100 #define EAREG	(REG|EA)
101 #define EXAREG	(REG|EXPR|EA)
102 #define OPTOPRN	0x80		/* signals optional operand */
103 #define SPEC	(0x10|EXPR)		/* field or length specifier */
104 #define OPTREG	(OPTOPRN|REG)
105 #define OPTEXPR	(OPTOPRN|EXPR)
106 #define OPTSPEC	(OPTOPRN|SPEC)
107 #define OPTXREG	(OPTOPRN|EXREG)
108 
109 #define MIN(a, b)	((a) < (b)? (a): (b))
110 
111 /*
112  * N.B. This list must be sorted in order of opname.
113  */
114 struct inst instructions[] = {
115 	{".BLKB", BLKB,	PSEUDO,	{0,	0,	0,	0}},
116 	{".BLKL", BLKL,	PSEUDO,	{0,	0,	0,	0}},
117 	{".BLKW", BLKW,	PSEUDO,	{0,	0,	0,	0}},
118 #ifdef EQU
119 	{".EQU", EQU,	PSEUDO,	{0,	0,	0,	0}},
120 #endif
121 	{".INCLUDE", INCL, PSEUDO, {0,	0,	0,	0}},
122 	{".LONG", LONG,	PSEUDO,	{0,	0,	0,	0}},
123 	{".ORG", ORG,	PSEUDO,	{0,	0,	0,	0}},
124 	{".START",START,PSEUDO,	{0,	0,	0,	0}},
125 	{".WORD",WORD,	PSEUDO,	{0,	0,	0,	0}},
126 	{"ABS",	0x0380,	ONEREG,	{REG,	0,	0,	0}},
127 	{"ADD",	0x4000,	ADD,	{EXREG,	REG,	OPTSPEC,0}},
128 	{"ADDC",0x4200, TWOREG,	{REG,	REG,	0,	0}},
129 	{"ADDI",0x0B20,	IMMREG,	{EXPR,	REG,	OPTSPEC,0}},
130 	{"ADDK",0x1000,	K32REG,	{EXPR,	REG,	0,	0}},
131 	{"ADDXY",0xE000,TWOREG,	{REG,	REG,	0,	0}},
132 	{"AND",	0x5000,	AND,	{EXREG,	REG,	0,	0}},
133 	{"ANDI",0x0B80,	LIMREGC,{EXPR,	REG,	0,	0}},
134 	{"ANDN",0x5200,	OR,	{EXREG,	REG,	0,	0}},
135 	{"ANDNI",0x0B80,LIMREG,	{EXPR,	REG,	0,	0}},
136 	{"BTST",0x1C00,	BTST,	{EXREG,	REG,	0,	0}},
137 	{"CALL",0x0920,	CALL,	{EXREG,	0,	0,	0}},
138 	{"CALLA",0x0D5F,CALL,	{EXPR,	0,	0,	0}},
139 	{"CALLR",0x0D3F,CALL,	{EXPR,	0,	0,	0}},
140 	{"CLR",	0x5600,	CLR,	{REG,	0,	0,	0}},
141 	{"CLRC",0x0320,	NOP,	{0,	0,	0,	0}},
142 	{"CMP",	0x4800,	CMP,	{EXREG,	REG,	OPTSPEC,0}},
143 	{"CMPI",0x0B60,	IMMREGC,{EXPR,	REG,	OPTSPEC,0}},
144 	{"CMPXY",0xE400,TWOREG,	{REG,	REG,	0,	0}},
145 	{"CPW",	0xE600,	TWOREG,	{REG,	REG,	0,	0}},
146 	{"CVXYL",0xE800,TWOREG,	{REG,	REG,	0,	0}},
147 	{"DEC",	0x1420,	ONEREG,	{REG,	0,	0,	0}},
148 	{"DINT",0x0360,	NOP,	{0,	0,	0,	0}},
149 	{"DIVS",0x5800,	TWOREG,	{REG,	REG,	0,	0}},
150 	{"DIVU",0x5A00,	TWOREG,	{REG,	REG,	0,	0}},
151 	{"DRAV",0xF600,	TWOREG,	{REG,	REG,	0,	0}},
152 	{"DSJ",	0x0D80,	DSJ,	{REG,	EXPR,	0,	0}},
153 	{"DSJEQ",0x0DA0,DSJEQ,	{REG,	EXPR,	0,	0}},
154 	{"DSJNE",0x0DC0,DSJEQ,	{REG,	EXPR,	0,	0}},
155 	{"DSJS",0x3800,	DSJS,	{REG,	EXPR,	0,	0}},
156 	{"EINT",0x0D60,	NOP,	{0,	0,	0,	0}},
157 	{"EMU",	0x0100,	NOP,	{0,	0,	0,	0}},
158 	{"EXGF",0xD500,	EXGF,	{REG,	OPTSPEC,0,	0}},
159 	{"EXGPC",0x0120,ONEREG,	{REG,	0,	0,	0}},
160 	{"FILL",0x0FC0,	FILL,	{SPEC,	0,	0,	0}},
161 	{"GETPC",0x0140,ONEREG,	{REG,	0,	0,	0}},
162 	{"GETST",0x0180,ONEREG,	{REG,	0,	0,	0}},
163 	{"INC",	0x1020,	ONEREG,	{REG,	0,	0,	0}},
164 	{"JAB",	0xC880,	JUMP,	{EXPR,	0,	0,	0}},
165 	{"JAC",	0xC880,	JUMP,	{EXPR,	0,	0,	0}},
166 	{"JAEQ",0xCA80,	JUMP,	{EXPR,	0,	0,	0}},
167 	{"JAGE",0xC580,	JUMP,	{EXPR,	0,	0,	0}},
168 	{"JAGT",0xC780,	JUMP,	{EXPR,	0,	0,	0}},
169 	{"JAHI",0xC380,	JUMP,	{EXPR,	0,	0,	0}},
170 	{"JAHS",0xC980,	JUMP,	{EXPR,	0,	0,	0}},
171 	{"JALE",0xC680,	JUMP,	{EXPR,	0,	0,	0}},
172 	{"JALO",0xC880,	JUMP,	{EXPR,	0,	0,	0}},
173 	{"JALS",0xC280,	JUMP,	{EXPR,	0,	0,	0}},
174 	{"JALT",0xC480,	JUMP,	{EXPR,	0,	0,	0}},
175 	{"JAN",	0xCE80,	JUMP,	{EXPR,	0,	0,	0}},
176 	{"JANB",0xC980,	JUMP,	{EXPR,	0,	0,	0}},
177 	{"JANC",0xC980,	JUMP,	{EXPR,	0,	0,	0}},
178 	{"JANE",0xCB80,	JUMP,	{EXPR,	0,	0,	0}},
179 	{"JANN",0xCF80,	JUMP,	{EXPR,	0,	0,	0}},
180 	{"JANV",0xCD80,	JUMP,	{EXPR,	0,	0,	0}},
181 	{"JANZ",0xCB80,	JUMP,	{EXPR,	0,	0,	0}},
182 	{"JAP",	0xC180,	JUMP,	{EXPR,	0,	0,	0}},
183 	{"JAUC",0xC080,	JUMP,	{EXPR,	0,	0,	0}},
184 	{"JAV",	0xCC80,	JUMP,	{EXPR,	0,	0,	0}},
185 	{"JAZ",	0xCA80,	JUMP,	{EXPR,	0,	0,	0}},
186 	{"JRB",	0xC800,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
187 	{"JRC",	0xC800,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
188 	{"JREQ",0xCA00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
189 	{"JRGE",0xC500,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
190 	{"JRGT",0xC700,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
191 	{"JRHI",0xC300,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
192 	{"JRHS",0xC900,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
193 	{"JRLE",0xC600,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
194 	{"JRLO",0xC800,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
195 	{"JRLS",0xC200,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
196 	{"JRLT",0xC400,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
197 	{"JRN",	0xCE00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
198 	{"JRNB",0xC900,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
199 	{"JRNC",0xC900,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
200 	{"JRNE",0xCB00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
201 	{"JRNN",0xCF00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
202 	{"JRNV",0xCD00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
203 	{"JRNZ",0xCB00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
204 	{"JRP",	0xC100,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
205 	{"JRUC",0xC000,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
206 	{"JRV",	0xCC00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
207 	{"JRZ",	0xCA00,	JUMP,	{EXPR,	OPTSPEC,0,	0}},
208 	{"JUMP",0x0160,	JUMP,	{EXREG,	OPTSPEC,0,	0}},
209 	{"LINE",0xDF1A,	LINE,	{SPEC,	0,	0,	0}},
210 	{"LMO",	0x6A00,	TWOREG,	{REG,	REG,	0,	0}},
211 	{"MMFM",0x09A0,	MMFM,	{REG,	OPTXREG,OPTREG,	OPTREG}},
212 	{"MMTM",0x0980,	MMFM,	{REG,	OPTXREG,OPTREG,	OPTREG}},
213 	{"MODS",0x6C00,	TWOREG,	{REG,	REG,	0,	0}},
214 	{"MODU",0x6E00,	TWOREG,	{REG,	REG,	0,	0}},
215 	{"MOVB",0,	MOVB,	{EAREG,	EAREG,	0,	0}},
216 	{"MOVE",0x4C00,	MOVEK,	{EXAREG,EAREG,	OPTSPEC,0}},
217 	{"MOVI",0x09E0,	IMMREG,	{EXPR,	REG,	OPTSPEC,0}},
218 	{"MOVK",0x1800,	K32REG,	{EXPR,	REG,	0,	0}},
219 	{"MOVX",0xEC00,	TWOREG,	{REG,	REG,	0,	0}},
220 	{"MOVY",0xEE00,	TWOREG,	{REG,	REG,	0,	0}},
221 	{"MPYS",0x5C00,	TWOREG,	{REG,	REG,	0,	0}},
222 	{"MPYU",0x5E00,	TWOREG,	{REG,	REG,	0,	0}},
223 	{"NEG",	0x03A0,	ONEREG,	{REG,	0,	0,	0}},
224 	{"NEGB",0x03C0,	ONEREG,	{REG,	0,	0,	0}},
225 	{"NOP",	0x0300,	NOP,	{0,	0,	0,	0}},
226 	{"NOT",	0x03E0,	ONEREG,	{REG,	0,	0,	0}},
227 	{"OR",	0x5400,	OR,	{EXREG,	REG,	0,	0}},
228 	{"ORI",	0x0BA0,	LIMREG,	{EXPR,	REG,	0,	0}},
229 	{"PIXBLT",0x0F00,PIXBLT,{SPEC,	SPEC,	0,	0}},
230 	{"PIXT",0,	PIXT,	{EAREG,	EAREG,	0,	0}},
231 	{"POPST",0x01C0,NOP,	{0,	0,	0,	0}},
232 	{"PUSHST",0x01E0,NOP,	{0,	0,	0,	0}},
233 	{"PUTST",0x01A0,ONEREG,	{REG,	0,	0,	0}},
234 	{"RETI",0x0940,	NOP,	{0,	0,	0,	0}},
235 	{"RETS",0x0960,	RETS,	{OPTEXPR,0,	0,	0}},
236 	{"REV",	0x0020,	ONEREG,	{REG,	0,	0,	0}},
237 	{"RL",	0x3000,	KREG,	{EXREG,	REG,	0,	0}},
238 	{"SETC",0x0DE0,	NOP,	{0,	0,	0,	0}},
239 	{"SETF",0x0540,	SETF,	{EXPR,	EXPR,	OPTSPEC,0}},
240 	{"SEXT",0x0500,	EXGF,	{REG,	OPTSPEC,0,	0}},
241 	{"SLA",	0x2000,	KREG,	{EXREG,	REG,	0,	0}},
242 	{"SLL",	0x2400,	KREG,	{EXREG,	REG,	0,	0}},
243 	{"SRA",	0x2800,	SRA,	{EXREG,	REG,	0,	0}},
244 	{"SRL",	0x2C00,	SRA,	{EXREG,	REG,	0,	0}},
245 	{"SUB",	0x4400,	SUB,	{EXREG,	REG,	OPTSPEC,0}},
246 	{"SUBB",0x4600,	TWOREG,	{REG,	REG,	0,	0}},
247 	{"SUBI",0x0D00,	IMMREGC,{EXPR,	REG,	OPTSPEC,0}},
248 	{"SUBK",0x1400,	K32REG,	{EXPR,	REG,	0,	0}},
249 	{"SUBXY",0xE200,TWOREG,	{REG,	REG,	0,	0}},
250 	{"TRAP",0x0900,	RETS,	{EXPR,	0,	0,	0}},
251 	{"XOR",	0x5600,	OR,	{EXREG,	REG,	0,	0}},
252 	{"XORI",0x0BC0,	LIMREG,	{EXPR,	REG,	0,	0}},
253 	{"ZEXT",0x0520,	EXGF,	{REG,	OPTSPEC,0,	0}},
254 	{NULL,	0,	0,	{0,	0,	0,	0}}
255 };
256 
257 int check_spec(int spec, const char *valid, const char *what);
258 void do_statement(char *opcode, operand operands);
259 int encode_instr(struct inst *ip, operand ops, int *spec, u_int16_t *iwords);
260 int specifier(operand op);
261 
262 void
263 statement(char *opcode, operand operands)
264 {
265 	do_statement(opcode, operands);
266 	free_operands(operands);
267 }
268 
269 void
270 do_statement(char *opcode, operand operands)
271 {
272 	struct inst *ip;
273 	int i, req;
274 	unsigned nop;
275 	operand op;
276 	int spec[3];
277 	u_int16_t iwords[6];
278 
279 	ucasify(opcode);
280 	i = 1;
281 	for( ip = instructions; ip->opname != NULL; ++ip )
282 		if( opcode[0] == ip->opname[0] ){
283 			i = strcmp(opcode, ip->opname);
284 			if( i <= 0 )
285 				break;
286 		}
287 	if( i != 0 ){
288 		perr("Unknown instruction code %s", opcode);
289 		return;
290 	}
291 	if( ip->class == PSEUDO ){
292 		pseudo(ip->opcode, operands);
293 		return;
294 	}
295 
296 	/* Check correspondence of operands with instruction requirements */
297 	nop = 0;
298 	spec[0] = spec[1] = spec[2] = 0;
299 	for( op = operands; op != NULL; op = op->next ){
300 		req = ip->optypes[MIN(nop, 3)];
301 		if( req == 0 )
302 			break;
303 		if( (op->type & req) == 0 ){
304 			perr("Inappropriate type for operand %u", nop+1);
305 			return;
306 		}
307 		if( (req & ~OPTOPRN) == SPEC ) {
308 			if (nop >= sizeof(spec) / sizeof(spec[0])) {
309 				perr("Spec out of bounds");
310 				return;
311 			}
312 			/* operand is a field/type/length specifier */
313 			spec[nop] = specifier(op);
314 		}
315 		++nop;
316 	}
317 	if( nop < 4 && ip->optypes[nop] != 0
318 	   && (ip->optypes[nop] & OPTOPRN) == 0 ){
319 		perr("Insufficient operands");
320 		return;
321 	}
322 	if( op != NULL )
323 		perr("Extra operands ignored");
324 
325 	i = encode_instr(ip, operands, spec, iwords);
326 
327 	/* Pass 1 processing */
328 	if( !pass2 ){
329 		/* for pass 1, just work out the instruction size */
330 /*		printf("pc = %#x, size = %d\n", pc, i);	*/
331 		pc += i << 4;
332 		return;
333 	}
334 
335 	/* Pass 2 processing */
336 	if( i > 0 )
337 		putcode(iwords, i);
338 }
339 
340 const char *specs[] = { "B", "L", "W", "XY", NULL };
341 
342 int
343 specifier(operand op)
344 {
345 	const char **sl;
346 	expr e;
347 	char sp[4];
348 
349 	if( op->type != EXPR )
350 		return '?';
351 	e = op->op_u.value;
352 	if( e->e_op == CONST ){
353 		if( e->e_val == 0 || e->e_val == 1 )
354 			return e->e_val + '0';
355 	} else if( e->e_op == SYM ){
356 		if( strlen(e->e_sym->name) > 2 )
357 			return '?';
358 		strcpy(sp, e->e_sym->name);
359 		ucasify(sp);
360 		for( sl = specs; *sl != NULL; ++sl )
361 			if( strcmp(*sl, sp) == 0 )
362 				return sp[0];
363 	}
364 	return '?';
365 }
366 
367 int
368 check_spec(int spec, const char *valid, const char *what)
369 {
370 	char *p;
371 
372 	if( spec == 0 )
373 		return 0;
374 	p = strchr(valid, spec);
375 	if( p == NULL ){
376 		perr("Invalid %s specifier", what);
377 		return 0;
378 	}
379 	return p - valid;
380 }
381 
382 u_int16_t code_to_imm[] = {
383 	0x0B20,		/* ADDI */
384 	0,
385 	0x0D00,		/* SUBI */
386 	0,
387 	0x0B60,		/* CMPI */
388 	0,
389 	0x09E0,		/* MOVI */
390 	0,
391 	0x0B80,		/* ANDI */
392 	0x0B80, 	/* ANDNI */
393 	0x0BA0,		/* ORI */
394 	0x0BC0,		/* XORI */
395 };
396 
397 /* Opcodes for MOVE instruction */
398 u_int16_t move_opc[7][7] = {
399 /*				Source */
400 /*	Reg	*Reg	*Reg+	*-Reg	*Reg.XY	*Reg(n)	@addr 	  Dest */
401 	{0x4C00,0x8400,	0x9400,	0xA400,	0,	0xB400,	0x05A0}, /* R */
402 	{0x8000,0x8800,	0,	0,	0,	0,	0},	/* *R */
403 	{0x9000,0,	0x9800,	0,	0,	0xD000,	0xD400}, /* *R+ */
404 	{0xA000,0,	0,	0xA800,	0,	0,	0},	/* *-R */
405 	{0,	0,	0,	0,	0,	0,	0},	/* *R.XY */
406 	{0xB000,0,	0,	0,	0,	0xB800,	0},	/* *R(n) */
407 	{0x0580,0,	0,	0,	0,	0,	0x05C0}	/* @adr */
408 };
409 
410 /* Opcodes for MOVB instruction */
411 u_int16_t movb_opc[7][7] = {
412 /*				Source */
413 /*	Reg	*Reg	*Reg+	*-Reg	*Reg.XY	*Reg(n)	@addr 	  Dest */
414 	{0,	0x8E00,	0,	0,	0,	0xAE00,	0x07E0},/* R */
415 	{0x8C00,0x9C00,	0,	0,	0,	0,	0},	/* *R */
416 	{0,	0,	0,	0,	0,	0,	0},	/* *R+ */
417 	{0,	0,	0,	0,	0,	0,	0},	/* *-R */
418 	{0,	0,	0,	0,	0,	0,	0},	/* *R.XY */
419 	{0xAC00,0,	0,	0,	0,	0xBC00,	0},	/* *R(n) */
420 	{0x05E0,0,	0,	0,	0,	0,	0x0340}	/* @adr */
421 };
422 
423 /* Opcodes for PIXT instruction */
424 u_int16_t pixt_opc[7][7] = {
425 /*				Source */
426 /*	Reg	*Reg	*Reg+	*-Reg	*Reg.XY	*Reg(n)	@addr 	  Dest */
427 	{0,	0xFA00,	0,	0,	0xF200,	0,	0},	/* R */
428 	{0xF800,0xFC00,	0,	0,	0,	0,	0},	/* *R */
429 	{0,	0,	0,	0,	0,	0,	0},	/* *R+ */
430 	{0,	0,	0,	0,	0,	0,	0},	/* *-R */
431 	{0xF000,0,	0,	0,	0xF400,	0,	0},	/* *R.XY */
432 	{0,	0,	0,	0,	0,	0,	0},	/* *R(n) */
433 	{0,	0,	0,	0,	0,	0,	0}	/* @adr */
434 };
435 
436 #define USES_REG(op)	((op)->type == REG \
437 			 || ((op)->type == EA && (op)->mode != M_ABSOLUTE))
438 #define USES_EXPR(op)	((op)->type == EXPR \
439 			 || ((op)->type == EA && (op)->mode >= M_INDEX))
440 
441 int
442 encode_instr(struct inst *ip, operand ops, int *spec, u_int16_t *iwords)
443 {
444 	int rs, rd;
445 	int opc, nw, class, flags, ms, md, off;
446 	int mask, file, bit, i;
447 	operand op0, op1;
448 	unsigned eline[2];
449 	int32_t val[2];
450 
451 	rs = rd = 0;
452 	opc = ip->opcode;
453 	nw = 1;
454 	op0 = ops;
455 	if( op0 != NULL ){
456 		if( spec[0] == 0 && USES_EXPR(op0) )
457 			eval_expr(op0->op_u.value, &val[0], &eline[0]);
458 		op1 = ops->next;
459 		if( op1 != NULL && spec[1] == 0 && USES_EXPR(op1) )
460 			eval_expr(op1->op_u.value, &val[1], &eline[1]);
461 	} else
462 		op1 = NULL;
463 	class = ip->class & CLASS;
464 	flags = ip->class & ~CLASS;
465 	if (class == MOVE && op0 && op1 && op1->type == REG) {
466 		if (op0->type == REG) {
467 			class = DYADIC;
468 			if ((op0->reg_no & op1->reg_no & GSPA_REGFILE) == 0) {
469 				opc += 0x0200;
470 				op1->reg_no ^= GSPA_A0 ^ GSPA_B0;
471 			}
472 		} else if ( op0->type == EXPR )
473 			class = DYADIC;
474 	}
475 	if( class == DYADIC ){
476 		/* turn it into TWOREG, IMMREG or KREG */
477 		if( op0->type == REG ){
478 			class = TWOREG;
479 		} else if( (flags & K32) != 0 && eline[0] <= lineno
480 			  && spec[2] == 0
481 			  && 0 < val[0] && val[0] <= 32 ){
482 			/* use 5-bit immediate */
483 			class = KREG;
484 			opc -= 0x3000;
485 			if( opc == 0x1C00 )
486 				opc = 0x1800;
487 			flags &= ~IMMCOM;
488 		} else {
489 			class = IMMREG;
490 			opc = code_to_imm[(opc - 0x4000) >> 9];
491 		}
492 		if( (class == TWOREG || class == KREG)
493 		   && spec[2] != 0 && op1->next->next == NULL )
494 			perr("Extra operands ignored");
495 	} else if( class == KREG ){
496 		if( op0 && op0->type == REG ){
497 			class = TWOREG;
498 			if( opc < 0x2000 )
499 				opc = 0x4A00;	/* BTST */
500 			else
501 				opc = (opc >> 1) + 0x5000;
502 		}
503 	}
504 
505 	if( op0 != NULL )
506 		rs = op0->reg_no;
507 	if( op1 != NULL ){
508 		rd = op1->reg_no;
509 		if( USES_REG(op0) && USES_REG(op1) ){
510 			if ((rs & rd & GSPA_REGFILE) == 0)
511 				perr("Registers must be in the same register file");
512 			/* force SP to the file of the other operand */
513 			if (rs == GSPA_SP)
514 				rs |= rd;
515 			if (rd == GSPA_SP)
516 				rd |= rs;
517 		}
518 	}
519 
520 	switch( class ){
521 	case NOP:			/* no operands */
522 		break;
523 	case ONEREG:			/* reg */
524 		opc |= rs & 0x1F;
525 		break;
526 	case TWOREG:			/* reg, reg */
527 		opc |= ((rs & 0x0F) << 5) | (rd & 0x1F);
528 		break;
529 	case IMMREG:			/* immediate, reg */
530 		opc |= rd & 0x1F;
531 		if( (flags & IMMCOM) != 0 )
532 			val[0] = ~ val[0];
533 		i = check_spec(spec[2], " WL", "length");
534 		if( i == 1
535 		   || (i == 0 && (flags & NOIMM16) == 0 && eline[0] <= lineno
536 		      && (int16_t)val[0] == val[0] )){
537 			if( (int16_t) val[0] != val[0] )
538 				perr("Value truncated to 16 bits");
539 			opc -= 0x20;
540 			if( opc == 0x0CE0 )	/* SUBI,W */
541 				opc = 0x0BE0;
542 			nw = 2;
543 		} else {
544 			iwords[2] = (val[0] >> 16);
545 			nw = 3;
546 		}
547 		iwords[1] = val[0];
548 		break;
549 	case KREG:			/* short immediate, reg */
550 		opc |= rd & 0x1F;
551 		if( val[0] < 0 || ((flags & K32) == 0 && val[0] > 31)
552 		   || ((flags & K32) != 0 && val[0] <= 0) || val[0] > 32 )
553 			perr("5-bit constant out of range");
554 		rs = val[0];
555 		if( (flags & IMMCOM) != 0 )
556 			rs = ~rs;
557 		else if( (flags & IMMNEG) != 0 )
558 			rs = -rs;
559 		opc |= (rs & 0x1F) << 5;
560 		break;
561 	case CALL:			/* reg or address */
562 		if( op0 && op0->type == REG ){
563 			opc |= rs & 0x1F;
564 			break;
565 		}
566 		off = (int)(val[0] - pc - 0x20) >> 4;
567 		if( opc == 0x0920 ){		/* CALL */
568 			if( eline[0] <= lineno && (int16_t) off == off )
569 				opc = 0x0D3F;	/* CALLR */
570 			else
571 				opc = 0x0D5F;	/* CALLA */
572 		}
573 		if( opc == 0x0D3F ){	/* CALLR */
574 			if( (int16_t) off != off )
575 				perr("Displacement too large");
576 			iwords[1] = off;
577 			nw = 2;
578 		} else {		/* CALLA */
579 			iwords[1] = val[0];
580 			iwords[2] = val[0] >> 16;
581 			nw = 3;
582 		}
583 		break;
584 	case JUMP:
585 		if( op0 && op0->type == REG ){
586 			opc |= rs & 0x1F;
587 			break;
588 		}
589 		off = (int)(val[0] - pc - 0x10) >> 4;
590 		if( (opc & 0x80) != 0 )		/* JAcc */
591 			i = 2;
592 		else
593 			i = check_spec(spec[1], " WL", "length");
594 		if( opc == 0x0160 ){	/* JUMP */
595 			opc = 0xC000;	/* JRUC */
596 			if( i == 0 )
597 				i = 1;	/* ,W is the default for JUMP */
598 		}
599 		switch( i ){
600 		case 2:		/* JAcc */
601 			iwords[1] = val[0];
602 			iwords[2] = val[0] >> 16;
603 			opc |= 0x80;
604 			nw = 3;
605 			break;
606 		case 1:
607 			--off;
608 			if( (int16_t) off != off )
609 				perr("Displacement too large (word)");
610 			iwords[1] = off;
611 			nw = 2;
612 			break;
613 		default:
614 			if( off == 0 || off < -127 || off > 127 )
615 				perr("Short displacement too large or 0");
616 			opc |= off & 0xFF;
617 		}
618 		break;
619 	case CLR:			/* reg appears twice in encoding */
620 		opc |= (rs & 0x1F) | ((rs & 0x0F) << 5);
621 		break;
622 	case DSJ:
623 		off = (int)(val[1] - pc - 0x10) >> 4;
624 		if( flags == 0 ){	/* DSJ */
625 			if( off != 0 && off >= -31 && off <= 31 ){
626 				flags = DSHORT;
627 				opc = 0x3800;	/* DSJS */
628 			}
629 		}
630 		if( flags == DSHORT ){
631 			if( off == 0 || off < -31 || off > 31 )
632 				perr("DSJS displacement too large");
633 			if( off > 0 )
634 				opc |= (off & 0x1F) << 5;
635 			else
636 				opc |= 0x400 | ((-off & 0x1F) << 5);
637 		} else {
638 			--off;
639 			if( (int16_t) off != off )
640 				perr("Displacement too large (word)");
641 			iwords[1] = off;
642 			nw = 2;
643 		}
644 		opc |= rs & 0x1F;
645 		break;
646 	case EXGF:
647 		opc |= rs & 0x1F;
648 		opc |= check_spec(spec[1], "01", "field") << 9;
649 		break;
650 	case SETF:
651 		rs = val[0];
652 		rd = val[1];
653 		if( rs <= 0 || rs > 32 )
654 			perr("Field size must be 1..32");
655 		if( rd != 0 && rd != 1 )
656 			perr("Field extension must be 0 or 1");
657 		opc |= (rs & 0x1F) | ((rd & 1) << 5);
658 		opc |= check_spec(spec[2], "01", "field") << 9;
659 		break;
660 	case FILL:
661 		opc |= check_spec(spec[0], "LX", "array type") << 5;
662 		break;
663 	case LINE:
664 		opc |= check_spec(spec[0], "01", "algorithm") << 7;
665 		break;
666 	case PIXBLT:
667 		rs = check_spec(spec[0], "LXB", "source array type");
668 		rd = check_spec(spec[1], "LX", "destination array type");
669 		opc |= (rs << 6) | (rd << 5);
670 		break;
671 	case MMFM:
672 		opc |= rs & 0xF;
673 		file = rs & GSPA_REGFILE;
674 		if( op1 == NULL )
675 			mask = 0xFFFF;
676 		else if( op1->type == REG ){
677 			file &= rd;
678 			mask = 0;
679 			for( ; op1 != NULL; op1 = op1->next ){
680 				rd = op1->reg_no;
681 				bit = 1 << (~rd & 0xF);
682 				if( file != 0 && (file &= rd) == 0 )
683 					perr("Registers must all be in the same file");
684 				if( file != 0 && (mask & bit) != 0 )
685 					perr("Register name repeated");
686 				mask |= bit;
687 			}
688 		} else {
689 			if( val[1] < 0 || val[1] > 0xFFFFL )
690 				perr("Mask value out of range");
691 			mask = val[1];
692 			if( op1->next != NULL )
693 				perr("Extra operands ignored");
694 		}
695 		if ((file & GSPA_A0 & GSPA_REGFILE) == 0)
696 			opc |= 0x10;
697 		if ((opc & 0x20) != 0) {
698 			/* mask reversed for MMFM */
699 			rs = 0;
700 			for( bit = 16; bit != 0; --bit ){
701 				rs <<= 1;
702 				rs |= mask & 1;
703 				mask >>= 1;
704 			}
705 			mask = rs;
706 		}
707 		iwords[1] = mask;
708 		nw = 2;
709 		break;
710 	case PIXT:
711 	case MOVB:
712 	case MOVE:
713 		ms = op0 && op0->type == REG? M_REG: op0->mode;
714 		assert(op1 != NULL);
715 		md = op1->type == REG? M_REG: op1->mode;
716 		opc = class == MOVE? move_opc[md][ms]:
717 		      class == MOVB? movb_opc[md][ms]: pixt_opc[md][ms];
718 		if( opc == 0 ){
719 			perr("Illegal combination of addressing modes");
720 			nw = 0;
721 			break;
722 		}
723 		if( ms == M_INDEX ){
724 			if( (int16_t) val[0] != val[0] )
725 				perr("Source displacement too large");
726 			iwords[1] = val[0];
727 			nw = 2;
728 		} else if( ms == M_ABSOLUTE ){
729 			iwords[1] = val[0];
730 			iwords[2] = val[0] >> 16;
731 			nw = 3;
732 			rs = 0;
733 		}
734 		if( md == M_INDEX ){
735 			if( (int16_t) val[1] != val[1] )
736 				perr("Destination displacement too large");
737 			iwords[nw] = val[1];
738 			++nw;
739 		} else if( md == M_ABSOLUTE ){
740 			iwords[nw] = val[1];
741 			iwords[nw+1] = val[1] >> 16;
742 			nw += 2;
743 			rd = rs;
744 			rs = 0;
745 		}
746 		opc |= (rd & 0x1F) | ((rs & 0xF) << 5);
747 		opc |= check_spec(spec[2], "01", "field") << 9;
748 		break;
749 	case RETS:
750 		if( op0 == NULL )
751 			val[0] = 0;
752 		else if( val[0] < 0 || val[0] > 31 )
753 			perr("%s out of range",
754 			     (opc > 0x900? "Pop count": "Trap number"));
755 		opc |= val[0] & 0x1F;
756 		break;
757 	default:
758 		perr("BUG: unknown instruction class %d", class);
759 	}
760 	iwords[0] = opc;
761 	return nw;
762 }
763 
764