1 #include "l.h"
2
3 long OFFSET;
4
5 xlong
entryvalue(void)6 entryvalue(void)
7 {
8 char *a;
9 Sym *s;
10
11 a = INITENTRY;
12 if(*a >= '0' && *a <= '9')
13 return atolwhex(a);
14 s = lookup(a, 0);
15 if(s->type == 0)
16 return INITTEXT;
17 if(s->type != STEXT && s->type != SLEAF)
18 diag("entry not text: %s", s->name);
19 return s->value + INITTEXT;
20 }
21
22 void
asmb(void)23 asmb(void)
24 {
25 Prog *p;
26 long t, etext;
27 Optab *o;
28
29 if(debug['v'])
30 Bprint(&bso, "%5.2f asm\n", cputime());
31 Bflush(&bso);
32 OFFSET = HEADR;
33 seek(cout, OFFSET, 0);
34 pc = 0;
35 for(p = firstp; p != P; p = p->link) {
36 if(p->as == ATEXT) {
37 /* align on word boundary */
38 if(!debug['c'] && (pc & 2) != 0){
39 nopalign.pc = pc;
40 pc += asmout(&nopalign, oplook(&nopalign), 0);
41 }
42 curtext = p;
43 autosize = p->to.offset + ptrsize;
44 }
45 if(p->pc != pc) {
46 diag("phase error %lux sb %lux",
47 p->pc, pc);
48 if(!debug['a'])
49 prasm(curp);
50 pc = p->pc;
51 }
52 curp = p;
53 o = oplook(p); /* could probably avoid this call */
54 pc += asmout(p, o, 0);
55 }
56 if(debug['a'])
57 Bprint(&bso, "\n");
58 Bflush(&bso);
59 cflush();
60
61 etext = textsize;
62 for(t = pc; t < etext; t += sizeof(buf)-100) {
63 if(etext-t > sizeof(buf)-100)
64 datblk(t, sizeof(buf)-100, 1);
65 else
66 datblk(t, etext-t, 1);
67 }
68
69 Bflush(&bso);
70 cflush();
71
72 curtext = P;
73 switch(HEADTYPE) {
74 case 0:
75 case 4:
76 OFFSET = rnd(HEADR+textsize, 4096);
77 seek(cout, OFFSET, 0);
78 break;
79 case 1:
80 case 2:
81 case 3:
82 case 5:
83 case 6:
84 OFFSET = HEADR+textsize;
85 seek(cout, OFFSET, 0);
86 break;
87 }
88 for(t = 0; t < datsize; t += sizeof(buf)-100) {
89 if(datsize-t > sizeof(buf)-100)
90 datblk(t, sizeof(buf)-100, 0);
91 else
92 datblk(t, datsize-t, 0);
93 }
94
95 symsize = 0;
96 lcsize = 0;
97 if(!debug['s']) {
98 if(debug['v'])
99 Bprint(&bso, "%5.2f sym\n", cputime());
100 Bflush(&bso);
101 switch(HEADTYPE) {
102 case 0:
103 case 4:
104 OFFSET = rnd(HEADR+textsize, 4096)+datsize;
105 seek(cout, OFFSET, 0);
106 break;
107 case 3:
108 case 2:
109 case 1:
110 case 5:
111 case 6:
112 OFFSET = HEADR+textsize+datsize;
113 seek(cout, OFFSET, 0);
114 break;
115 }
116 if(!debug['s'])
117 asmsym();
118 if(debug['v'])
119 Bprint(&bso, "%5.2f pc\n", cputime());
120 Bflush(&bso);
121 if(!debug['s'])
122 asmlc();
123 cflush();
124 }
125
126 if(debug['v'])
127 Bprint(&bso, "%5.2f header\n", cputime());
128 Bflush(&bso);
129 OFFSET = 0;
130 seek(cout, OFFSET, 0);
131 switch(HEADTYPE) {
132 case 1:
133 break;
134 case 2:
135 /* XXX expanded header needed? */
136 t = thechar == 'j' ? 30 : 29;
137 lput(((((4*t)+0)*t)+7)); /* magic */
138 lput(textsize); /* sizes */
139 lput(datsize);
140 lput(bsssize);
141 lput(symsize); /* nsyms */
142 lput(entryvalue()); /* va of entry */
143 lput(0L);
144 lput(lcsize);
145 break;
146 case 5:
147 if(thechar == 'j')
148 elf64(243, ELFDATA2LSB, 0, nil); /* 243 is RISCV */
149 else
150 elf32(243, ELFDATA2LSB, 0, nil);
151 }
152 cflush();
153 }
154
155 void
strnput(char * s,int n)156 strnput(char *s, int n)
157 {
158 for(; *s; s++){
159 cput(*s);
160 n--;
161 }
162 for(; n > 0; n--)
163 cput(0);
164 }
165
166 void
cput(int c)167 cput(int c)
168 {
169 cbp[0] = c;
170 cbp++;
171 cbc--;
172 if(cbc <= 0)
173 cflush();
174 }
175
176 void
wput(long l)177 wput(long l)
178 {
179
180 cbp[0] = l>>8;
181 cbp[1] = l;
182 cbp += 2;
183 cbc -= 2;
184 if(cbc <= 0)
185 cflush();
186 }
187
188 void
wputl(long l)189 wputl(long l)
190 {
191
192 cbp[0] = l;
193 cbp[1] = l>>8;
194 cbp += 2;
195 cbc -= 2;
196 if(cbc <= 0)
197 cflush();
198 }
199
200 void
lput(long l)201 lput(long l)
202 {
203
204 cbp[0] = l>>24;
205 cbp[1] = l>>16;
206 cbp[2] = l>>8;
207 cbp[3] = l;
208 cbp += 4;
209 cbc -= 4;
210 if(cbc <= 0)
211 cflush();
212 }
213
214 void
lputl(long l)215 lputl(long l)
216 {
217
218 cbp[3] = l>>24;
219 cbp[2] = l>>16;
220 cbp[1] = l>>8;
221 cbp[0] = l;
222 cbp += 4;
223 cbc -= 4;
224 if(cbc <= 0)
225 cflush();
226 }
227
228 void
llput(vlong v)229 llput(vlong v)
230 {
231 lput(v>>32);
232 lput(v);
233 }
234
235 void
llputl(vlong v)236 llputl(vlong v)
237 {
238 lputl(v);
239 lputl(v>>32);
240 }
241
242 void
cflush(void)243 cflush(void)
244 {
245 int n;
246
247 n = sizeof(buf.cbuf) - cbc;
248 if(n)
249 write(cout, buf.cbuf, n);
250 cbp = buf.cbuf;
251 cbc = sizeof(buf.cbuf);
252 }
253
254 void
nopstat(char * f,Count * c)255 nopstat(char *f, Count *c)
256 {
257 if(c->outof)
258 Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
259 c->outof - c->count, c->outof,
260 (double)(c->outof - c->count)/c->outof);
261 }
262
263 void
asmsym(void)264 asmsym(void)
265 {
266 Prog *p;
267 Auto *a;
268 Sym *s;
269 int h;
270
271 s = lookup("etext", 0);
272 if(s->type == STEXT)
273 putsymb(s->name, 'T', s->value+INITTEXT, s->version);
274
275 for(h=0; h<NHASH; h++)
276 for(s=hash[h]; s!=S; s=s->link)
277 switch(s->type) {
278 case SCONST:
279 putsymb(s->name, 'D', s->value, s->version);
280 continue;
281
282 case SSTRING:
283 putsymb(s->name, 'T', s->value, s->version);
284 continue;
285
286 case SDATA:
287 putsymb(s->name, 'D', s->value+INITDAT, s->version);
288 continue;
289
290 case SBSS:
291 putsymb(s->name, 'B', s->value+INITDAT, s->version);
292 continue;
293
294 case SFILE:
295 putsymb(s->name, 'f', s->value, s->version);
296 continue;
297 }
298
299 for(p=textp; p!=P; p=p->cond) {
300 s = p->from.sym;
301 if(s->type != STEXT && s->type != SLEAF)
302 continue;
303
304 /* filenames first */
305 for(a=p->to.autom; a; a=a->link)
306 if(a->type == D_FILE)
307 putsymb(a->asym->name, 'z', a->aoffset, 0);
308 else
309 if(a->type == D_FILE1)
310 putsymb(a->asym->name, 'Z', a->aoffset, 0);
311
312 if(s->type == STEXT)
313 putsymb(s->name, 'T', s->value+INITTEXT, s->version);
314 else
315 putsymb(s->name, 'L', s->value+INITTEXT, s->version);
316
317 /* frame, auto and param after */
318 putsymb(".frame", 'm', p->to.offset+ptrsize, 0);
319 for(a=p->to.autom; a; a=a->link)
320 if(a->type == D_AUTO)
321 putsymb(a->asym->name, 'a', -a->aoffset, 0);
322 else
323 if(a->type == D_PARAM)
324 putsymb(a->asym->name, 'p', a->aoffset, 0);
325 }
326 if(debug['v'] || debug['n'])
327 Bprint(&bso, "symsize = %lud\n", symsize);
328 Bflush(&bso);
329 }
330
331 void
putsymb(char * s,int t,vlong v,int ver)332 putsymb(char *s, int t, vlong v, int ver)
333 {
334 int i, f, l;
335
336 if(t == 'f')
337 s++;
338 if(thechar == 'j'){
339 l = 8;
340 llput(v);
341 }else{
342 l = 4;
343 lput(v);
344 }
345 if(ver)
346 t += 'a' - 'A';
347 cput(t+0x80); /* 0x80 is variable length */
348
349 if(t == 'Z' || t == 'z') {
350 cput(s[0]);
351 for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
352 cput(s[i]);
353 cput(s[i+1]);
354 }
355 cput(0);
356 cput(0);
357 i++;
358 }
359 else {
360 for(i=0; s[i]; i++)
361 cput(s[i]);
362 cput(0);
363 }
364 symsize += l + 1 + i + 1;
365
366 if(debug['n']) {
367 if(t == 'z' || t == 'Z') {
368 Bprint(&bso, "%c %.8llux ", t, v);
369 for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
370 f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
371 Bprint(&bso, "/%x", f);
372 }
373 Bprint(&bso, "\n");
374 return;
375 }
376 if(ver)
377 Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver);
378 else
379 Bprint(&bso, "%c %.8llux %s\n", t, v, s);
380 }
381 }
382
383 #define MINLC 2
384 void
asmlc(void)385 asmlc(void)
386 {
387 long oldpc, oldlc;
388 Prog *p;
389 long v, s;
390
391 oldpc = 0;
392 oldlc = 0;
393 for(p = firstp; p != P; p = p->link) {
394 if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
395 if(p->as == ATEXT)
396 curtext = p;
397 if(debug['L'])
398 Bprint(&bso, "%6lux %P\n",
399 p->pc, p);
400 continue;
401 }
402 if(debug['L'])
403 Bprint(&bso, "\t\t%6ld", lcsize);
404 v = (p->pc - oldpc) / MINLC;
405 while(v) {
406 s = 127;
407 if(v < 127)
408 s = v;
409 cput(s+128); /* 129-255 +pc */
410 if(debug['L'])
411 Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
412 v -= s;
413 lcsize++;
414 }
415 s = p->line - oldlc;
416 oldlc = p->line;
417 oldpc = p->pc + MINLC;
418 if(s > 64 || s < -64) {
419 cput(0); /* 0 vv +lc */
420 cput(s>>24);
421 cput(s>>16);
422 cput(s>>8);
423 cput(s);
424 if(debug['L']) {
425 if(s > 0)
426 Bprint(&bso, " lc+%ld(%d,%ld)\n",
427 s, 0, s);
428 else
429 Bprint(&bso, " lc%ld(%d,%ld)\n",
430 s, 0, s);
431 Bprint(&bso, "%6lux %P\n",
432 p->pc, p);
433 }
434 lcsize += 5;
435 continue;
436 }
437 if(s > 0) {
438 cput(0+s); /* 1-64 +lc */
439 if(debug['L']) {
440 Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
441 Bprint(&bso, "%6lux %P\n",
442 p->pc, p);
443 }
444 } else {
445 cput(64-s); /* 65-128 -lc */
446 if(debug['L']) {
447 Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
448 Bprint(&bso, "%6lux %P\n",
449 p->pc, p);
450 }
451 }
452 lcsize++;
453 }
454 while(lcsize & 1) {
455 s = 129;
456 cput(s);
457 lcsize++;
458 }
459 if(debug['v'] || debug['L'])
460 Bprint(&bso, "lcsize = %ld\n", lcsize);
461 Bflush(&bso);
462 }
463
464 void
datblk(long s,long n,int str)465 datblk(long s, long n, int str)
466 {
467 Prog *p;
468 char *cast;
469 vlong d;
470 long l, fl, j;
471 int i, c;
472
473 memset(buf.dbuf, 0, n+100);
474 for(p = datap; p != P; p = p->link) {
475 curp = p;
476 if(str != (p->from.sym->type == SSTRING))
477 continue;
478 l = p->from.sym->value + p->from.offset - s;
479 c = p->reg;
480 i = 0;
481 if(l < 0) {
482 if(l+c <= 0)
483 continue;
484 while(l < 0) {
485 l++;
486 i++;
487 }
488 }
489 if(l >= n)
490 continue;
491 if(p->as != AINIT && p->as != ADYNT) {
492 for(j=l+(c-i)-1; j>=l; j--)
493 if(buf.dbuf[j]) {
494 print("%P\n", p);
495 diag("multiple initialization");
496 break;
497 }
498 }
499 switch(p->to.type) {
500 default:
501 diag("unknown mode in initialization\n%P", p);
502 break;
503
504 case D_FCONST:
505 switch(c) {
506 default:
507 case 4:
508 fl = ieeedtof(p->to.ieee);
509 cast = (char*)&fl;
510 for(; i<c; i++) {
511 buf.dbuf[l] = cast[fnuxi8[i]];
512 l++;
513 }
514 break;
515 case 8:
516 cast = (char*)p->to.ieee;
517 for(; i<c; i++) {
518 buf.dbuf[l] = cast[fnuxi8[i]];
519 l++;
520 }
521 break;
522 }
523 break;
524
525 case D_SCONST:
526 for(; i<c; i++) {
527 buf.dbuf[l] = p->to.sval[i];
528 l++;
529 }
530 break;
531
532 case D_VCONST:
533 d = *p->to.vval;
534 goto dconst;
535
536 case D_CONST:
537 d = p->to.offset;
538 dconst:
539 if(p->to.sym) {
540 switch(p->to.sym->type) {
541 case STEXT:
542 case SLEAF:
543 case SSTRING:
544 d += (p->to.sym->value + INITTEXT);
545 break;
546 case SDATA:
547 case SBSS:
548 d += (p->to.sym->value + INITDAT);
549 break;
550 }
551 }
552 cast = (char*)&d;
553 switch(c) {
554 default:
555 diag("bad nuxi %d %d\n%P", c, i, curp);
556 break;
557 case 1:
558 for(; i<c; i++) {
559 buf.dbuf[l] = cast[inuxi1[i]];
560 l++;
561 }
562 break;
563 case 2:
564 for(; i<c; i++) {
565 buf.dbuf[l] = cast[inuxi2[i]];
566 l++;
567 }
568 break;
569 case 4:
570 for(; i<c; i++) {
571 buf.dbuf[l] = cast[inuxi4[i]];
572 l++;
573 }
574 break;
575 case 8:
576 for(; i<c; i++) {
577 buf.dbuf[l] = cast[inuxi8[i]];
578 l++;
579 }
580 break;
581 }
582 break;
583 }
584 if(debug['d'] && i == c) {
585 Bprint(&bso, "%.8llux", l+s+INITDAT-c);
586 for(j = -c; j<0; j++)
587 Bprint(&bso, " %.2ux", ((uchar*)buf.dbuf)[l + j]);
588 Bprint(&bso, "\t%P\n", curp);
589 }
590 }
591 write(cout, buf.dbuf, n);
592 }
593
594 #define R(r) ((r)&0x1F)
595 #define OPX (0x3 | o->op<<2)
596 #define OPF (OPX | o->func3<<12)
597 #define OP_R(rs1,rs2,rd)\
598 (OPF | rd<<7 | R(rs1)<<15 | R(rs2)<<20 | o->param<<25)
599 #define OP_RF(rs1,rs2,rd,rm)\
600 (OPX | rm<<12 | rd<<7 | R(rs1)<<15 | R(rs2)<<20 | o->param<<25)
601 #define OP_RO(rs1,rs2,rd)\
602 (0x3 | OOP<<2 | o->func3<<12 | rd<<7 | R(rs1)<<15 | R(rs2)<<20)
603 #define OP_ADD(rs1,rs2,rd)\
604 (0x3 | OOP<<2 | rd<<7 | R(rs1)<<15 | R(rs2)<<20)
605 #define OP_I(rs1,rd,imm)\
606 (OPF | rd<<7 | R(rs1)<<15 | (imm)<<20)
607 #define OP_FI(func3,rs1,rd,imm)\
608 (OPX | func3<<12 | rd<<7 | R(rs1)<<15 | (imm)<<20)
609 #define OP_S(rs1,rs2,imm)\
610 (OPF | (imm&0x1F)<<7 | R(rs1)<<15 | R(rs2)<<20 | (imm>>5)<<25)
611 #define OP_B(rs1,rs2,imm)\
612 (OPF | R(rs1)<<15 | R(rs2)<<20 | (imm&0x800)>>4 | (imm&0x1E)<<7 | \
613 (imm&0x7E0)<<20 | (imm&0x1000)<<19)
614 #define OP_U(rd,imm)\
615 (0x3 | OLUI<<2 | rd<<7 | (imm&0xFFFFF000))
616 #define OP_UP(rd,imm)\
617 (0x3 | OAUIPC<<2 | rd<<7 | (imm&0xFFFFF000))
618 #define OP_J(rd,imm)\
619 (OPX | rd<<7 | (imm&0xff000) | (imm&0x800)<<9 | (imm&0x7FE)<<20 | (imm&0x100000)<<11)
620
621 /*
622 * aflag: 0 - assemble to object file
623 * 1 - return assembled instruction
624 * 2 - first pass, return length of assembled instruction
625 * 3 - later pass, return length of assembled instruction
626 */
627 int
asmout(Prog * p,Optab * o,int aflag)628 asmout(Prog *p, Optab *o, int aflag)
629 {
630 vlong vv;
631 long o1, o2, o3, v;
632 int r;
633
634 o1 = 0;
635 o2 = 0;
636 o3 = 0;
637 r = p->reg;
638 if(r == NREG) switch(p->as){
639 case AMOVF:
640 case AMOVD:
641 if(p->from.type == D_FREG && p->to.type == D_FREG)
642 r = p->from.reg;
643 break;
644 case AMOV:
645 case AJMP:
646 r = REGZERO;
647 break;
648 case AJAL:
649 r = REGLINK;
650 break;
651 default:
652 r = p->to.reg;
653 break;
654 }
655 if(!debug['c'] && o->ctype){
656 o1 = asmcompressed(p, o, r, aflag == 2);
657 if(o1 != 0){
658 switch(aflag){
659 case 1:
660 return o1;
661 case 2:
662 case 3:
663 return 2;
664 }
665 if(debug['a']){
666 v = p->pc + INITTEXT;
667 Bprint(&bso, " %.8lux: %.4lux \t%P\n", v, o1, p);
668 }
669 wputl(o1);
670 return 2;
671 }
672 }
673 if(aflag >= 2)
674 return o->size;
675 switch(o->type) {
676 default:
677 diag("unknown type %d", o->type);
678 if(!debug['a'])
679 prasm(p);
680 break;
681
682 case 0: /* add S,[R,]D */
683 o1 = OP_R(r, p->from.reg, p->to.reg);
684 break;
685
686 case 1: /* slli $I,[R,]D */
687 v = p->from.offset & 0x3F;
688 v |= (o->param<<5);
689 o1 = OP_I(r, p->to.reg, v);
690 break;
691
692 case 2: /* addi $I,[R,]D */
693 v = p->from.offset;
694 if(v < -BIG || v >= BIG)
695 diag("imm out of range\n%P", p);
696 o1 = OP_I(r, p->to.reg, v);
697 break;
698
699 case 3: /* beq S,[R,]L */
700 if(r == NREG)
701 r = REGZERO;
702 if(p->cond == P)
703 v = 0;
704 else
705 v = (p->cond->pc - pc);
706 if(v < -0x1000 || v >= 0x1000)
707 diag("branch out of range\n%P", p);
708 o1 = OP_B(r, p->from.reg, v);
709 break;
710
711 case 4: /* jal [D,]L */
712 if(p->cond == P)
713 v = 0;
714 else
715 v = (p->cond->pc - pc);
716 if(v < -0x100000 || v >= 0x100000)
717 diag("jump out of range\n%P", p);
718 o1 = OP_J(r, v);
719 break;
720
721 case 5: /* jalr [D,]I(S) */
722 v = regoff(&p->to);
723 if(v < -BIG || v >= BIG)
724 diag("imm out of range\n%P", p);
725 o1 = OP_I(classreg(&p->to), r, v);
726 break;
727
728 case 6: /* sb R,I(S) */
729 v = regoff(&p->to);
730 r = classreg(&p->to);
731 if(v < -BIG || v >= BIG)
732 diag("imm out of range\n%P", p);
733 o1 = OP_S(r, p->from.reg, v);
734 break;
735
736 case 7: /* lb I(S),D */
737 v = regoff(&p->from);
738 r = classreg(&p->from);
739 if(v < -BIG || v >= BIG)
740 diag("imm out of range\n%P", p);
741 o1 = OP_I(r, p->to.reg, v);
742 break;
743
744 case 8: /* lui I,D */
745 v = p->from.offset;
746 o1 = OP_U(p->to.reg, v);
747 break;
748
749 case 9: /* lui I1,D; addi I0,D */
750 v = regoff(&p->from);
751 if(thechar == 'j' && v >= 0x7ffff800){
752 /* awkward edge case */
753 o1 = OP_U(p->to.reg, -v);
754 v &= 0xFFF;
755 o2 = OP_FI(4, p->to.reg, p->to.reg, v); /* xori */
756 break;
757 }
758 if(v & 0x800)
759 v += 0x1000;
760 o1 = OP_U(p->to.reg, v);
761 v &= 0xFFF;
762 o2 = OP_I(p->to.reg, p->to.reg, v);
763 break;
764
765 case 10: /* sign extend */
766 if(p->as == AMOVBU) {
767 o1 = OP_I(p->from.reg, p->to.reg, o->param);
768 break;
769 }
770 v = o->param;
771 if(thechar == 'j')
772 v += 32;
773 o1 = OP_FI(1, p->from.reg, p->to.reg, v & 0x3F); /* slli */
774 o2 = OP_I(p->to.reg, p->to.reg, v); /* srli or srai */
775 break;
776
777 case 11: /* addi $I,R,D */
778 v = regoff(&p->from);
779 if(v < -BIG || v >= BIG)
780 diag("imm out of range\n%P", p);
781 o1 = OP_I(classreg(&p->from), p->to.reg, v);
782 break;
783
784 case 12: /* mov r,lext => lui/auipc I1,T; sb r,I0(T) */
785 v = regoff(&p->to);
786 if(thechar == 'j'){
787 vv = v + INITDAT + BIG - INITTEXT - pc;
788 v = (long)vv;
789 if(v != vv || (v&~0x7FF) == 0x7FFFF800)
790 diag("address out of range\n%P", p);
791 }else
792 v += INITDAT + BIG;
793 if(v & 0x800)
794 v += 0x1000;
795 o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v);
796 v &= 0xFFF;
797 o2 = OP_S(REGTMP, p->from.reg, v);
798 break;
799
800 case 13: /* mov lext, r => lui/auipc I1,T; lb r,I0(T) */
801 v = regoff(&p->from);
802 if(thechar == 'j'){
803 vv = v + INITDAT + BIG - INITTEXT - pc;
804 v = (long)vv;
805 if(v != vv || (v&~0x7FF) == 0x7FFFF800)
806 diag("address out of range\n%P", p);
807 }else
808 v += INITDAT + BIG;
809 if(v & 0x800)
810 v += 0x1000;
811 o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v);
812 v &= 0xFFF;
813 o2 = OP_I(REGTMP, p->to.reg, v);
814 break;
815
816 case 14: /* op $lcon,[r,]d => lui L1,T; addi $L0,T,T; op T,r,d */
817 v = regoff(&p->from);
818 if(p->as == AMOVW || p->as == AMOV)
819 r = classreg(&p->from);
820 if(thechar == 'j' && v >= 0x7ffff800){
821 /* awkward edge case */
822 o1 = OP_U(p->to.reg, -v);
823 v &= 0xFFF;
824 o2 = OP_FI(4, p->to.reg, p->to.reg, v); /* xori */
825 }else{
826 if(v & 0x800)
827 v += 0x1000;
828 o1 = OP_U(REGTMP, v);
829 v &= 0xFFF;
830 o2 = OP_FI(0, REGTMP, REGTMP, v); /* addi */
831 }
832 o3 = OP_RO(r, REGTMP, p->to.reg);
833 break;
834
835 case 15: /* mov r,L(s) => lui L1,T; add s,T,T; sb r,L0(T) */
836 v = regoff(&p->to);
837 r = classreg(&p->to);
838 if(v & 0x800)
839 v += 0x1000;
840 o1 = OP_U(REGTMP, v);
841 v &= 0xFFF;
842 o2 = OP_ADD(r, REGTMP, REGTMP);
843 o3 = OP_S(REGTMP, p->from.reg, v);
844 break;
845
846 case 16: /* mov L(s),r => lui L1,T; add s,T,T; lb r,L0(T) */
847 v = regoff(&p->from);
848 r = classreg(&p->from);
849 if(v & 0x800)
850 v += 0x1000;
851 o1 = OP_U(REGTMP, v);
852 v &= 0xFFF;
853 o2 = OP_ADD(r, REGTMP, REGTMP);
854 o3 = OP_I(REGTMP, p->to.reg, v);
855 break;
856
857 case 17: /* fcvt S,D */
858 v = 7; /* dynamic rounding mode */
859 if(o->a3 == C_REG) /* convert to int? */
860 v = 1; /* round towards zero */
861 o1 = OP_RF(p->from.reg, o->func3, p->to.reg, v);
862 break;
863
864 case 18: /* lui L1, T; jal [r,]L0(T) */
865 if(p->cond == P)
866 v = 0;
867 else
868 v = p->cond->pc;
869 if(thechar == 'j'){
870 vv = v + INITTEXT;
871 v = (long)vv;
872 if(v != vv || (v&~0x7FF) == 0x7FFFF800)
873 diag("branch out of range\n%P", p);
874 }else
875 v += INITTEXT;
876 if(v & 0x800)
877 v += 0x1000;
878 o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v);
879 v &= 0xFFF;
880 o2 = OP_I(REGTMP, r, v);
881 break;
882
883 case 19: /* addiw $0, rs, rd */
884 v = 0;
885 o1 = OP_I(p->from.reg, p->to.reg, v);
886 break;
887
888 case 20: /* lui/auipc I1,D; addi I0; D */
889 if(thechar == 'j'){
890 vv = regoff(&p->from) + instoffx - (pc + INITTEXT);
891 v = (long)vv;
892 if(v != vv || (v&~0x7FF) == 0x7FFFF800)
893 diag("address %llux out of range\n%P", regoff(&p->from) + instoffx, p);
894 }else{
895 v = regoff(&p->from) + instoffx;
896 }
897 if(v & 0x800)
898 v += 0x1000;
899 o1 = thechar == 'j' ? OP_UP(p->to.reg, v) : OP_U(p->to.reg, v);
900 v &= 0xFFF;
901 o2 = OP_I(p->to.reg, p->to.reg, v);
902 break;
903
904 case 21: /* lui I,D; s[lr]ai N,D */
905 vv = *p->from.vval;
906 v = vconshift(vv);
907 if(v < 0)
908 diag("64 bit constant error:\n%P", p);
909 if(v < 12)
910 vv <<= 12 - v;
911 else
912 vv >>= v - 12;
913 o1 = OP_U(p->to.reg, (long)vv);
914 if (v > 12)
915 o2 = OP_FI(1, p->to.reg, p->to.reg, v - 12); /* slli */
916 else
917 o2 = OP_I(p->to.reg, p->to.reg, 12 - v); /* srai */
918 break;
919
920 case 22: /* CSRRx C, rs, rd */
921 v = p->from.offset & 0xFFF;
922 o1 = OP_I(p->reg, p->to.reg, v);
923 break;
924
925 case 24: /* SYS */
926 v = p->to.offset & 0xFFF;
927 o1 = OP_I(0, 0, v);
928 break;
929
930 case 25: /* word $x */
931 o1 = regoff(&p->to);
932 break;
933
934 case 26: /* pseudo ops */
935 break;
936 }
937 if(aflag)
938 return o1;
939 v = p->pc + INITTEXT;
940 switch(o->size) {
941 default:
942 if(debug['a'])
943 Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
944 break;
945 case 4:
946 if(debug['a'])
947 Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
948 lputl(o1);
949 break;
950 case 8:
951 if(debug['a'])
952 Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
953 lputl(o1);
954 lputl(o2);
955 break;
956 case 12:
957 if(debug['a'])
958 Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
959 lputl(o1);
960 lputl(o2);
961 lputl(o3);
962 break;
963 }
964 return o->size;
965 }
966
967