xref: /plan9-contrib/sys/src/cmd/5l/asm.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
1 #include	"l.h"
2 
3 long	OFFSET;
4 
5 static Prog *PP;
6 
7 long
8 entryvalue(void)
9 {
10 	char *a;
11 	Sym *s;
12 
13 	a = INITENTRY;
14 	if(*a >= '0' && *a <= '9')
15 		return atolwhex(a);
16 	s = lookup(a, 0);
17 	if(s->type == 0)
18 		return INITTEXT;
19 	switch(s->type) {
20 	case STEXT:
21 	case SLEAF:
22 		break;
23 	case SDATA:
24 		if(dlm)
25 			return s->value+INITDAT;
26 	default:
27 		diag("entry not text: %s", s->name);
28 	}
29 	return s->value;
30 }
31 
32 void
33 asmb(void)
34 {
35 	Prog *p;
36 	long t, etext;
37 	Optab *o;
38 
39 	if(debug['v'])
40 		Bprint(&bso, "%5.2f asm\n", cputime());
41 	Bflush(&bso);
42 	OFFSET = HEADR;
43 	seek(cout, OFFSET, 0);
44 	pc = INITTEXT;
45 	for(p = firstp; p != P; p = p->link) {
46 		if(p->as == ATEXT) {
47 			curtext = p;
48 			autosize = p->to.offset + 4;
49 		}
50 		if(p->pc != pc) {
51 			diag("phase error %lux sb %lux",
52 				p->pc, pc);
53 			if(!debug['a'])
54 				prasm(curp);
55 			pc = p->pc;
56 		}
57 		curp = p;
58 		o = oplook(p);	/* could probably avoid this call */
59 		asmout(p, o);
60 		pc += o->size;
61 	}
62 
63 	if(debug['a'])
64 		Bprint(&bso, "\n");
65 	Bflush(&bso);
66 	cflush();
67 
68 	/* output strings in text segment */
69 	etext = INITTEXT + textsize;
70 	for(t = pc; t < etext; t += sizeof(buf)-100) {
71 		if(etext-t > sizeof(buf)-100)
72 			datblk(t, sizeof(buf)-100, 1);
73 		else
74 			datblk(t, etext-t, 1);
75 	}
76 
77 	curtext = P;
78 	switch(HEADTYPE) {
79 	case 0:
80 	case 1:
81 	case 2:
82 	case 5:
83 		OFFSET = HEADR+textsize;
84 		seek(cout, OFFSET, 0);
85 		break;
86 	case 3:
87 		OFFSET = rnd(HEADR+textsize, 4096);
88 		seek(cout, OFFSET, 0);
89 		break;
90 	}
91 	if(dlm){
92 		char buf[8];
93 
94 		write(cout, buf, INITDAT-textsize);
95 		textsize = INITDAT;
96 	}
97 	for(t = 0; t < datsize; t += sizeof(buf)-100) {
98 		if(datsize-t > sizeof(buf)-100)
99 			datblk(t, sizeof(buf)-100, 0);
100 		else
101 			datblk(t, datsize-t, 0);
102 	}
103 
104 	symsize = 0;
105 	lcsize = 0;
106 	if(!debug['s']) {
107 		if(debug['v'])
108 			Bprint(&bso, "%5.2f sym\n", cputime());
109 		Bflush(&bso);
110 		switch(HEADTYPE) {
111 		case 0:
112 		case 1:
113 		case 4:
114 		case 5:
115 			debug['s'] = 1;
116 			break;
117 		case 2:
118 			OFFSET = HEADR+textsize+datsize;
119 			seek(cout, OFFSET, 0);
120 			break;
121 		case 3:
122 			OFFSET += rnd(datsize, 4096);
123 			seek(cout, OFFSET, 0);
124 			break;
125 		}
126 		if(!debug['s'])
127 			asmsym();
128 		if(debug['v'])
129 			Bprint(&bso, "%5.2f pc\n", cputime());
130 		Bflush(&bso);
131 		if(!debug['s'])
132 			asmlc();
133 		if(dlm)
134 			asmdyn();
135 		cflush();
136 	}
137 	else if(dlm){
138 		seek(cout, HEADR+textsize+datsize, 0);
139 		asmdyn();
140 		cflush();
141 	}
142 
143 	if(debug['v'])
144 		Bprint(&bso, "%5.2f header\n", cputime());
145 	Bflush(&bso);
146 	OFFSET = 0;
147 	seek(cout, OFFSET, 0);
148 	switch(HEADTYPE) {
149 	case 0:	/* no header */
150 		break;
151 	case 1:	/* aif for risc os */
152 		lputl(0xe1a00000);		/* NOP - decompress code */
153 		lputl(0xe1a00000);		/* NOP - relocation code */
154 		lputl(0xeb000000 + 12);		/* BL - zero init code */
155 		lputl(0xeb000000 +
156 			(entryvalue()
157 			 - INITTEXT
158 			 + HEADR
159 			 - 12
160 			 - 8) / 4);		/* BL - entry code */
161 
162 		lputl(0xef000011);		/* SWI - exit code */
163 		lputl(textsize+HEADR);		/* text size */
164 		lputl(datsize);			/* data size */
165 		lputl(0);			/* sym size */
166 
167 		lputl(bsssize);			/* bss size */
168 		lputl(0);			/* sym type */
169 		lputl(INITTEXT-HEADR);		/* text addr */
170 		lputl(0);			/* workspace - ignored */
171 
172 		lputl(32);			/* addr mode / data addr flag */
173 		lputl(0);			/* data addr */
174 		for(t=0; t<2; t++)
175 			lputl(0);		/* reserved */
176 
177 		for(t=0; t<15; t++)
178 			lputl(0xe1a00000);	/* NOP - zero init code */
179 		lputl(0xe1a0f00e);		/* B (R14) - zero init return */
180 		break;
181 	case 2:	/* plan 9 */
182 		if(dlm)
183 			lput(0x80000000|0x647);	/* magic */
184 		else
185 			lput(0x647);			/* magic */
186 		lput(textsize);			/* sizes */
187 		lput(datsize);
188 		lput(bsssize);
189 		lput(symsize);			/* nsyms */
190 		lput(entryvalue());		/* va of entry */
191 		lput(0L);
192 		lput(lcsize);
193 		break;
194 	case 3:	/* boot for NetBSD */
195 		lput((143<<16)|0413);		/* magic */
196 		lputl(rnd(HEADR+textsize, 4096));
197 		lputl(rnd(datsize, 4096));
198 		lputl(bsssize);
199 		lputl(symsize);			/* nsyms */
200 		lputl(entryvalue());		/* va of entry */
201 		lputl(0L);
202 		lputl(0L);
203 		break;
204 	case 4: /* boot for IXP1200 */
205 		break;
206 	case 5: /* boot for ipaq */
207 		lputl(0xe3300000);		/* nop */
208 		lputl(0xe3300000);		/* nop */
209 		lputl(0xe3300000);		/* nop */
210 		lputl(0xe3300000);		/* nop */
211 		break;
212 	}
213 	cflush();
214 }
215 
216 void
217 strnput(char *s, int n)
218 {
219 	for(; *s; s++){
220 		cput(*s);
221 		n--;
222 	}
223 	for(; n > 0; n--)
224 		cput(0);
225 }
226 
227 void
228 cput(int c)
229 {
230 	cbp[0] = c;
231 	cbp++;
232 	cbc--;
233 	if(cbc <= 0)
234 		cflush();
235 }
236 
237 void
238 wput(long l)
239 {
240 
241 	cbp[0] = l>>8;
242 	cbp[1] = l;
243 	cbp += 2;
244 	cbc -= 2;
245 	if(cbc <= 0)
246 		cflush();
247 }
248 
249 void
250 lput(long l)
251 {
252 
253 	cbp[0] = l>>24;
254 	cbp[1] = l>>16;
255 	cbp[2] = l>>8;
256 	cbp[3] = l;
257 	cbp += 4;
258 	cbc -= 4;
259 	if(cbc <= 0)
260 		cflush();
261 }
262 
263 void
264 lputl(long l)
265 {
266 
267 	cbp[3] = l>>24;
268 	cbp[2] = l>>16;
269 	cbp[1] = l>>8;
270 	cbp[0] = l;
271 	cbp += 4;
272 	cbc -= 4;
273 	if(cbc <= 0)
274 		cflush();
275 }
276 
277 void
278 cflush(void)
279 {
280 	int n;
281 
282 	n = sizeof(buf.cbuf) - cbc;
283 	if(n)
284 		write(cout, buf.cbuf, n);
285 	cbp = buf.cbuf;
286 	cbc = sizeof(buf.cbuf);
287 }
288 
289 void
290 nopstat(char *f, Count *c)
291 {
292 	if(c->outof)
293 	Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
294 		c->outof - c->count, c->outof,
295 		(double)(c->outof - c->count)/c->outof);
296 }
297 
298 void
299 asmsym(void)
300 {
301 	Prog *p;
302 	Auto *a;
303 	Sym *s;
304 	int h;
305 
306 	s = lookup("etext", 0);
307 	if(s->type == STEXT)
308 		putsymb(s->name, 'T', s->value, s->version);
309 
310 	for(h=0; h<NHASH; h++)
311 		for(s=hash[h]; s!=S; s=s->link)
312 			switch(s->type) {
313 			case SCONST:
314 				putsymb(s->name, 'D', s->value, s->version);
315 				continue;
316 
317 			case SDATA:
318 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
319 				continue;
320 
321 			case SBSS:
322 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
323 				continue;
324 
325 			case SSTRING:
326 				putsymb(s->name, 'T', s->value, s->version);
327 				continue;
328 
329 			case SFILE:
330 				putsymb(s->name, 'f', s->value, s->version);
331 				continue;
332 			}
333 
334 	for(p=textp; p!=P; p=p->cond) {
335 		s = p->from.sym;
336 		if(s->type != STEXT && s->type != SLEAF)
337 			continue;
338 
339 		/* filenames first */
340 		for(a=p->to.autom; a; a=a->link)
341 			if(a->type == D_FILE)
342 				putsymb(a->asym->name, 'z', a->aoffset, 0);
343 			else
344 			if(a->type == D_FILE1)
345 				putsymb(a->asym->name, 'Z', a->aoffset, 0);
346 
347 		if(s->type == STEXT)
348 			putsymb(s->name, 'T', s->value, s->version);
349 		else
350 			putsymb(s->name, 'L', s->value, s->version);
351 
352 		/* frame, auto and param after */
353 		putsymb(".frame", 'm', p->to.offset+4, 0);
354 		for(a=p->to.autom; a; a=a->link)
355 			if(a->type == D_AUTO)
356 				putsymb(a->asym->name, 'a', -a->aoffset, 0);
357 			else
358 			if(a->type == D_PARAM)
359 				putsymb(a->asym->name, 'p', a->aoffset, 0);
360 	}
361 	if(debug['v'] || debug['n'])
362 		Bprint(&bso, "symsize = %lud\n", symsize);
363 	Bflush(&bso);
364 }
365 
366 void
367 putsymb(char *s, int t, long v, int ver)
368 {
369 	int i, f;
370 
371 	if(t == 'f')
372 		s++;
373 	lput(v);
374 	if(ver)
375 		t += 'a' - 'A';
376 	cput(t+0x80);			/* 0x80 is variable length */
377 
378 	if(t == 'Z' || t == 'z') {
379 		cput(s[0]);
380 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
381 			cput(s[i]);
382 			cput(s[i+1]);
383 		}
384 		cput(0);
385 		cput(0);
386 		i++;
387 	}
388 	else {
389 		for(i=0; s[i]; i++)
390 			cput(s[i]);
391 		cput(0);
392 	}
393 	symsize += 4 + 1 + i + 1;
394 
395 	if(debug['n']) {
396 		if(t == 'z' || t == 'Z') {
397 			Bprint(&bso, "%c %.8lux ", t, v);
398 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
399 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
400 				Bprint(&bso, "/%x", f);
401 			}
402 			Bprint(&bso, "\n");
403 			return;
404 		}
405 		if(ver)
406 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
407 		else
408 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
409 	}
410 }
411 
412 #define	MINLC	4
413 void
414 asmlc(void)
415 {
416 	long oldpc, oldlc;
417 	Prog *p;
418 	long v, s;
419 
420 	oldpc = INITTEXT;
421 	oldlc = 0;
422 	for(p = firstp; p != P; p = p->link) {
423 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
424 			if(p->as == ATEXT)
425 				curtext = p;
426 			if(debug['L'])
427 				Bprint(&bso, "%6lux %P\n",
428 					p->pc, p);
429 			continue;
430 		}
431 		if(debug['L'])
432 			Bprint(&bso, "\t\t%6ld", lcsize);
433 		v = (p->pc - oldpc) / MINLC;
434 		while(v) {
435 			s = 127;
436 			if(v < 127)
437 				s = v;
438 			cput(s+128);	/* 129-255 +pc */
439 			if(debug['L'])
440 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
441 			v -= s;
442 			lcsize++;
443 		}
444 		s = p->line - oldlc;
445 		oldlc = p->line;
446 		oldpc = p->pc + MINLC;
447 		if(s > 64 || s < -64) {
448 			cput(0);	/* 0 vv +lc */
449 			cput(s>>24);
450 			cput(s>>16);
451 			cput(s>>8);
452 			cput(s);
453 			if(debug['L']) {
454 				if(s > 0)
455 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
456 						s, 0, s);
457 				else
458 					Bprint(&bso, " lc%ld(%d,%ld)\n",
459 						s, 0, s);
460 				Bprint(&bso, "%6lux %P\n",
461 					p->pc, p);
462 			}
463 			lcsize += 5;
464 			continue;
465 		}
466 		if(s > 0) {
467 			cput(0+s);	/* 1-64 +lc */
468 			if(debug['L']) {
469 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
470 				Bprint(&bso, "%6lux %P\n",
471 					p->pc, p);
472 			}
473 		} else {
474 			cput(64-s);	/* 65-128 -lc */
475 			if(debug['L']) {
476 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
477 				Bprint(&bso, "%6lux %P\n",
478 					p->pc, p);
479 			}
480 		}
481 		lcsize++;
482 	}
483 	while(lcsize & 1) {
484 		s = 129;
485 		cput(s);
486 		lcsize++;
487 	}
488 	if(debug['v'] || debug['L'])
489 		Bprint(&bso, "lcsize = %ld\n", lcsize);
490 	Bflush(&bso);
491 }
492 
493 void
494 datblk(long s, long n, int str)
495 {
496 	Sym *v;
497 	Prog *p;
498 	char *cast;
499 	long a, l, fl, j, d;
500 	int i, c;
501 
502 	memset(buf.dbuf, 0, n+100);
503 	for(p = datap; p != P; p = p->link) {
504 		if(str != (p->from.sym->type == SSTRING))
505 			continue;
506 		curp = p;
507 		a = p->from.sym->value + p->from.offset;
508 		l = a - s;
509 		c = p->reg;
510 		i = 0;
511 		if(l < 0) {
512 			if(l+c <= 0)
513 				continue;
514 			while(l < 0) {
515 				l++;
516 				i++;
517 			}
518 		}
519 		if(l >= n)
520 			continue;
521 		if(p->as != AINIT && p->as != ADYNT) {
522 			for(j=l+(c-i)-1; j>=l; j--)
523 				if(buf.dbuf[j]) {
524 					print("%P\n", p);
525 					diag("multiple initialization");
526 					break;
527 				}
528 		}
529 		switch(p->to.type) {
530 		default:
531 			diag("unknown mode in initialization%P", p);
532 			break;
533 
534 		case D_FCONST:
535 			switch(c) {
536 			default:
537 			case 4:
538 				fl = ieeedtof(p->to.ieee);
539 				cast = (char*)&fl;
540 				for(; i<c; i++) {
541 					buf.dbuf[l] = cast[fnuxi4[i]];
542 					l++;
543 				}
544 				break;
545 			case 8:
546 				cast = (char*)p->to.ieee;
547 				for(; i<c; i++) {
548 					buf.dbuf[l] = cast[fnuxi8[i]];
549 					l++;
550 				}
551 				break;
552 			}
553 			break;
554 
555 		case D_SCONST:
556 			for(; i<c; i++) {
557 				buf.dbuf[l] = p->to.sval[i];
558 				l++;
559 			}
560 			break;
561 
562 		case D_CONST:
563 			d = p->to.offset;
564 			v = p->to.sym;
565 			if(v) {
566 				switch(v->type) {
567 				case SUNDEF:
568 					ckoff(v, d);
569 				case STEXT:
570 				case SLEAF:
571 				case SSTRING:
572 					d += p->to.sym->value;
573 					break;
574 				case SDATA:
575 				case SBSS:
576 					d += p->to.sym->value + INITDAT;
577 				}
578 				if(dlm)
579 					dynreloc(v, a+INITDAT, 1);
580 			}
581 			cast = (char*)&d;
582 			switch(c) {
583 			default:
584 				diag("bad nuxi %d %d%P", c, i, curp);
585 				break;
586 			case 1:
587 				for(; i<c; i++) {
588 					buf.dbuf[l] = cast[inuxi1[i]];
589 					l++;
590 				}
591 				break;
592 			case 2:
593 				for(; i<c; i++) {
594 					buf.dbuf[l] = cast[inuxi2[i]];
595 					l++;
596 				}
597 				break;
598 			case 4:
599 				for(; i<c; i++) {
600 					buf.dbuf[l] = cast[inuxi4[i]];
601 					l++;
602 				}
603 				break;
604 			}
605 			break;
606 		}
607 	}
608 	write(cout, buf.dbuf, n);
609 }
610 
611 void
612 asmout(Prog *p, Optab *o)
613 {
614 	long o1, o2, o3, o4, o5, o6, v;
615 	int r, rf, rt, rt2;
616 	Sym *s;
617 
618 PP = p;
619 	o1 = 0;
620 	o2 = 0;
621 	o3 = 0;
622 	o4 = 0;
623 	o5 = 0;
624 	o6 = 0;
625 	switch(o->type) {
626 	default:
627 		diag("unknown asm %d", o->type);
628 		prasm(p);
629 		break;
630 
631 	case 0:		/* pseudo ops */
632 		break;
633 
634 	case 1:		/* op R,[R],R */
635 		o1 = oprrr(p->as, p->scond);
636 		rf = p->from.reg;
637 		rt = p->to.reg;
638 		r = p->reg;
639 		if(p->to.type == D_NONE)
640 			rt = 0;
641 		if(p->as == AMOVW || p->as == AMVN)
642 			r = 0;
643 		else if(r == NREG)
644 			r = rt;
645 		o1 |= rf | (r<<16) | (rt<<12);
646 		break;
647 
648 	case 2:		/* movbu $I,[R],R */
649 		aclass(&p->from);
650 		o1 = oprrr(p->as, p->scond);
651 		o1 |= immrot(instoffset);
652 		rt = p->to.reg;
653 		r = p->reg;
654 		if(p->to.type == D_NONE)
655 			rt = 0;
656 		if(p->as == AMOVW || p->as == AMVN)
657 			r = 0;
658 		else if(r == NREG)
659 			r = rt;
660 		o1 |= (r<<16) | (rt<<12);
661 		break;
662 
663 	case 3:		/* add R<<[IR],[R],R */
664 	mov:
665 		aclass(&p->from);
666 		o1 = oprrr(p->as, p->scond);
667 		o1 |= p->from.offset;
668 		rt = p->to.reg;
669 		r = p->reg;
670 		if(p->to.type == D_NONE)
671 			rt = 0;
672 		if(p->as == AMOVW || p->as == AMVN)
673 			r = 0;
674 		else if(r == NREG)
675 			r = rt;
676 		o1 |= (r<<16) | (rt<<12);
677 		break;
678 
679 	case 4:		/* add $I,[R],R */
680 		aclass(&p->from);
681 		o1 = oprrr(AADD, p->scond);
682 		o1 |= immrot(instoffset);
683 		r = p->from.reg;
684 		if(r == NREG)
685 			r = o->param;
686 		o1 |= r << 16;
687 		o1 |= p->to.reg << 12;
688 		break;
689 
690 	case 5:		/* bra s */
691 		v = -8;
692 		if(p->cond == UP) {
693 			s = p->to.sym;
694 			if(s->type != SUNDEF)
695 				diag("bad branch sym type");
696 			v = (ulong)s->value >> (Roffset-2);
697 			dynreloc(s, p->pc, 0);
698 		}
699 		else if(p->cond != P)
700 			v = (p->cond->pc - pc) - 8;
701 		o1 = opbra(p->as, p->scond);
702 		o1 |= (v >> 2) & 0xffffff;
703 		break;
704 
705 	case 6:		/* b ,O(R) -> add $O,R,PC */
706 		aclass(&p->to);
707 		o1 = oprrr(AADD, p->scond);
708 		o1 |= immrot(instoffset);
709 		o1 |= p->to.reg << 16;
710 		o1 |= REGPC << 12;
711 		break;
712 
713 	case 7:		/* bl ,O(R) -> mov PC,link; add $O,R,PC */
714 		aclass(&p->to);
715 		o1 = oprrr(AADD, p->scond);
716 		o1 |= immrot(0);
717 		o1 |= REGPC << 16;
718 		o1 |= REGLINK << 12;
719 
720 		o2 = oprrr(AADD, p->scond);
721 		o2 |= immrot(instoffset);
722 		o2 |= p->to.reg << 16;
723 		o2 |= REGPC << 12;
724 		break;
725 
726 	case 8:		/* sll $c,[R],R -> mov (R<<$c),R */
727 		aclass(&p->from);
728 		o1 = oprrr(p->as, p->scond);
729 		r = p->reg;
730 		if(r == NREG)
731 			r = p->to.reg;
732 		o1 |= r;
733 		o1 |= (instoffset&31) << 7;
734 		o1 |= p->to.reg << 12;
735 		break;
736 
737 	case 9:		/* sll R,[R],R -> mov (R<<R),R */
738 		o1 = oprrr(p->as, p->scond);
739 		r = p->reg;
740 		if(r == NREG)
741 			r = p->to.reg;
742 		o1 |= r;
743 		o1 |= (p->from.reg << 8) | (1<<4);
744 		o1 |= p->to.reg << 12;
745 		break;
746 
747 	case 10:	/* swi [$con] */
748 		o1 = oprrr(p->as, p->scond);
749 		if(p->to.type != D_NONE) {
750 			aclass(&p->to);
751 			o1 |= instoffset & 0xffffff;
752 		}
753 		break;
754 
755 	case 11:	/* word */
756 		switch(aclass(&p->to)) {
757 		case C_LCON:
758 			if(!dlm)
759 				break;
760 			if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
761 				break;
762 		case C_ADDR:
763 			if(p->to.sym->type == SUNDEF)
764 				ckoff(p->to.sym, p->to.offset);
765 			dynreloc(p->to.sym, p->pc, 1);
766 		}
767 		o1 = instoffset;
768 		break;
769 
770 	case 12:	/* movw $lcon, reg */
771 		o1 = omvl(p, &p->from, p->to.reg);
772 		break;
773 
774 	case 13:	/* op $lcon, [R], R */
775 		o1 = omvl(p, &p->from, REGTMP);
776 		if(!o1)
777 			break;
778 		o2 = oprrr(p->as, p->scond);
779 		o2 |= REGTMP;
780 		r = p->reg;
781 		if(p->as == AMOVW || p->as == AMVN)
782 			r = 0;
783 		else if(r == NREG)
784 			r = p->to.reg;
785 		o2 |= r << 16;
786 		if(p->to.type != D_NONE)
787 			o2 |= p->to.reg << 12;
788 		break;
789 
790 	case 14:	/* movb/movbu/movh/movhu R,R */
791 		o1 = oprrr(ASLL, p->scond);
792 
793 		if(p->as == AMOVBU || p->as == AMOVHU)
794 			o2 = oprrr(ASRL, p->scond);
795 		else
796 			o2 = oprrr(ASRA, p->scond);
797 
798 		r = p->to.reg;
799 		o1 |= (p->from.reg)|(r<<12);
800 		o2 |= (r)|(r<<12);
801 		if(p->as == AMOVB || p->as == AMOVBU) {
802 			o1 |= (24<<7);
803 			o2 |= (24<<7);
804 		} else {
805 			o1 |= (16<<7);
806 			o2 |= (16<<7);
807 		}
808 		break;
809 
810 	case 15:	/* mul r,[r,]r */
811 		o1 = oprrr(p->as, p->scond);
812 		rf = p->from.reg;
813 		rt = p->to.reg;
814 		r = p->reg;
815 		if(r == NREG)
816 			r = rt;
817 		if(rt == r) {
818 			r = rf;
819 			rf = rt;
820 		}
821 		if(0)
822 		if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
823 			diag("bad registers in MUL");
824 			prasm(p);
825 		}
826 		o1 |= (rf<<8) | r | (rt<<16);
827 		break;
828 
829 
830 	case 16:	/* div r,[r,]r */
831 		o1 = 0xf << 28;
832 		o2 = 0;
833 		break;
834 
835 	case 17:
836 		o1 = oprrr(p->as, p->scond);
837 		rf = p->from.reg;
838 		rt = p->to.reg;
839 		rt2 = p->to.offset;
840 		r = p->reg;
841 		o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
842 		break;
843 
844 	case 20:	/* mov/movb/movbu R,O(R) */
845 		aclass(&p->to);
846 		r = p->to.reg;
847 		if(r == NREG)
848 			r = o->param;
849 		o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
850 		break;
851 
852 	case 21:	/* mov/movbu O(R),R -> lr */
853 		aclass(&p->from);
854 		r = p->from.reg;
855 		if(r == NREG)
856 			r = o->param;
857 		o1 = olr(instoffset, r, p->to.reg, p->scond);
858 		if(p->as != AMOVW)
859 			o1 |= 1<<22;
860 		break;
861 
862 	case 22:	/* movb/movh/movhu O(R),R -> lr,shl,shr */
863 		aclass(&p->from);
864 		r = p->from.reg;
865 		if(r == NREG)
866 			r = o->param;
867 		o1 = olr(instoffset, r, p->to.reg, p->scond);
868 
869 		o2 = oprrr(ASLL, p->scond);
870 		o3 = oprrr(ASRA, p->scond);
871 		r = p->to.reg;
872 		if(p->as == AMOVB) {
873 			o2 |= (24<<7)|(r)|(r<<12);
874 			o3 |= (24<<7)|(r)|(r<<12);
875 		} else {
876 			o2 |= (16<<7)|(r)|(r<<12);
877 			if(p->as == AMOVHU)
878 				o3 = oprrr(ASRL, p->scond);
879 			o3 |= (16<<7)|(r)|(r<<12);
880 		}
881 		break;
882 
883 	case 23:	/* movh/movhu R,O(R) -> sb,sb */
884 		aclass(&p->to);
885 		r = p->to.reg;
886 		if(r == NREG)
887 			r = o->param;
888 		o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond);
889 
890 		o2 = oprrr(ASRL, p->scond);
891 		o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12);
892 
893 		o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond);
894 		break;
895 
896 	case 30:	/* mov/movb/movbu R,L(R) */
897 		o1 = omvl(p, &p->to, REGTMP);
898 		if(!o1)
899 			break;
900 		r = p->to.reg;
901 		if(r == NREG)
902 			r = o->param;
903 		o2 = osrr(p->from.reg, REGTMP,r, p->scond);
904 		if(p->as != AMOVW)
905 			o2 |= 1<<22;
906 		break;
907 
908 	case 31:	/* mov/movbu L(R),R -> lr[b] */
909 	case 32:	/* movh/movb L(R),R -> lr[b] */
910 		o1 = omvl(p, &p->from, REGTMP);
911 		if(!o1)
912 			break;
913 		r = p->from.reg;
914 		if(r == NREG)
915 			r = o->param;
916 		o2 = olrr(REGTMP,r, p->to.reg, p->scond);
917 		if(p->as == AMOVBU || p->as == AMOVB)
918 			o2 |= 1<<22;
919 		if(o->type == 31)
920 			break;
921 
922 		o3 = oprrr(ASLL, p->scond);
923 
924 		if(p->as == AMOVBU || p->as == AMOVHU)
925 			o4 = oprrr(ASRL, p->scond);
926 		else
927 			o4 = oprrr(ASRA, p->scond);
928 
929 		r = p->to.reg;
930 		o3 |= (r)|(r<<12);
931 		o4 |= (r)|(r<<12);
932 		if(p->as == AMOVB || p->as == AMOVBU) {
933 			o3 |= (24<<7);
934 			o4 |= (24<<7);
935 		} else {
936 			o3 |= (16<<7);
937 			o4 |= (16<<7);
938 		}
939 		break;
940 
941 	case 33:	/* movh/movhu R,L(R) -> sb, sb */
942 		o1 = omvl(p, &p->to, REGTMP);
943 		if(!o1)
944 			break;
945 		r = p->to.reg;
946 		if(r == NREG)
947 			r = o->param;
948 		o2 = osrr(p->from.reg, REGTMP, r, p->scond);
949 		o2 |= (1<<22) ;
950 
951 		o3 = oprrr(ASRL, p->scond);
952 		o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
953 		o3 |= (1<<6);	/* ROR 8 */
954 
955 		o4 = oprrr(AADD, p->scond);
956 		o4 |= (REGTMP << 12) | (REGTMP << 16);
957 		o4 |= immrot(1);
958 
959 		o5 = osrr(p->from.reg, REGTMP,r,p->scond);
960 		o5 |= (1<<22);
961 
962 		o6 = oprrr(ASRL, p->scond);
963 		o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
964 		o6 |= (1<<6);	/* ROL 8 */
965 
966 		break;
967 
968 	case 34:	/* mov $lacon,R */
969 		o1 = omvl(p, &p->from, REGTMP);
970 		if(!o1)
971 			break;
972 
973 		o2 = oprrr(AADD, p->scond);
974 		o2 |= REGTMP;
975 		r = p->from.reg;
976 		if(r == NREG)
977 			r = o->param;
978 		o2 |= r << 16;
979 		if(p->to.type != D_NONE)
980 			o2 |= p->to.reg << 12;
981 		break;
982 
983 	case 35:	/* mov PSR,R */
984 		o1 = (2<<23) | (0xf<<16) | (0<<0);
985 		o1 |= (p->scond & C_SCOND) << 28;
986 		o1 |= (p->from.reg & 1) << 22;
987 		o1 |= p->to.reg << 12;
988 		break;
989 
990 	case 36:	/* mov R,PSR */
991 		o1 = (2<<23) | (0x29f<<12) | (0<<4);
992 		if(p->scond & C_FBIT)
993 			o1 ^= 0x010 << 12;
994 		o1 |= (p->scond & C_SCOND) << 28;
995 		o1 |= (p->to.reg & 1) << 22;
996 		o1 |= p->from.reg << 0;
997 		break;
998 
999 	case 37:	/* mov $con,PSR */
1000 		aclass(&p->from);
1001 		o1 = (2<<23) | (0x29f<<12) | (0<<4);
1002 		if(p->scond & C_FBIT)
1003 			o1 ^= 0x010 << 12;
1004 		o1 |= (p->scond & C_SCOND) << 28;
1005 		o1 |= immrot(instoffset);
1006 		o1 |= (p->to.reg & 1) << 22;
1007 		o1 |= p->from.reg << 0;
1008 		break;
1009 
1010 	case 38:	/* movm $con,oreg -> stm */
1011 		o1 = (0x4 << 25);
1012 		o1 |= p->from.offset & 0xffff;
1013 		o1 |= p->to.reg << 16;
1014 		aclass(&p->to);
1015 		goto movm;
1016 
1017 	case 39:	/* movm oreg,$con -> ldm */
1018 		o1 = (0x4 << 25) | (1 << 20);
1019 		o1 |= p->to.offset & 0xffff;
1020 		o1 |= p->from.reg << 16;
1021 		aclass(&p->from);
1022 	movm:
1023 		if(instoffset != 0)
1024 			diag("offset must be zero in MOVM");
1025 		o1 |= (p->scond & C_SCOND) << 28;
1026 		if(p->scond & C_PBIT)
1027 			o1 |= 1 << 24;
1028 		if(p->scond & C_UBIT)
1029 			o1 |= 1 << 23;
1030 		if(p->scond & C_SBIT)
1031 			o1 |= 1 << 22;
1032 		if(p->scond & C_WBIT)
1033 			o1 |= 1 << 21;
1034 		break;
1035 
1036 	case 40:	/* swp oreg,reg,reg */
1037 		aclass(&p->from);
1038 		if(instoffset != 0)
1039 			diag("offset must be zero in SWP");
1040 		o1 = (0x2<<23) | (0x9<<4);
1041 		if(p->as != ASWPW)
1042 			o1 |= 1 << 22;
1043 		o1 |= p->from.reg << 16;
1044 		o1 |= p->reg << 0;
1045 		o1 |= p->to.reg << 12;
1046 		o1 |= (p->scond & C_SCOND) << 28;
1047 		break;
1048 
1049 	case 41:	/* rfe -> movm.s.w.u 0(r13),[r15] */
1050 		o1 = 0xe8fd8000;
1051 		break;
1052 
1053 	case 50:	/* floating point store */
1054 		v = regoff(&p->to);
1055 		r = p->to.reg;
1056 		if(r == NREG)
1057 			r = o->param;
1058 		o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
1059 		break;
1060 
1061 	case 51:	/* floating point load */
1062 		v = regoff(&p->from);
1063 		r = p->from.reg;
1064 		if(r == NREG)
1065 			r = o->param;
1066 		o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
1067 		break;
1068 
1069 	case 52:	/* floating point store, long offset UGLY */
1070 		o1 = omvl(p, &p->to, REGTMP);
1071 		if(!o1)
1072 			break;
1073 		r = p->to.reg;
1074 		if(r == NREG)
1075 			r = o->param;
1076 		o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
1077 		o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
1078 		break;
1079 
1080 	case 53:	/* floating point load, long offset UGLY */
1081 		o1 = omvl(p, &p->from, REGTMP);
1082 		if(!o1)
1083 			break;
1084 		r = p->from.reg;
1085 		if(r == NREG)
1086 			r = o->param;
1087 		o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
1088 		o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
1089 		break;
1090 
1091 	case 54:	/* floating point arith */
1092 		o1 = oprrr(p->as, p->scond);
1093 		if(p->from.type == D_FCONST) {
1094 			rf = chipfloat(p->from.ieee);
1095 			if(rf < 0){
1096 				diag("invalid floating-point immediate\n%P", p);
1097 				rf = 0;
1098 			}
1099 			rf |= (1<<3);
1100 		} else
1101 			rf = p->from.reg;
1102 		rt = p->to.reg;
1103 		r = p->reg;
1104 		if(p->to.type == D_NONE)
1105 			rt = 0;	/* CMP[FD] */
1106 		else if(o1 & (1<<15))
1107 			r = 0;	/* monadic */
1108 		else if(r == NREG)
1109 			r = rt;
1110 		o1 |= rf | (r<<16) | (rt<<12);
1111 		break;
1112 
1113 	case 55:	/* floating point fix and float */
1114 		o1 = oprrr(p->as, p->scond);
1115 		rf = p->from.reg;
1116 		rt = p->to.reg;
1117 		if(p->to.type == D_NONE){
1118 			rt = 0;
1119 			diag("to.type==D_NONE (asm/fp)");
1120 		}
1121 		if(p->from.type == D_REG)
1122 			o1 |= (rf<<12) | (rt<<16);
1123 		else
1124 			o1 |= rf | (rt<<12);
1125 		break;
1126 
1127 	case 56:	/* move to FP[CS]R */
1128 		o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
1129 		o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
1130 		break;
1131 
1132 	case 57:	/* move from FP[CS]R */
1133 		o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
1134 		o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
1135 		break;
1136 	case 58:	/* movbu R,R */
1137 		o1 = oprrr(AAND, p->scond);
1138 		o1 |= immrot(0xff);
1139 		rt = p->to.reg;
1140 		r = p->from.reg;
1141 		if(p->to.type == D_NONE)
1142 			rt = 0;
1143 		if(r == NREG)
1144 			r = rt;
1145 		o1 |= (r<<16) | (rt<<12);
1146 		break;
1147 
1148 	case 59:	/* movw/bu R<<I(R),R -> ldr indexed */
1149 		if(p->from.reg == NREG) {
1150 			if(p->as != AMOVW)
1151 				diag("byte MOV from shifter operand");
1152 			goto mov;
1153 		}
1154 		if(p->from.offset&(1<<4))
1155 			diag("bad shift in LDR");
1156 		o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
1157 		if(p->as == AMOVBU)
1158 			o1 |= 1<<22;
1159 		break;
1160 
1161 	case 60:	/* movb R(R),R -> ldrsb indexed */
1162 		if(p->from.reg == NREG) {
1163 			diag("byte MOV from shifter operand");
1164 			goto mov;
1165 		}
1166 		if(p->from.offset&(~0xf))
1167 			diag("bad shift in LDRSB");
1168 		o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
1169 		o1 ^= (1<<5)|(1<<6);
1170 		break;
1171 
1172 	case 61:	/* movw/b/bu R,R<<[IR](R) -> str indexed */
1173 		if(p->to.reg == NREG)
1174 			diag("MOV to shifter operand");
1175 		o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
1176 		if(p->as == AMOVB || p->as == AMOVBU)
1177 			o1 |= 1<<22;
1178 		break;
1179 
1180 	case 62:	/* case R -> movw	R<<2(PC),PC */
1181 		o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
1182 		o1 |= 2<<7;
1183 		break;
1184 
1185 	case 63:	/* bcase */
1186 		if(p->cond != P) {
1187 			o1 = p->cond->pc;
1188 			if(dlm)
1189 				dynreloc(S, p->pc, 1);
1190 		}
1191 		break;
1192 
1193 	/* reloc ops */
1194 	case 64:	/* mov/movb/movbu R,addr */
1195 		o1 = omvl(p, &p->to, REGTMP);
1196 		if(!o1)
1197 			break;
1198 		o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1199 		break;
1200 
1201 	case 65:	/* mov/movbu addr,R */
1202 	case 66:	/* movh/movhu/movb addr,R */
1203 		o1 = omvl(p, &p->from, REGTMP);
1204 		if(!o1)
1205 			break;
1206 		o2 = olr(0, REGTMP, p->to.reg, p->scond);
1207 		if(p->as == AMOVBU || p->as == AMOVB)
1208 			o2 |= 1<<22;
1209 		if(o->type == 65)
1210 			break;
1211 
1212 		o3 = oprrr(ASLL, p->scond);
1213 
1214 		if(p->as == AMOVBU || p->as == AMOVHU)
1215 			o4 = oprrr(ASRL, p->scond);
1216 		else
1217 			o4 = oprrr(ASRA, p->scond);
1218 
1219 		r = p->to.reg;
1220 		o3 |= (r)|(r<<12);
1221 		o4 |= (r)|(r<<12);
1222 		if(p->as == AMOVB || p->as == AMOVBU) {
1223 			o3 |= (24<<7);
1224 			o4 |= (24<<7);
1225 		} else {
1226 			o3 |= (16<<7);
1227 			o4 |= (16<<7);
1228 		}
1229 		break;
1230 
1231 	case 67:	/* movh/movhu R,addr -> sb, sb */
1232 		o1 = omvl(p, &p->to, REGTMP);
1233 		if(!o1)
1234 			break;
1235 		o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1236 
1237 		o3 = oprrr(ASRL, p->scond);
1238 		o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
1239 		o3 |= (1<<6);	/* ROR 8 */
1240 
1241 		o4 = oprrr(AADD, p->scond);
1242 		o4 |= (REGTMP << 12) | (REGTMP << 16);
1243 		o4 |= immrot(1);
1244 
1245 		o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1246 
1247 		o6 = oprrr(ASRL, p->scond);
1248 		o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
1249 		o6 |= (1<<6);	/* ROL 8 */
1250 		break;
1251 
1252 	case 68:	/* floating point store -> ADDR */
1253 		o1 = omvl(p, &p->to, REGTMP);
1254 		if(!o1)
1255 			break;
1256 		o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
1257 		break;
1258 
1259 	case 69:	/* floating point load <- ADDR */
1260 		o1 = omvl(p, &p->from, REGTMP);
1261 		if(!o1)
1262 			break;
1263 		o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
1264 		break;
1265 
1266 	/* ArmV4 ops: */
1267 	case 70:	/* movh/movhu R,O(R) -> strh */
1268 		aclass(&p->to);
1269 		r = p->to.reg;
1270 		if(r == NREG)
1271 			r = o->param;
1272 		o1 = oshr(p->from.reg, instoffset, r, p->scond);
1273 		break;
1274 	case 71:	/* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
1275 		aclass(&p->from);
1276 		r = p->from.reg;
1277 		if(r == NREG)
1278 			r = o->param;
1279 		o1 = olhr(instoffset, r, p->to.reg, p->scond);
1280 		if(p->as == AMOVB)
1281 			o1 ^= (1<<5)|(1<<6);
1282 		else if(p->as == AMOVH)
1283 			o1 ^= (1<<6);
1284 		break;
1285 	case 72:	/* movh/movhu R,L(R) -> strh */
1286 		o1 = omvl(p, &p->to, REGTMP);
1287 		if(!o1)
1288 			break;
1289 		r = p->to.reg;
1290 		if(r == NREG)
1291 			r = o->param;
1292 		o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
1293 		break;
1294 	case 73:	/* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
1295 		o1 = omvl(p, &p->from, REGTMP);
1296 		if(!o1)
1297 			break;
1298 		r = p->from.reg;
1299 		if(r == NREG)
1300 			r = o->param;
1301 		o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
1302 		if(p->as == AMOVB)
1303 			o2 ^= (1<<5)|(1<<6);
1304 		else if(p->as == AMOVH)
1305 			o2 ^= (1<<6);
1306 		break;
1307 	}
1308 
1309 	if(debug['a'] > 1)
1310 		Bprint(&bso, "%2d ", o->type);
1311 
1312 	v = p->pc;
1313 	switch(o->size) {
1314 	default:
1315 		if(debug['a'])
1316 			Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
1317 		break;
1318 	case 4:
1319 		if(debug['a'])
1320 			Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
1321 		lputl(o1);
1322 		break;
1323 	case 8:
1324 		if(debug['a'])
1325 			Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
1326 		lputl(o1);
1327 		lputl(o2);
1328 		break;
1329 	case 12:
1330 		if(debug['a'])
1331 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
1332 		lputl(o1);
1333 		lputl(o2);
1334 		lputl(o3);
1335 		break;
1336 	case 16:
1337 		if(debug['a'])
1338 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
1339 				v, o1, o2, o3, o4, p);
1340 		lputl(o1);
1341 		lputl(o2);
1342 		lputl(o3);
1343 		lputl(o4);
1344 		break;
1345 	case 20:
1346 		if(debug['a'])
1347 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1348 				v, o1, o2, o3, o4, o5, p);
1349 		lputl(o1);
1350 		lputl(o2);
1351 		lputl(o3);
1352 		lputl(o4);
1353 		lputl(o5);
1354 		break;
1355 	case 24:
1356 		if(debug['a'])
1357 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1358 				v, o1, o2, o3, o4, o5, o6, p);
1359 		lputl(o1);
1360 		lputl(o2);
1361 		lputl(o3);
1362 		lputl(o4);
1363 		lputl(o5);
1364 		lputl(o6);
1365 		break;
1366 	}
1367 }
1368 
1369 long
1370 oprrr(int a, int sc)
1371 {
1372 	long o;
1373 
1374 	o = (sc & C_SCOND) << 28;
1375 	if(sc & C_SBIT)
1376 		o |= 1 << 20;
1377 	if(sc & (C_PBIT|C_WBIT))
1378 		diag(".P/.W on dp instruction");
1379 	switch(a) {
1380 	case AMULU:
1381 	case AMUL:	return o | (0x0<<21) | (0x9<<4);
1382 	case AMULA:	return o | (0x1<<21) | (0x9<<4);
1383 	case AMULLU:	return o | (0x4<<21) | (0x9<<4);
1384 	case AMULL:	return o | (0x6<<21) | (0x9<<4);
1385 	case AMULALU:	return o | (0x5<<21) | (0x9<<4);
1386 	case AMULAL:	return o | (0x7<<21) | (0x9<<4);
1387 	case AAND:	return o | (0x0<<21);
1388 	case AEOR:	return o | (0x1<<21);
1389 	case ASUB:	return o | (0x2<<21);
1390 	case ARSB:	return o | (0x3<<21);
1391 	case AADD:	return o | (0x4<<21);
1392 	case AADC:	return o | (0x5<<21);
1393 	case ASBC:	return o | (0x6<<21);
1394 	case ARSC:	return o | (0x7<<21);
1395 	case ATST:	return o | (0x8<<21) | (1<<20);
1396 	case ATEQ:	return o | (0x9<<21) | (1<<20);
1397 	case ACMP:	return o | (0xa<<21) | (1<<20);
1398 	case ACMN:	return o | (0xb<<21) | (1<<20);
1399 	case AORR:	return o | (0xc<<21);
1400 	case AMOVW:	return o | (0xd<<21);
1401 	case ABIC:	return o | (0xe<<21);
1402 	case AMVN:	return o | (0xf<<21);
1403 	case ASLL:	return o | (0xd<<21) | (0<<5);
1404 	case ASRL:	return o | (0xd<<21) | (1<<5);
1405 	case ASRA:	return o | (0xd<<21) | (2<<5);
1406 	case ASWI:	return o | (0xf<<24);
1407 
1408 	case AADDD:	return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
1409 	case AADDF:	return o | (0xe<<24) | (0x0<<20) | (1<<8);
1410 	case AMULD:	return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
1411 	case AMULF:	return o | (0xe<<24) | (0x1<<20) | (1<<8);
1412 	case ASUBD:	return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
1413 	case ASUBF:	return o | (0xe<<24) | (0x2<<20) | (1<<8);
1414 	case ADIVD:	return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
1415 	case ADIVF:	return o | (0xe<<24) | (0x4<<20) | (1<<8);
1416 	case ACMPD:
1417 	case ACMPF:	return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4);	/* arguably, ACMPF should expand to RNDF, CMPD */
1418 
1419 	case AMOVF:
1420 	case AMOVDF:	return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
1421 	case AMOVD:
1422 	case AMOVFD:	return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
1423 
1424 	case AMOVWF:	return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
1425 	case AMOVWD:	return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
1426 	case AMOVFW:	return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
1427 	case AMOVDW:	return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
1428 	}
1429 	diag("bad rrr %d", a);
1430 	prasm(curp);
1431 	return 0;
1432 }
1433 
1434 long
1435 opbra(int a, int sc)
1436 {
1437 
1438 	if(sc & (C_SBIT|C_PBIT|C_WBIT))
1439 		diag(".S/.P/.W on bra instruction");
1440 	sc &= C_SCOND;
1441 	if(a == ABL)
1442 		return (sc<<28)|(0x5<<25)|(0x1<<24);
1443 	if(sc != 0xe)
1444 		diag(".COND on bcond instruction");
1445 	switch(a) {
1446 	case ABEQ:	return (0x0<<28)|(0x5<<25);
1447 	case ABNE:	return (0x1<<28)|(0x5<<25);
1448 	case ABCS:	return (0x2<<28)|(0x5<<25);
1449 	case ABHS:	return (0x2<<28)|(0x5<<25);
1450 	case ABCC:	return (0x3<<28)|(0x5<<25);
1451 	case ABLO:	return (0x3<<28)|(0x5<<25);
1452 	case ABMI:	return (0x4<<28)|(0x5<<25);
1453 	case ABPL:	return (0x5<<28)|(0x5<<25);
1454 	case ABVS:	return (0x6<<28)|(0x5<<25);
1455 	case ABVC:	return (0x7<<28)|(0x5<<25);
1456 	case ABHI:	return (0x8<<28)|(0x5<<25);
1457 	case ABLS:	return (0x9<<28)|(0x5<<25);
1458 	case ABGE:	return (0xa<<28)|(0x5<<25);
1459 	case ABLT:	return (0xb<<28)|(0x5<<25);
1460 	case ABGT:	return (0xc<<28)|(0x5<<25);
1461 	case ABLE:	return (0xd<<28)|(0x5<<25);
1462 	case AB:	return (0xe<<28)|(0x5<<25);
1463 	}
1464 	diag("bad bra %A", a);
1465 	prasm(curp);
1466 	return 0;
1467 }
1468 
1469 long
1470 olr(long v, int b, int r, int sc)
1471 {
1472 	long o;
1473 
1474 	if(sc & C_SBIT)
1475 		diag(".S on LDR/STR instruction");
1476 	o = (sc & C_SCOND) << 28;
1477 	if(!(sc & C_PBIT))
1478 		o |= 1 << 24;
1479 	if(!(sc & C_UBIT))
1480 		o |= 1 << 23;
1481 	if(sc & C_WBIT)
1482 		o |= 1 << 21;
1483 	o |= (0x1<<26) | (1<<20);
1484 	if(v < 0) {
1485 		v = -v;
1486 		o ^= 1 << 23;
1487 	}
1488 	if(v >= (1<<12))
1489 		diag("literal span too large: %ld (R%d)\n%P", v, b, PP);
1490 	o |= v;
1491 	o |= b << 16;
1492 	o |= r << 12;
1493 	return o;
1494 }
1495 
1496 long
1497 olhr(long v, int b, int r, int sc)
1498 {
1499 	long o;
1500 
1501 	if(sc & C_SBIT)
1502 		diag(".S on LDRH/STRH instruction");
1503 	o = (sc & C_SCOND) << 28;
1504 	if(!(sc & C_PBIT))
1505 		o |= 1 << 24;
1506 	if(sc & C_WBIT)
1507 		o |= 1 << 21;
1508 	o |= (1<<23) | (1<<20)|(0xb<<4);
1509 	if(v < 0) {
1510 		v = -v;
1511 		o ^= 1 << 23;
1512 	}
1513 	if(v >= (1<<8))
1514 		diag("literal span too large: %ld (R%d)\n%P", v, b, PP);
1515 	o |= (v&0xf)|((v>>4)<<8)|(1<<22);
1516 	o |= b << 16;
1517 	o |= r << 12;
1518 	return o;
1519 }
1520 
1521 long
1522 osr(int a, int r, long v, int b, int sc)
1523 {
1524 	long o;
1525 
1526 	o = olr(v, b, r, sc) ^ (1<<20);
1527 	if(a != AMOVW)
1528 		o |= 1<<22;
1529 	return o;
1530 }
1531 
1532 long
1533 oshr(int r, long v, int b, int sc)
1534 {
1535 	long o;
1536 
1537 	o = olhr(v, b, r, sc) ^ (1<<20);
1538 	return o;
1539 }
1540 
1541 
1542 long
1543 osrr(int r, int i, int b, int sc)
1544 {
1545 
1546 	return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
1547 }
1548 
1549 long
1550 oshrr(int r, int i, int b, int sc)
1551 {
1552 	return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
1553 }
1554 
1555 long
1556 olrr(int i, int b, int r, int sc)
1557 {
1558 
1559 	return olr(i, b, r, sc) ^ (1<<25);
1560 }
1561 
1562 long
1563 olhrr(int i, int b, int r, int sc)
1564 {
1565 	return olhr(i, b, r, sc) ^ (1<<22);
1566 }
1567 
1568 long
1569 ofsr(int a, int r, long v, int b, int sc, Prog *p)
1570 {
1571 	long o;
1572 
1573 	if(sc & C_SBIT)
1574 		diag(".S on FLDR/FSTR instruction");
1575 	o = (sc & C_SCOND) << 28;
1576 	if(!(sc & C_PBIT))
1577 		o |= 1 << 24;
1578 	if(sc & C_WBIT)
1579 		o |= 1 << 21;
1580 	o |= (6<<25) | (1<<24) | (1<<23);
1581 	if(v < 0) {
1582 		v = -v;
1583 		o ^= 1 << 23;
1584 	}
1585 	if(v & 3)
1586 		diag("odd offset for floating point op: %ld\n%P", v, p);
1587 	else if(v >= (1<<10))
1588 		diag("literal span too large: %ld\n%P", v, p);
1589 	o |= (v>>2) & 0xFF;
1590 	o |= b << 16;
1591 	o |= r << 12;
1592 	o |= 1 << 8;
1593 
1594 	switch(a) {
1595 	default:
1596 		diag("bad fst %A", a);
1597 	case AMOVD:
1598 		o |= 1<<15;
1599 	case AMOVF:
1600 		break;
1601 	}
1602 	return o;
1603 }
1604 
1605 long
1606 omvl(Prog *p, Adr *a, int dr)
1607 {
1608 	long v, o1;
1609 	if(!p->cond) {
1610 		aclass(a);
1611 		v = immrot(~instoffset);
1612 		if(v == 0) {
1613 			diag("missing literal");
1614 			prasm(p);
1615 			return 0;
1616 		}
1617 		o1 = oprrr(AMVN, p->scond&C_SCOND);
1618 		o1 |= v;
1619 		o1 |= dr << 12;
1620 	} else {
1621 		v = p->cond->pc - p->pc - 8;
1622 		o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
1623 	}
1624 	return o1;
1625 }
1626 
1627 static Ieee chipfloats[] = {
1628 	{0x00000000, 0x00000000}, /* 0 */
1629 	{0x00000000, 0x3ff00000}, /* 1 */
1630 	{0x00000000, 0x40000000}, /* 2 */
1631 	{0x00000000, 0x40080000}, /* 3 */
1632 	{0x00000000, 0x40100000}, /* 4 */
1633 	{0x00000000, 0x40140000}, /* 5 */
1634 	{0x00000000, 0x3fe00000}, /* .5 */
1635 	{0x00000000, 0x40240000}, /* 10 */
1636 };
1637 
1638 int
1639 chipfloat(Ieee *e)
1640 {
1641 	Ieee *p;
1642 	int n;
1643 
1644 	for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
1645 		p = &chipfloats[n];
1646 		if(p->l == e->l && p->h == e->h)
1647 			return n;
1648 	}
1649 	return -1;
1650 }
1651