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