Home | History | Annotate | Line # | Download | only in gspa
      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