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
immbuildcon(int c,Prog * p)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
immoreg(int off,Prog * p)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
immacon(int off,Prog * p,int t1,int t2)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
immauto(int off,Prog * p)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
immsmall(int off,Prog * p,int t1,int t2,int t3)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
immcon(int off,Prog * p)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
thumbaclass(Adr * a,Prog * p)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
brextra(Prog * p)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
mv(Prog * p,int r,int off)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
mvcon(Prog * p,int r,int c,long * o1,long * o2)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
mvlh(int rs,int rd)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
thumbbuildop()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
thumbasmout(Prog * p,Optab * o)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
thumboprr(int a)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
thumbopirr(int a,int ld)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
thumboprrr(int a,int ld)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
thumbopri(int a)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
thumbophh(int a)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
thumbopbra(int a)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
thumbopmv(int a,int ld)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
lowreg(Prog * p,int r)1352 lowreg(Prog *p, int r)
1353 {
1354 if(high(r))
1355 diag("high reg [%P]", p);
1356 }
1357
1358 static void
mult(Prog * p,int n,int m)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
numr(Prog * p,int n,int min,int max)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
regis(Prog * p,int r,int r1,int r2)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
hputl(int n)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
thumbcount()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
bits(int i,int h,int l)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 *
reg(int r)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 *
lhreg(int r,int lh)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
illegal(int i,int pc)1487 illegal(int i, int pc)
1488 {
1489 diag("%x: %x illegal instruction", pc, i);
1490 }
1491
1492 static void
dis(int i,int pc)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