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