1 #include "l.h" 2 3 static long thumboprr(int); 4 static long thumboprrr(int, int); 5 static long thumbopirr(int , int); 6 static long thumbopri(int); 7 static long thumbophh(int); 8 static long thumbopbra(int); 9 static long thumbopmv(int, int); 10 static void lowreg(Prog *, int); 11 static void mult(Prog *, int, int); 12 static void numr(Prog *, int, int, int); 13 static void regis(Prog *, int, int, int); 14 static void dis(int, int); 15 16 // build a constant using neg, add and shift - only worth it if < 6 bytes */ 17 static int 18 immbuildcon(int c, Prog *p) 19 { 20 int n = 0; 21 22 USED(p); 23 if(c >= 0 && c <= 255) 24 return 0; // mv 25 if(c >= -255 && c < 0) // mv, neg 26 return 1; 27 if(c >= 256 && c <= 510) // mv, add 28 return 1; 29 if(c < 0) 30 return 0; 31 while(!(c & 1)){ 32 n++; 33 c >>= 1; 34 } 35 if(c >= 0 && c <= 255) // mv, lsl 36 return 1; 37 return 0; 38 } 39 40 // positive 5 bit offset from register - O(R) 41 // positive 8 bit offset from register - mov O, R then [R, R] 42 // otherwise O goes in literal pool - mov O1(PC), R then [R, R] 43 static int 44 immoreg(int off, Prog *p) 45 { 46 int v = 1; 47 int as = p->as; 48 49 if(off < 0) 50 return C_GOREG; 51 if(as == AMOVW) 52 v = 4; 53 else if(as == AMOVH || as == AMOVHU) 54 v = 2; 55 else if(as == AMOVB || as == AMOVBU) 56 v = 1; 57 else 58 diag("bad op in immoreg"); 59 if(off/v <= 31) 60 return C_SOREG; 61 if(off <= 255) 62 return C_LOREG; 63 return C_GOREG; 64 } 65 66 // positive 8 bit - mov O, R then 0(R) 67 // otherwise O goes in literal pool - mov O1(PC), R then 0(R) 68 static int 69 immacon(int off, Prog *p, int t1, int t2) 70 { 71 USED(p); 72 if(off < 0) 73 return t2; 74 if(off <= 255) 75 return t1; 76 return t2; 77 } 78 79 // unsigned 8 bit in words 80 static int 81 immauto(int off, Prog *p) 82 { 83 if(p->as != AMOVW) 84 diag("bad op in immauto"); 85 mult(p, off, 4); 86 if(off >= 0 && off <= 1020) 87 return C_SAUTO; 88 return C_LAUTO; 89 } 90 91 static int 92 immsmall(int off, Prog *p, int t1, int t2, int t3) 93 { 94 USED(p); 95 if(off >= 0 && off <= 7) 96 return t1; 97 if(off >= 0 && off <= 255) 98 return t2; 99 return t3; 100 } 101 102 static int 103 immcon(int off, Prog *p) 104 { 105 int as = p->as; 106 107 if(as == ASLL || as == ASRL || as == ASRA) 108 return C_SCON; 109 if(p->to.type == D_REG && p->to.reg == REGSP){ 110 if(as == AADD || as == ASUB){ 111 if(off >= 0 && off <= 508) 112 return C_SCON; 113 if(as == ASUB){ 114 p->as = AADD; 115 p->from.offset = -p->from.offset; 116 } 117 return C_LCON; 118 } 119 diag("unknown type in immcon"); 120 } 121 if(as == AADD || as == ASUB){ 122 if(p->reg != NREG) 123 return immsmall(off, p, C_SCON, C_LCON, C_GCON); 124 return immacon(off, p, C_SCON, C_LCON); 125 } 126 if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p)) 127 return C_BCON; 128 if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p)) 129 return C_BCON; 130 if(as == ACMP || as == AMOVW) 131 return immacon(off, p, C_SCON, C_LCON); 132 return C_LCON; 133 } 134 135 int 136 thumbaclass(Adr *a, Prog *p) 137 { 138 Sym *s; 139 int t; 140 141 switch(a->type) { 142 case D_NONE: 143 return C_NONE; 144 case D_REG: 145 if(a->reg == REGSP) 146 return C_SP; 147 if(a->reg == REGPC) 148 return C_PC; 149 if(a->reg >= 8) 150 return C_HREG; 151 return C_REG; 152 case D_SHIFT: 153 diag("D_SHIFT in thumbaclass"); 154 return C_SHIFT; 155 case D_FREG: 156 diag("D_FREG in thumbaclass"); 157 return C_FREG; 158 case D_FPCR: 159 diag("D_FPCR in thumbaclass"); 160 return C_FCR; 161 case D_OREG: 162 switch(a->name) { 163 case D_EXTERN: 164 case D_STATIC: 165 if(a->sym == 0 || a->sym->name == 0) { 166 print("null sym external\n"); 167 print("%D\n", a); 168 return C_GOK; 169 } 170 t = a->sym->type; 171 if(t == 0 || t == SXREF) { 172 diag("undefined external: %s in %s\n", 173 a->sym->name, TNAME); 174 a->sym->type = SDATA; 175 } 176 instoffset = a->sym->value + a->offset + INITDAT; 177 return C_LEXT; /* INITDAT unknown at this stage */ 178 // return immacon(instoffset, p, C_SEXT, C_LEXT); 179 case D_AUTO: 180 instoffset = autosize + a->offset; 181 return immauto(instoffset, p); 182 case D_PARAM: 183 instoffset = autosize + a->offset + 4L; 184 // print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4); 185 return immauto(instoffset, p); 186 case D_NONE: 187 instoffset = a->offset; 188 if(a->reg == REGSP) 189 return immauto(instoffset, p); 190 else 191 return immoreg(instoffset, p); 192 } 193 return C_GOK; 194 case D_PSR: 195 diag("D_PSR in thumbaclass"); 196 return C_PSR; 197 case D_OCONST: 198 switch(a->name) { 199 case D_EXTERN: 200 case D_STATIC: 201 s = a->sym; 202 t = s->type; 203 if(t == 0 || t == SXREF) { 204 diag("undefined external: %s in %s\n", 205 s->name, TNAME); 206 s->type = SDATA; 207 } 208 instoffset = s->value + a->offset + INITDAT; 209 if(s->type == STEXT || s->type == SLEAF){ 210 instoffset = s->value + a->offset; 211 #ifdef CALLEEBX 212 instoffset += fnpinc(s); 213 #else 214 if(s->thumb) 215 instoffset++; // T bit 216 #endif 217 return C_LCON; 218 } 219 return C_LCON; /* INITDAT unknown at this stage */ 220 // return immcon(instoffset, p); 221 } 222 return C_GOK; 223 case D_FCONST: 224 diag("D_FCONST in thumaclass"); 225 return C_FCON; 226 case D_CONST: 227 switch(a->name) { 228 case D_NONE: 229 instoffset = a->offset; 230 if(a->reg != NREG) 231 goto aconsize; 232 return immcon(instoffset, p); 233 case D_EXTERN: 234 case D_STATIC: 235 s = a->sym; 236 if(s == S) 237 break; 238 t = s->type; 239 switch(t) { 240 case 0: 241 case SXREF: 242 diag("undefined external: %s in %s\n", 243 s->name, TNAME); 244 s->type = SDATA; 245 break; 246 case SCONST: 247 case STEXT: 248 case SLEAF: 249 instoffset = s->value + a->offset; 250 #ifdef CALLEEBX 251 instoffset += fnpinc(s); 252 #else 253 if(s->thumb) 254 instoffset++; // T bit 255 #endif 256 return C_LCON; 257 } 258 instoffset = s->value + a->offset + INITDAT; 259 return C_LCON; /* INITDAT unknown at this stage */ 260 // return immcon(instoffset, p); 261 case D_AUTO: 262 instoffset = autosize + a->offset; 263 goto aconsize; 264 case D_PARAM: 265 instoffset = autosize + a->offset + 4L; 266 aconsize: 267 if(p->from.reg == REGSP || p->from.reg == NREG) 268 return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON; 269 else if(p->from.reg == p->to.reg) 270 return immacon(instoffset, p, C_SACON, C_GACON); 271 return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON); 272 } 273 return C_GOK; 274 case D_BRANCH: { 275 int v, va; 276 277 p->align = 0; 278 v = -4; 279 va = 0; 280 if(p->cond != P){ 281 v = (p->cond->pc - p->pc) - 4; 282 va = p->cond->pc; 283 } 284 instoffset = v; 285 if(p->as == AB){ 286 if(v >= -2048 && v <= 2046) 287 return C_SBRA; 288 p->align = 4; 289 instoffset = va; 290 return C_LBRA; 291 } 292 if(p->as == ABL){ 293 #ifdef CALLEEBX 294 int e; 295 296 if((e = fninc(p->to.sym))) { 297 v += e; 298 va += e; 299 instoffset += e; 300 } 301 #endif 302 if(v >= -4194304 && v <= 4194302) 303 return C_SBRA; 304 p->align = 2; 305 instoffset = va; 306 return C_LBRA; 307 } 308 if(p->as == ABX){ 309 v = va; 310 if(v >= 0 && v <= 255) 311 return C_SBRA; 312 p->align = 2; 313 instoffset = va; 314 return C_LBRA; 315 } 316 if(v >= -256 && v <= 254) 317 return C_SBRA; 318 if(v >= -(2048-2) && v <= (2046+2)) 319 return C_LBRA; 320 p->align = 2; 321 instoffset = va; 322 return C_GBRA; 323 } 324 } 325 return C_GOK; 326 } 327 328 // as a1 a2 a3 type size param lit vers 329 Optab thumboptab[] = 330 { 331 { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, 332 { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, 333 { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 }, 334 { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 }, 335 { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 }, 336 { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 }, 337 { AADD, C_REG, C_REG, C_REG, 2, 2, 0 }, 338 { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 }, 339 { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 }, 340 { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 }, 341 { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM }, 342 // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM }, 343 { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 }, 344 { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 }, 345 { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 }, 346 { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM }, 347 { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 }, 348 { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 }, 349 { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM }, 350 { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 }, 351 { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 }, 352 { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM }, 353 // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM }, 354 // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM }, 355 { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 }, 356 { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM }, 357 { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 }, 358 { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 }, 359 { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, 360 { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 }, 361 { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 }, 362 { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, 363 { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 }, 364 { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 }, 365 { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 }, 366 { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL }, 367 { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 }, 368 { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 }, 369 { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 }, 370 { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL }, 371 { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 }, 372 { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 }, 373 { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 }, 374 { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 }, 375 // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 }, 376 // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 }, 377 { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 }, 378 { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 }, 379 { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 }, 380 { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 }, 381 { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 }, 382 { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 }, 383 { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 }, 384 { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 }, 385 { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 }, 386 { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 }, 387 { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP }, 388 { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM }, 389 // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM }, 390 { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, 391 { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, 392 { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, 393 { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, 394 { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, 395 { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, 396 { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 }, 397 { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO }, 398 { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, 399 { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, 400 { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, 401 { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, 402 { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, 403 { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, 404 { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, 405 { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, 406 { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, 407 { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, 408 { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 }, 409 { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 }, 410 { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 }, 411 { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 }, 412 { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 }, 413 { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, 414 { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, 415 { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, 416 { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, 417 { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 }, 418 { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 }, 419 { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM }, 420 { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 }, 421 { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 }, 422 { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, 423 { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, 424 { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, 425 { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, 426 { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, 427 { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, 428 { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, 429 { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, 430 { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, 431 { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, 432 { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, 433 { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, 434 { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, 435 { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, 436 { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, 437 { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, 438 { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, 439 { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, 440 { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, 441 { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, 442 { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, 443 { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, 444 { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, 445 { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, 446 { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, 447 { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, 448 { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, 449 { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, 450 { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, 451 { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, 452 453 { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 }, 454 }; 455 456 #define OPCNTSZ 52 457 int opcount[OPCNTSZ]; 458 459 // is this too pessimistic ? 460 int 461 brextra(Prog *p) 462 { 463 int c; 464 465 // +2 is for padding 466 if(p->as == ATEXT) 467 return 0-0+2; 468 if(!isbranch(p)) 469 diag("bad op in brextra()"); 470 c = thumbaclass(&p->to, p); 471 switch(p->as){ 472 case AB: 473 if(c != C_SBRA) 474 return 0; 475 return 8-2+2; 476 case ABL: 477 if(c != C_SBRA) 478 return 0; 479 return 14-4+2; 480 case ABX: 481 if(c == C_REG || c == C_HREG) 482 return 0; 483 #ifdef CALLEEBX 484 diag("ABX $I in brextra"); 485 #endif 486 if(c != C_SBRA) 487 return 0; 488 return 14-10+2; 489 default: 490 if(c == C_GBRA) 491 return 0; 492 if(c == C_LBRA) 493 return 10-4+2; 494 return 10-2+2; 495 } 496 } 497 498 #define high(r) ((r)>=8) 499 500 static long 501 mv(Prog *p, int r, int off) 502 { 503 int v, o; 504 if(p != nil && p->cond != nil){ // in literal pool 505 v = p->cond->pc - p->pc - 4; 506 if(p->cond->pc & 3) 507 diag("mv: bad literal pool alignment"); 508 if(v & 3) 509 v += 2; // ensure M(4) offset 510 mult(p, v, 4); 511 off = v/4; 512 numr(p, off, 0, 255); 513 o = 0x9<<11; 514 } 515 else{ 516 numr(p, off, 0, 255); 517 o = 0x4<<11; 518 } 519 o |= (r<<8) | off; 520 return o; 521 } 522 523 static void 524 mvcon(Prog *p, int r, int c, long *o1, long *o2) 525 { 526 int op = 0, n = 0; 527 528 if(c >= 0 && c <= 255) 529 diag("bad c in mvcon"); 530 if(c >= -255 && c < 0) // mv, neg 531 c = -c; 532 else if(c >= 256 && c <= 510){ // mv, add 533 n = rand()%(511-c) + (c-255); 534 c -= n; 535 // n = c-255; 536 // c = 255; 537 op = AADD; 538 } 539 else{ 540 if(c < 0) 541 diag("-ve in mvcon"); 542 while(!(c & 1)){ 543 n++; 544 c >>= 1; 545 } 546 if(c >= 0 && c <= 255) // mv, lsl 547 op = ASLL; 548 else 549 diag("bad shift in mvcon"); 550 } 551 *o1 = mv(p, r, c); 552 switch(op){ 553 case 0: 554 *o2 = (1<<14) | (9<<6) | (r<<3) | r; 555 break; 556 case AADD: 557 *o2 = (6<<11) | (r<<8) | n; 558 break; 559 case ASLL: 560 *o2 = (n<<6) | (r<<3) | r; 561 break; 562 } 563 } 564 565 static long 566 mvlh(int rs, int rd) 567 { 568 int o = 0x46<<8; 569 570 if(high(rs)){ 571 rs -= 8; 572 o |= 1<<6; 573 } 574 if(high(rd)){ 575 rd -= 8; 576 o |= 1<<7; 577 } 578 o |= (rs<<3) | rd; 579 return o; 580 } 581 582 void 583 thumbbuildop() 584 { 585 int i, n, r; 586 Optab *optab = thumboptab; 587 Oprang *oprange = thumboprange; 588 589 for(n=0; optab[n].as != AXXX; n++) 590 ; 591 qsort(optab, n, sizeof(optab[0]), ocmp); 592 for(i=0; i<n; i++) { 593 r = optab[i].as; 594 oprange[r].start = optab+i; 595 while(optab[i].as == r) 596 i++; 597 oprange[r].stop = optab+i; 598 i--; 599 600 switch(r) 601 { 602 default: 603 break; 604 case ABEQ: 605 oprange[ABNE] = oprange[r]; 606 oprange[ABCS] = oprange[r]; 607 oprange[ABHS] = oprange[r]; 608 oprange[ABCC] = oprange[r]; 609 oprange[ABLO] = oprange[r]; 610 oprange[ABMI] = oprange[r]; 611 oprange[ABPL] = oprange[r]; 612 oprange[ABVS] = oprange[r]; 613 oprange[ABVC] = oprange[r]; 614 oprange[ABHI] = oprange[r]; 615 oprange[ABLS] = oprange[r]; 616 oprange[ABGE] = oprange[r]; 617 oprange[ABLT] = oprange[r]; 618 oprange[ABGT] = oprange[r]; 619 oprange[ABLE] = oprange[r]; 620 break; 621 case AMVN: 622 oprange[AADC] = oprange[r]; 623 oprange[ASBC] = oprange[r]; 624 oprange[AMUL] = oprange[r]; 625 oprange[AAND] = oprange[r]; 626 oprange[AEOR] = oprange[r]; 627 oprange[AORR] = oprange[r]; 628 oprange[ABIC] = oprange[r]; 629 oprange[AMULU] = oprange[r]; 630 break; 631 case ACMN: 632 oprange[ATST] = oprange[r]; 633 break; 634 case ASRL: 635 oprange[ASRA] = oprange[r]; 636 oprange[ASLL] = oprange[r]; 637 break; 638 case AADD: 639 oprange[ASUB] = oprange[r]; 640 break; 641 } 642 } 643 } 644 645 void 646 thumbasmout(Prog *p, Optab *o) 647 { 648 long o1, o2, o3, o4, o5, o6, o7, v; 649 int r, rf, rt; 650 651 rf = p->from.reg; 652 rt = p->to.reg; 653 r = p->reg; 654 o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0; 655 if(debug['P']) print("%ulx: %P type %d %d\n", (ulong)(p->pc), p, o->type, p->align); 656 opcount[o->type] += o->size; 657 switch(o->type) { 658 default: 659 diag("unknown asm %d", o->type); 660 prasm(p); 661 break; 662 case 0: /* pseudo ops */ 663 if(debug['G']) print("%ulx: %s: thumb\n", (ulong)(p->pc), p->from.sym->name); 664 break; 665 case 1: /* op R, -, R or op R, R, - */ 666 o1 = thumboprr(p->as); 667 if(rt == NREG) 668 rt = r; 669 lowreg(p, rf); 670 lowreg(p, rt); 671 o1 |= (0x10<<10) | (rf<<3) | rt; 672 break; 673 case 2: /* add/sub R, R, R or add/sub R, -, R */ 674 o1 = p->as == AADD ? 0x0<<9 : 0x1<<9; 675 if(r == NREG) 676 r = rt; 677 lowreg(p, rf); 678 lowreg(p, r); 679 lowreg(p, rt); 680 o1 |= (0x6<<10) | (rf<<6) | (r<<3) | rt; 681 break; 682 case 3: /* add/sub $I, R, R or add/sub $I, -, R */ 683 thumbaclass(&p->from, p); 684 o1 = p->as == AADD ? 0x0<<9 : 0x1<<9; 685 if(r == NREG) 686 r = rt; 687 numr(p, instoffset, 0, 7); 688 lowreg(p, r); 689 lowreg(p, rt); 690 o1 |= (0x7<<10) | (instoffset<<6) | (r<<3) | rt; 691 break; 692 case 4: /* shift $I, R, R or shift $I, -, R */ 693 thumbaclass(&p->from, p); 694 if(instoffset < 0) 695 diag("negative shift in thumbasmout"); 696 instoffset %= 32; 697 o1 = thumbopri(p->as); 698 if(r == NREG) 699 r = rt; 700 numr(p, instoffset, 0, 31); 701 lowreg(p, r); 702 lowreg(p, rt); 703 o1 |= (0x0<<13) | (instoffset<<6) | (r<<3) | rt; 704 break; 705 case 5: /* add/sub/mov $I, -, R or cmp $I, R, - */ 706 thumbaclass(&p->from, p); 707 o1 = thumbopri(p->as); 708 if(rt == NREG) 709 rt = r; 710 numr(p, instoffset, 0, 255); 711 lowreg(p, rt); 712 o1 |= (0x1<<13) | (rt<<8) | instoffset; 713 break; 714 case 6: /* add $I, PC/SP, R */ 715 if(p->as == ASUB) 716 diag("subtract in add $I, PC/SP, R"); 717 thumbaclass(&p->from, p); 718 o1 = r == REGSP ? 0x1<<11 : 0x0<<11; 719 numr(p, instoffset, 0, 255); 720 regis(p, r, REGSP, REGPC); 721 lowreg(p, rt); 722 o1 |= (0xa<<12) | (rt<<8) | instoffset; 723 break; 724 case 7: /* add, sub $I, SP */ 725 thumbaclass(&p->from, p); 726 o1 = p->as == AADD ? 0x0<<7 : 0x1<<7; 727 numr(p, instoffset, 0, 508); 728 mult(p, instoffset, 4); 729 regis(p, rt, REGSP, REGSP); 730 o1 |= (0xb0<<8) | (instoffset>>2); 731 break; 732 case 8: /* add/mov/cmp R, R where at least 1 reg is high */ 733 o1 = 0; 734 if(rt == NREG) 735 rt = r; 736 if(high(rf)){ 737 o1 |= 1<<6; 738 rf -= 8; 739 } 740 if(high(rt)){ 741 o1 |= 2<<6; 742 rt -= 8; 743 } 744 if(o1 == 0) 745 diag("no high register(%P)", p); 746 o1 |= thumbophh(p->as); 747 o1 |= (0x11<<10) | (rf<<3) | rt; 748 break; 749 case 9: /* B $I */ 750 thumbaclass(&p->to, p); 751 numr(p, instoffset, -2048, 2046); 752 o1 = (0x1c<<11) | ((instoffset>>1)&0x7ff); 753 break; 754 case 10: /* Bcc $I */ 755 thumbaclass(&p->to, p); 756 numr(p, instoffset, -256, 254); 757 o1 = thumbopbra(p->as); 758 o1 |= (0xd<<12) | ((instoffset>>1)&0xff); 759 break; 760 case 11: /* BL $I */ 761 thumbaclass(&p->to, p); 762 numr(p, instoffset, -4194304, 4194302); 763 o1 = (0x1e<<11) | ((instoffset>>12)&0x7ff); 764 o2 = (0x1f<<11) | ((instoffset>>1)&0x7ff); 765 break; 766 case 12: /* BX $I */ 767 #ifdef CALLEEBX 768 diag("BX $I case"); 769 #endif 770 thumbaclass(&p->to, p); 771 if(p->to.sym->thumb) 772 instoffset |= 1; // T bit 773 o1 = mvlh(REGPC, REGTMPT); 774 o2 = (0x6<<11) | (REGTMPT<<8) | 7; // add 7, RTMP (T bit + PC offset) 775 o3 = mvlh(REGTMPT, REGLINK); 776 o4 = mv(nil, REGTMPT, instoffset); 777 o5 = (0x11c<<6) | (REGTMPT<<3); 778 // o1 = mv(nil, REGTMPT, v); 779 // o2 = (0x11b<<6) | (REGPC<<3) | REGLINK; 780 // o3 = (0x11c<<6) | (REGTMPT<<3); 781 break; 782 case 13: /* B O(R) */ 783 diag("B O(R)"); 784 break; 785 case 14: /* BL O(R) */ 786 diag("BL O(R)"); 787 break; 788 case 15: /* BX R */ 789 o1 = mvlh(REGPC, REGTMPT); 790 o2 = (0x6<<11) | (REGTMPT<<8) | 5; // add 5, RTMP (T bit + PC offset) 791 o3 = mvlh(REGTMPT, REGLINK); 792 o4 = 0; 793 if(high(rt)){ 794 rt -= 8; 795 o4 |= 1<<6; 796 } 797 o4 |= (0x8e<<7) | (rt<<3); 798 // o1 = (0x11c<<6) | (rt<<3); 799 break; 800 case 16: /* SWI $I */ 801 thumbaclass(&p->to, p); 802 numr(p, instoffset, 0, 255); 803 o1 = (0xdf<<8) | instoffset; 804 break; 805 case 17: /* AWORD */ 806 thumbaclass(&p->to, p); 807 o1 = instoffset&0xffff; 808 o2 = (instoffset>>16)&0xffff; 809 break; 810 case 18: /* AMOVW O(SP), R and AMOVW O(PC), R */ 811 thumbaclass(&p->from, p); 812 rf = o->param; 813 o1 = rf == REGSP ? 0x13<<11 : 0x9<<11; 814 regis(p, rf, REGSP, REGPC); 815 lowreg(p, rt); 816 mult(p, instoffset, 4); 817 numr(p, instoffset/4, 0, 255); 818 o1 |= (rt<<8) | (instoffset/4); 819 break; 820 case 19: /* AMOVW... O(R), R */ 821 thumbaclass(&p->from, p); 822 o1 = thumbopmv(p->as, 1); 823 v = 4; 824 if(p->as == AMOVHU) 825 v = 2; 826 else if(p->as == AMOVBU) 827 v = 1; 828 mult(p, instoffset, v); 829 lowreg(p, rf); 830 lowreg(p, rt); 831 numr(p, instoffset/v, 0, 31); 832 o1 |= ((instoffset/v)<<6) | (rf<<3) | rt; 833 break; 834 case 20: /* AMOVW R, O(SP) */ 835 thumbaclass(&p->to, p); 836 o1 = 0x12<<11; 837 if(rt != NREG) regis(p, rt, REGSP, REGSP); 838 lowreg(p, rf); 839 mult(p, instoffset, 4); 840 numr(p, instoffset/4, 0, 255); 841 o1 |= (rf<<8) | (instoffset/4); 842 break; 843 case 21: /* AMOVW... R, O(R) */ 844 thumbaclass(&p->to, p); 845 o1 = thumbopmv(p->as, 0); 846 v = 4; 847 if(p->as == AMOVHU || p->as == AMOVH) 848 v = 2; 849 else if(p->as == AMOVBU || p->as == AMOVB) 850 v = 1; 851 lowreg(p, rf); 852 lowreg(p, rt); 853 mult(p, instoffset, v); 854 numr(p, instoffset/v, 0, 31); 855 o1 |= ((instoffset/v)<<6) | (rt<<3) | rf; 856 break; 857 case 22: /* AMOVW R, R -> ASLL $0, R, R */ 858 o1 = thumbopri(ASLL); 859 lowreg(p, rf); 860 lowreg(p, rt); 861 o1 |= (0x0<<13) | (rf<<3) | rt; 862 break; 863 case 23: /* AMOVB/AMOVH/AMOVBU/AMOVHU R, R */ 864 o1 = thumbopri(ASLL); 865 o2 = p->as == AMOVB || p->as == AMOVH ? thumbopri(ASRA) : thumbopri(ASRL); 866 v = p->as == AMOVB || p->as == AMOVBU ? 24 : 16; 867 lowreg(p, rf); 868 lowreg(p, rt); 869 o1 |= (0x0<<13) | (v<<6) | (rf<<3) | rt; 870 o2 |= (0x0<<13) | (v<<6) | (rt<<3) | rt; 871 break; 872 case 24: /* AMOVH/AMOVB O(R), R -> AMOVH/AMOVB [R, R], R */ 873 thumbaclass(&p->from, p); 874 lowreg(p, rf); 875 lowreg(p, rt); 876 if(rf == rt) 877 r = REGTMPT; 878 else 879 r = rt; 880 if(p->as == AMOVB) 881 numr(p, instoffset, 0, 31); 882 else{ 883 mult(p, instoffset, 2); 884 numr(p, instoffset, 0, 62); 885 } 886 o1 = mv(p, r, instoffset); 887 o2 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9; 888 o2 |= (r<<6) | (rf<<3) | rt; 889 break; 890 case 25: /* MOVW $sacon, R */ 891 thumbaclass(&p->from, p); 892 // print("25: %d %d %d %d\n", instoffset, rf, r, rt); 893 if(rf == NREG) 894 rf = REGSP; 895 lowreg(p, rt); 896 if(rf == REGSP){ 897 mult(p, instoffset, 4); 898 numr(p, instoffset>>2, 0, 255); 899 o1 = (0x15<<11) | (rt<<8) | (instoffset>>2); // add $O, SP, R 900 } 901 else if(rf == rt){ 902 numr(p, instoffset, 0, 255); 903 o1 = (0x6<<11) | (rt<<8) | instoffset; // add $O, R 904 } 905 else{ 906 lowreg(p, rf); 907 numr(p, instoffset, 0, 7); 908 o1 = (0xe<<9) | (instoffset<<6) | (rf<<3) | rt; // add $O, Rs, Rd 909 } 910 break; 911 case 26: /* AMOVM $c, oreg -> stmia */ 912 lowreg(p, rt); 913 numr(p, p->from.offset, -256, 255); 914 o1 = (0x18<<11) | (rt<<8) | (p->from.offset&0xff); 915 break; 916 case 27: /* AMOVM oreg, $c ->ldmia */ 917 lowreg(p, rf); 918 numr(p, p->to.offset, -256, 256); 919 o1 = (0x19<<11) | (rf<<8) | (p->to.offset&0xff); 920 break; 921 case 28: /* AMOV* O(R), R -> AMOV* [R, R], R (offset large) */ 922 thumbaclass(&p->from, p); 923 lowreg(p, rf); 924 lowreg(p, rt); 925 if(rf == rt) 926 r = REGTMPT; 927 else 928 r = rt; 929 o1 = mv(p, r, instoffset); 930 o2 = thumboprrr(p->as, 1); 931 o2 |= (r<<6) | (rf<<3) | rt; 932 break; 933 case 29: /* AMOV* R, O(R) -> AMOV* R, [R, R] (offset large) */ 934 thumbaclass(&p->to, p); 935 lowreg(p, rf); 936 lowreg(p, rt); 937 if(rt == REGTMPT){ // used as tmp reg 938 if(instoffset >= 0 && instoffset <= 255){ 939 o1 = (1<<13) | (2<<11) | (rt<<8) | instoffset; // add $O, R7 940 o2 = thumbopirr(p->as, 0); 941 o2 |= (0<<6) | (rt<<3) | rf; // mov* R, 0(R) 942 } 943 else 944 diag("big offset - case 29"); 945 } 946 else{ 947 o1 = mv(p, REGTMPT, instoffset); 948 o2 = thumboprrr(p->as, 0); 949 o2 |= (REGTMPT<<6) | (rt<<3) | rf; 950 } 951 break; 952 case 30: /* AMOVW... *addr, R */ 953 thumbaclass(&p->from, p); 954 o1 = mv(p, rt, instoffset); // MOV addr, rtmp 955 o2 = thumbopmv(p->as, 1); 956 lowreg(p, rt); 957 o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R 958 break; 959 case 31: /* AMOVW... R, *addr */ 960 thumbaclass(&p->to, p); 961 o1 = mv(p, REGTMPT, instoffset); 962 o2 = thumbopmv(p->as, 0); 963 lowreg(p, rf); 964 o2 |= (REGTMPT<<3) | rf; 965 break; 966 case 32: /* AMOVH/AMOVB *addr, R -> AMOVH/AMOVB [R, R], R */ 967 thumbaclass(&p->from, p); 968 o1 = mv(p, rt, instoffset); 969 lowreg(p, rt); 970 o2 = mv(nil, REGTMPT, 0); 971 o3 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9; 972 o3 |= (REGTMPT<<6) | (rt<<3) | rt; 973 break; 974 case 33: /* AMOVW O(SP), R (O large) */ 975 thumbaclass(&p->from, p); 976 lowreg(p, rt); 977 o1 = mv(p, rt, instoffset); 978 o2 = (0x111<<6) | (REGSP-8)<<3 | rt; // add SP, rt 979 o3 = thumbopmv(p->as, 1); 980 o3 |= (rt<<3) | rt; 981 break; 982 case 34: /* AMOVW R, O(SP) (O large) */ 983 thumbaclass(&p->to, p); 984 lowreg(p, rf); 985 o1 = mv(p, REGTMPT, instoffset); 986 o2 = (0x111<<6) | (REGSP-8)<<3 | REGTMPT; // add SP, REGTMP 987 o3 = thumbopmv(p->as, 0); 988 o3 |= (REGTMPT<<3) | rf; 989 break; 990 case 35: /* AMOVW $lacon, R */ 991 thumbaclass(&p->from, p); 992 lowreg(p, rt); 993 if(rf == NREG) 994 rf = REGSP; 995 if(rf == rt) 996 rf = r = REGTMPT; 997 else 998 r = rt; 999 // print("35: io=%d rf=%d rt=%d\n", instoffset, rf, rt); 1000 o1 = mv(p, r, instoffset); // mov O, Rd 1001 if(high(rf)) 1002 o2 = (0x44<<8) | (0x1<<6) | ((rf-8)<<3) | rt; // add Rs, Rd 1003 else 1004 o2 = (0x6<<10) | (rf<<6) | (rt<<3) | rt; // add Rs, Rd 1005 break; 1006 case 36: /* AADD/ASUB $i, r, r when $i too big */ 1007 thumbaclass(&p->from, p); 1008 lowreg(p, r); 1009 lowreg(p, rt); 1010 o1 = mv(p, REGTMPT, instoffset); 1011 o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; 1012 o2 |= (REGTMPT<<6) | (r<<3) | rt; 1013 break; 1014 case 37: /* AADD/ASUB $i, r when $i too big */ 1015 thumbaclass(&p->from, p); 1016 lowreg(p, rt); 1017 o1 = mv(p, REGTMPT, instoffset); 1018 o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; 1019 o2 |= (REGTMPT<<6) | (rt<<3) | rt; 1020 break; 1021 case 38: /* AMOVW $i, r when $i too big */ 1022 thumbaclass(&p->from, p); 1023 lowreg(p, rt); 1024 o1 = mv(p, rt, instoffset); 1025 break; 1026 case 39: /* ACMP $i, r when $i too big */ 1027 thumbaclass(&p->from, p); 1028 lowreg(p, r); 1029 o1 = mv(p, REGTMPT, instoffset); 1030 o2 = (0x10a<<6) | (REGTMPT<<3) | r; 1031 break; 1032 case 40: /* add, sub $I, SP when $I large*/ 1033 thumbaclass(&p->from, p); 1034 if(p->as == ASUB) 1035 instoffset = -instoffset; 1036 o1 = mv(p, REGTMPT, instoffset); 1037 o2 = (0x112<<6) | (REGTMPT<<3) | (REGSP-8); 1038 regis(p, rt, REGSP, REGSP); 1039 break; 1040 case 41: /* BL LBRA */ 1041 thumbaclass(&p->to, p); 1042 o1 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7 1043 o2 = mvlh(REGTMPT, REGPC); // mov r7, pc 1044 o3 = instoffset&0xffff; // $lab 1045 o4 = (instoffset>>16)&0xffff; 1046 break; 1047 case 42: /* Bcc GBRA */ 1048 thumbaclass(&p->to, p); 1049 o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (6>>1); // bccnot 1050 // ab lbra 1051 o2 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7 1052 o3 = mvlh(REGTMPT, REGPC); // mov r7, pc 1053 o4 = instoffset&0xffff; // $lab 1054 o5 = (instoffset>>16)&0xffff; 1055 break; 1056 case 43: /* BL LBRA */ 1057 thumbaclass(&p->to, p); 1058 o1 = mvlh(REGPC, REGTMPT); // mov pc, r7 1059 o2 = (0x6<<11) | (REGTMPT<<8) | 10; // add 10, r7 1060 o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr 1061 o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7 1062 o5 = mvlh(REGTMPT, REGPC); // mov r7, pc 1063 o6 = instoffset&0xffff; // $lab 1064 o7 = (instoffset>>16)&0xffff; 1065 break; 1066 case 44: /* BX LBRA */ 1067 #ifdef CALLEEBX 1068 diag("BX LBRA case"); 1069 #endif 1070 thumbaclass(&p->to, p); 1071 if(p->to.sym->thumb) 1072 instoffset |= 1; // T bit 1073 o1 = mvlh(REGPC, REGTMPT); // mov pc, r7 1074 o2 = (0x6<<11) | (REGTMPT<<8) | 11; // add 11, r7 1075 o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr 1076 o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7 1077 o5 = (0x11c<<6) | (REGTMPT<<3); // bx r7 1078 o6 = instoffset&0xffff; // $lab 1079 o7 = (instoffset>>16)&0xffff; 1080 break; 1081 case 45: /* BX R when returning from fn */ 1082 o1 = 0; 1083 if(high(rt)){ 1084 rt -= 8; 1085 o1 |= 1<<6; 1086 } 1087 o1 |= (0x8e<<7) | (rt<<3); 1088 break; 1089 case 46: /* Bcc LBRA */ 1090 thumbaclass(&p->to, p); 1091 o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (0>>1); // bccnot 1092 // ab lbra 1093 instoffset -= 2; 1094 numr(p, instoffset, -2048, 2046); 1095 o2 = (0x1c<<11) | ((instoffset>>1)&0x7ff); 1096 break; 1097 case 47: /* mov $i, R where $i can be built */ 1098 thumbaclass(&p->from, p); 1099 mvcon(p, rt, instoffset, &o1, &o2); 1100 break; 1101 case 48: /* ACMP $i, r when $i built up */ 1102 thumbaclass(&p->from, p); 1103 lowreg(p, r); 1104 mvcon(p, REGTMPT, instoffset, &o1, &o2); 1105 o3 = (0x10a<<6) | (REGTMPT<<3) | r; 1106 break; 1107 case 49: /* AADD $i, r, r when $i is between 0 and 255 - could merge with case 36 */ 1108 thumbaclass(&p->from, p); 1109 lowreg(p, r); 1110 lowreg(p, rt); 1111 numr(p, instoffset, 0, 255); 1112 o1 = mv(p, REGTMPT, instoffset); 1113 o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; 1114 o2 |= (REGTMPT<<6) | (r<<3) | rt; 1115 break; 1116 case 50: /* ADWORD */ 1117 thumbaclass(&p->from, p); 1118 o1 = instoffset&0xffff; 1119 o2 = (instoffset>>16)&0xffff; 1120 thumbaclass(&p->to, p); 1121 o3 = instoffset&0xffff; 1122 o4 = (instoffset>>16)&0xffff; 1123 break; 1124 case 51: /* BL r */ 1125 o1 = mvlh(REGPC, REGLINK); // mov pc, lr 1126 o2 = mvlh(rt, REGPC); // mov r, pc 1127 break; 1128 } 1129 1130 v = p->pc; 1131 switch(o->size) { 1132 default: 1133 if(debug['a']) 1134 Bprint(&bso, " %.8lux:\t\t%P\n", v, p); 1135 break; 1136 case 2: 1137 if(debug['a']) 1138 Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); 1139 hputl(o1); 1140 break; 1141 case 4: 1142 if(debug['a']) 1143 Bprint(&bso, " %.8lux: %.8lux %.8lux\t%P\n", v, o1, o2, p); 1144 hputl(o1); 1145 hputl(o2); 1146 break; 1147 case 6: 1148 if(debug['a']) 1149 Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p); 1150 hputl(o1); 1151 hputl(o2); 1152 hputl(o3); 1153 break; 1154 case 8: 1155 if(debug['a']) 1156 Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, p); 1157 hputl(o1); 1158 hputl(o2); 1159 hputl(o3); 1160 hputl(o4); 1161 break; 1162 case 10: 1163 if(debug['a']) 1164 Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, p); 1165 hputl(o1); 1166 hputl(o2); 1167 hputl(o3); 1168 hputl(o4); 1169 hputl(o5); 1170 break; 1171 case 12: 1172 if(debug['a']) 1173 Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, p); 1174 hputl(o1); 1175 hputl(o2); 1176 hputl(o3); 1177 hputl(o4); 1178 hputl(o5); 1179 hputl(o6); 1180 break; 1181 case 14: 1182 if(debug['a']) 1183 Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p); 1184 hputl(o1); 1185 hputl(o2); 1186 hputl(o3); 1187 hputl(o4); 1188 hputl(o5); 1189 hputl(o6); 1190 hputl(o7); 1191 break; 1192 } 1193 if(debug['G']){ 1194 if(o->type == 17){ 1195 print("%lx: word %ld\n", p->pc, (o2<<16)+o1); 1196 return; 1197 } 1198 if(o->type == 50){ 1199 print("%lx: word %ld\n", p->pc, (o2<<16)+o1); 1200 print("%lx: word %ld\n", p->pc, (o4<<16)+o3); 1201 return; 1202 } 1203 if(o->size > 0) dis(o1, p->pc); 1204 if(o->size > 2) dis(o2, p->pc+2); 1205 if(o->size > 4) dis(o3, p->pc+4); 1206 if(o->size > 6) dis(o4, p->pc+6); 1207 if(o->size > 8) dis(o5, p->pc+8); 1208 if(o->size > 10) dis(o6, p->pc+10); 1209 if(o->size > 12) dis(o7, p->pc+12); 1210 // if(o->size > 14) dis(o8, p->pc+14); 1211 } 1212 } 1213 1214 static long 1215 thumboprr(int a) 1216 { 1217 switch(a) { 1218 case AMVN: return 0xf<<6; 1219 case ACMP: return 0xa<<6; 1220 case ACMN: return 0xb<<6; 1221 case ATST: return 0x8<<6; 1222 case AADC: return 0x5<<6; 1223 case ASBC: return 0x6<<6; 1224 case AMUL: 1225 case AMULU: return 0xd<<6; 1226 case AAND: return 0x0<<6; 1227 case AEOR: return 0x1<<6; 1228 case AORR: return 0xc<<6; 1229 case ABIC: return 0xe<<6; 1230 case ASRL: return 0x3<<6; 1231 case ASRA: return 0x4<<6; 1232 case ASLL: return 0x2<<6; 1233 } 1234 diag("bad thumbop oprr %d", a); 1235 prasm(curp); 1236 return 0; 1237 } 1238 1239 static long 1240 thumbopirr(int a, int ld) 1241 { 1242 if(ld) 1243 diag("load in thumbopirr"); 1244 switch(a){ 1245 case AMOVW: return 0xc<<11; 1246 case AMOVH: 1247 case AMOVHU: return 0x10<<11; 1248 case AMOVB: 1249 case AMOVBU: return 0xe<<11; 1250 } 1251 return 0; 1252 } 1253 1254 static long 1255 thumboprrr(int a, int ld) 1256 { 1257 if(ld){ 1258 switch(a){ 1259 case AMOVW: return 0x2c<<9; 1260 case AMOVH: return 0x2f<<9; 1261 case AMOVB: return 0x2b<<9; 1262 case AMOVHU: return 0x2d<<9; 1263 case AMOVBU: return 0x2e<<9; 1264 } 1265 } 1266 else{ 1267 switch(a){ 1268 case AMOVW: return 0x28<<9; 1269 case AMOVHU: 1270 case AMOVH: return 0x29<<9; 1271 case AMOVBU: 1272 case AMOVB: return 0x2a<<9; 1273 } 1274 } 1275 diag("bad thumbop oprrr %d", a); 1276 prasm(curp); 1277 return 0; 1278 } 1279 1280 static long 1281 thumbopri(int a) 1282 { 1283 switch(a) { 1284 case ASRL: return 0x1<<11; 1285 case ASRA: return 0x2<<11; 1286 case ASLL: return 0x0<<11; 1287 case AADD: return 0x2<<11; 1288 case ASUB: return 0x3<<11; 1289 case AMOVW: return 0x0<<11; 1290 case ACMP: return 0x1<<11; 1291 } 1292 diag("bad thumbop opri %d", a); 1293 prasm(curp); 1294 return 0; 1295 } 1296 1297 static long 1298 thumbophh(int a) 1299 { 1300 switch(a) { 1301 case AADD: return 0x0<<8; 1302 case AMOVW: return 0x2<<8; 1303 case ACMP: return 0x1<<8; 1304 } 1305 diag("bad thumbop ophh %d", a); 1306 prasm(curp); 1307 return 0; 1308 } 1309 1310 static long 1311 thumbopbra(int a) 1312 { 1313 switch(a) { 1314 case ABEQ: return 0x0<<8; 1315 case ABNE: return 0x1<<8; 1316 case ABCS: return 0x2<<8; 1317 case ABHS: return 0x2<<8; 1318 case ABCC: return 0x3<<8; 1319 case ABLO: return 0x3<<8; 1320 case ABMI: return 0x4<<8; 1321 case ABPL: return 0x5<<8; 1322 case ABVS: return 0x6<<8; 1323 case ABVC: return 0x7<<8; 1324 case ABHI: return 0x8<<8; 1325 case ABLS: return 0x9<<8; 1326 case ABGE: return 0xa<<8; 1327 case ABLT: return 0xb<<8; 1328 case ABGT: return 0xc<<8; 1329 case ABLE: return 0xd<<8; 1330 } 1331 diag("bad thumbop opbra %d", a); 1332 prasm(curp); 1333 return 0; 1334 } 1335 1336 static long 1337 thumbopmv(int a, int ld) 1338 { 1339 switch(a) { 1340 case AMOVW: return (ld ? 0xd : 0xc)<<11; 1341 case AMOVH: 1342 case AMOVHU: return (ld ? 0x11: 0x10)<<11; 1343 case AMOVB: 1344 case AMOVBU: return (ld ? 0xf : 0xe)<<11; 1345 } 1346 diag("bad thumbop opmv %d", a); 1347 prasm(curp); 1348 return 0; 1349 } 1350 1351 static void 1352 lowreg(Prog *p, int r) 1353 { 1354 if(high(r)) 1355 diag("high reg [%P]", p); 1356 } 1357 1358 static void 1359 mult(Prog *p, int n, int m) 1360 { 1361 if(m*(n/m) != n) 1362 diag("%d not M(%d) [%P]", n, m, p); 1363 } 1364 1365 static void 1366 numr(Prog *p, int n, int min, int max) 1367 { 1368 if(n < min || n > max) 1369 diag("%d not in %d-%d [%P]", n, min, max, p); 1370 } 1371 1372 static void 1373 regis(Prog *p, int r, int r1, int r2) 1374 { 1375 if(r != r1 && r != r2) 1376 diag("reg %d not %d or %d [%P]", r, r1, r2, p); 1377 } 1378 1379 void 1380 hputl(int n) 1381 { 1382 cbp[1] = n>>8; 1383 cbp[0] = n; 1384 cbp += 2; 1385 cbc -= 2; 1386 if(cbc <= 0) 1387 cflush(); 1388 } 1389 1390 void 1391 thumbcount() 1392 { 1393 int i, c = 0, t = 0; 1394 1395 for (i = 0; i < OPCNTSZ; i++) 1396 t += opcount[i]; 1397 if(t == 0) 1398 return; 1399 for (i = 0; i < OPCNTSZ; i++){ 1400 c += opcount[i]; 1401 print("%d: %d %d %d%%\n", i, opcount[i], c, (opcount[i]*100+t/2)/t); 1402 } 1403 } 1404 1405 char *op1[] = { "lsl", "lsr", "asr" }; 1406 char *op2[] = { "add", "sub" }; 1407 char *op3[] = { "movw", "cmp", "add", "sub" }; 1408 char *op4[] = { "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", 1409 "tst", "neg", "cmp", "cmpn", "or", "mul", "bitc", "movn" }; 1410 char *op5[] = { "add", "cmp", "movw", "bx" }; 1411 char *op6[] = { "smovw", "smovh", "smovb", "lmovb", "lmovw", "lmovhu", "lmovbu", "lmovh" }; 1412 char *op7[] = { "smovw", "lmovw", "smovb", "lmovbu" }; 1413 char *op8[] = { "smovh", "lmovhu" }; 1414 char *op9[] = { "smovw", "lmovw" }; 1415 char *op10[] = { "push", "pop" }; 1416 char *op11[] = { "stmia", "ldmia" }; 1417 1418 char *cond[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", 1419 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" }; 1420 1421 #define B(h, l) bits(i, h, l) 1422 #define IMM(h, l) B(h, l) 1423 #define REG(h, l) reg(B(h, l)) 1424 #define LHREG(h, l, lh) lhreg(B(h, l), B(lh, lh)) 1425 #define COND(h, l) cond[B(h, l)] 1426 #define OP1(h, l) op1[B(h, l)] 1427 #define OP2(h, l) op2[B(h, l)] 1428 #define OP3(h, l) op3[B(h, l)] 1429 #define OP4(h, l) op4[B(h, l)] 1430 #define OP5(h, l) op5[B(h, l)] 1431 #define OP6(h, l) op6[B(h, l)] 1432 #define OP7(h, l) op7[B(h, l)] 1433 #define OP8(h, l) op8[B(h, l)] 1434 #define OP9(h, l) op9[B(h, l)] 1435 #define OP10(h, l) op10[B(h, l)] 1436 #define OP11(h, l) op11[B(h, l)] 1437 #define SBZ(h, l) if(IMM(h, l) != 0) diag("%x: %x bits %d,%d not zero", pc, i, h, l) 1438 #define SNBZ(h, l) if(IMM(h, l) == 0) diag("%x: %x bits %d,%d zero", pc, i, h, l) 1439 #define SBO(h, l) if(IMM(h, l) != 1) diag("%x: %x bits %d,%d not one", pc, i, h, l) 1440 1441 static int 1442 bits(int i, int h, int l) 1443 { 1444 if(h < l) 1445 diag("h < l in bits"); 1446 return (i&(((1<<(h-l+1))-1)<<l))>>l; 1447 } 1448 1449 static char * 1450 reg(int r) 1451 { 1452 static char s[4][4]; 1453 static int i = 0; 1454 1455 if(r < 0 || r > 7) 1456 diag("register %d out of range", r); 1457 i++; 1458 if(i == 4) 1459 i = 0; 1460 sprint(s[i], "r%d", r); 1461 return s[i]; 1462 } 1463 1464 static char *regnames[] = { "sp", "lr", "pc" }; 1465 1466 static char * 1467 lhreg(int r, int lh) 1468 { 1469 static char s[4][4]; 1470 static int i = 0; 1471 1472 if(lh == 0) 1473 return reg(r); 1474 if(r < 0 || r > 7) 1475 diag("high register %d out of range", r); 1476 i++; 1477 if(i == 4) 1478 i = 0; 1479 if(r >= 5) 1480 sprint(s[i], "%s", regnames[r-5]); 1481 else 1482 sprint(s[i], "r%d", r+8); 1483 return s[i]; 1484 } 1485 1486 static void 1487 illegal(int i, int pc) 1488 { 1489 diag("%x: %x illegal instruction", pc, i); 1490 } 1491 1492 static void 1493 dis(int i, int pc) 1494 { 1495 static int lasto; 1496 int o, l; 1497 char *op; 1498 1499 print("%x: %x: ", pc, i); 1500 if(i&0xffff0000) 1501 illegal(i, pc); 1502 o = B(15, 13); 1503 switch(o){ 1504 case 0: 1505 o = B(12, 11); 1506 switch(o){ 1507 case 0: 1508 case 1: 1509 case 2: 1510 print("%s %d, %s, %s\n", OP1(12, 11), IMM(10, 6), REG(5, 3), REG(2, 0)); 1511 return; 1512 case 3: 1513 if(B(10, 10) == 0) 1514 print("%s %s, %s, %s\n", OP2(9, 9), REG(8, 6), REG(5, 3), REG(2, 0)); 1515 else 1516 print("%s %d, %s, %s\n", OP2(9, 9), IMM(8, 6), REG(5, 3), REG(2, 0)); 1517 return; 1518 } 1519 case 1: 1520 print("%s %d, %s\n", OP3(12, 11), IMM(7, 0), REG(10, 8)); 1521 return; 1522 case 2: 1523 o = B(12, 10); 1524 if(o == 0){ 1525 print("%s %s, %s\n", OP4(9, 6), REG(5, 3), REG(2, 0)); 1526 return; 1527 } 1528 if(o == 1){ 1529 o = B(9, 8); 1530 if(o == 3){ 1531 SBZ(7, 7); 1532 SBZ(2, 0); 1533 print("%s %s\n", OP5(9, 8), LHREG(5, 3, 6)); 1534 return; 1535 } 1536 SNBZ(7, 6); 1537 print("%s %s, %s\n", OP5(9, 8), LHREG(5, 3, 6), LHREG(2, 0, 7)); 1538 return; 1539 } 1540 if(o == 2 || o == 3){ 1541 print("movw %d(pc)[%x], %s\n", 4*IMM(7, 0), 4*IMM(7, 0)+pc+4, REG(10, 8)); 1542 return; 1543 } 1544 op = OP6(11, 9); 1545 if(*op == 'l') 1546 print("%s [%s, %s], %s\n", op+1, REG(8, 6), REG(5, 3), REG(2, 0)); 1547 else 1548 print("%s %s, [%s, %s]\n", op+1, REG(2, 0), REG(8, 6), REG(5, 3)); 1549 return; 1550 case 3: 1551 op = OP7(12, 11); 1552 if(B(12, 11) == 0 || B(12,11) == 1) 1553 l = 4; 1554 else 1555 l = 1; 1556 if(*op == 'l') 1557 print("%s %d(%s), %s\n", op+1, l*IMM(10, 6), REG(5, 3), REG(2, 0)); 1558 else 1559 print("%s %s, %d(%s)\n", op+1, REG(2, 0), l*IMM(10, 6), REG(5, 3)); 1560 return; 1561 case 4: 1562 if(B(12, 12) == 0){ 1563 op = OP8(11, 11); 1564 if(*op == 'l') 1565 print("%s %d(%s), %s\n", op+1, 2*IMM(10, 6), REG(5, 3), REG(2, 0)); 1566 else 1567 print("%s %s, %d(%s)\n", op+1, REG(2, 0), 2*IMM(10, 6), REG(5, 3)); 1568 return; 1569 } 1570 op = OP9(11, 11); 1571 if(*op == 'l') 1572 print("%s %d(sp), %s\n", op+1, 4*IMM(7, 0), REG(10, 8)); 1573 else 1574 print("%s %s, %d(sp)\n", op+1, REG(10, 8), 4*IMM(7, 0)); 1575 return; 1576 case 5: 1577 if(B(12, 12) == 0){ 1578 if(B(11, 11) == 0) 1579 print("add %d, pc, %s\n", 4*IMM(7, 0), REG(10, 8)); 1580 else 1581 print("add %d, sp, %s\n", 4*IMM(7, 0), REG(10, 8)); 1582 return; 1583 } 1584 if(B(11, 8) == 0){ 1585 print("%s %d, sp\n", OP2(7, 7), 4*IMM(6, 0)); 1586 return; 1587 } 1588 SBO(10, 10); 1589 SBZ(9, 9); 1590 if(B(8, 8) == 0) 1591 print("%s sp, %d\n", OP10(11, 11), IMM(7, 0)); 1592 else 1593 print("%s sp, %d|15\n", OP10(11, 11), IMM(7, 0)); 1594 return; 1595 case 6: 1596 if(B(12, 12) == 0){ 1597 print("%s %s, %d\n", OP11(11, 11), REG(10, 8), IMM(7, 0)); 1598 return; 1599 } 1600 if(B(11, 8) == 0xf){ 1601 print("swi %d\n", IMM(7, 0)); 1602 return; 1603 } 1604 o = IMM(7, 0); 1605 if(o&0x80) 1606 o |= 0xffffff00; 1607 o = pc+4+(o<<1); 1608 print("b%s %x\n", COND(11, 8), o); 1609 return; 1610 case 7: 1611 o = B(12, 11); 1612 switch(o){ 1613 case 0: 1614 o = IMM(10, 0); 1615 if(o&0x400) 1616 o |= 0xfffff800; 1617 o = pc+4+(o<<1); 1618 print("b %x\n", o); 1619 return; 1620 case 1: 1621 illegal(i, pc); 1622 return; 1623 case 2: 1624 lasto = IMM(10, 0); 1625 print("bl\n"); 1626 return; 1627 case 3: 1628 if(lasto&0x400) 1629 lasto |= 0xfffff800; 1630 o = IMM(10, 0); 1631 o = (pc-2)+4+(o<<1)+(lasto<<12); 1632 print("bl %x\n", o); 1633 return; 1634 } 1635 } 1636 } 1637