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