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
statement(char * opcode,operand operands)263 statement(char *opcode, operand operands)
264 {
265 do_statement(opcode, operands);
266 free_operands(operands);
267 }
268
269 void
do_statement(char * opcode,operand operands)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
specifier(operand op)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
check_spec(int spec,const char * valid,const char * what)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
encode_instr(struct inst * ip,operand ops,int * spec,u_int16_t * iwords)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