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