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