xref: /plan9/sys/src/cmd/5l/asm.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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(r == NREG)
642 			r = rt;
643 		o1 |= rf | (r<<16) | (rt<<12);
644 		break;
645 
646 	case 2:		/* movbu $I,[R],R */
647 		aclass(&p->from);
648 		o1 = oprrr(p->as, p->scond);
649 		o1 |= immrot(instoffset);
650 		rt = p->to.reg;
651 		r = p->reg;
652 		if(p->to.type == D_NONE)
653 			rt = 0;
654 		if(r == NREG)
655 			r = rt;
656 		o1 |= (r<<16) | (rt<<12);
657 		break;
658 
659 	case 3:		/* add R<<[IR],[R],R */
660 	mov:
661 		aclass(&p->from);
662 		o1 = oprrr(p->as, p->scond);
663 		o1 |= p->from.offset;
664 		rt = p->to.reg;
665 		r = p->reg;
666 		if(p->to.type == D_NONE)
667 			rt = 0;
668 		if(r == NREG)
669 			r = rt;
670 		o1 |= (r<<16) | (rt<<12);
671 		break;
672 
673 	case 4:		/* add $I,[R],R */
674 		aclass(&p->from);
675 		o1 = oprrr(AADD, p->scond);
676 		o1 |= immrot(instoffset);
677 		r = p->from.reg;
678 		if(r == NREG)
679 			r = o->param;
680 		o1 |= r << 16;
681 		o1 |= p->to.reg << 12;
682 		break;
683 
684 	case 5:		/* bra s */
685 		v = -8;
686 		if(p->cond == UP) {
687 			s = p->to.sym;
688 			if(s->type != SUNDEF)
689 				diag("bad branch sym type");
690 			v = (ulong)s->value >> (Roffset-2);
691 			dynreloc(s, p->pc, 0);
692 		}
693 		else if(p->cond != P)
694 			v = (p->cond->pc - pc) - 8;
695 		o1 = opbra(p->as, p->scond);
696 		o1 |= (v >> 2) & 0xffffff;
697 		break;
698 
699 	case 6:		/* b ,O(R) -> add $O,R,PC */
700 		aclass(&p->to);
701 		o1 = oprrr(AADD, p->scond);
702 		o1 |= immrot(instoffset);
703 		o1 |= p->to.reg << 16;
704 		o1 |= REGPC << 12;
705 		break;
706 
707 	case 7:		/* bl ,O(R) -> mov PC,link; add $O,R,PC */
708 		aclass(&p->to);
709 		o1 = oprrr(AADD, p->scond);
710 		o1 |= immrot(0);
711 		o1 |= REGPC << 16;
712 		o1 |= REGLINK << 12;
713 
714 		o2 = oprrr(AADD, p->scond);
715 		o2 |= immrot(instoffset);
716 		o2 |= p->to.reg << 16;
717 		o2 |= REGPC << 12;
718 		break;
719 
720 	case 8:		/* sll $c,[R],R -> mov (R<<$c),R */
721 		aclass(&p->from);
722 		o1 = oprrr(p->as, p->scond);
723 		r = p->reg;
724 		if(r == NREG)
725 			r = p->to.reg;
726 		o1 |= r;
727 		o1 |= (instoffset&31) << 7;
728 		o1 |= p->to.reg << 12;
729 		break;
730 
731 	case 9:		/* sll R,[R],R -> mov (R<<R),R */
732 		o1 = oprrr(p->as, p->scond);
733 		r = p->reg;
734 		if(r == NREG)
735 			r = p->to.reg;
736 		o1 |= r;
737 		o1 |= (p->from.reg << 8) | (1<<4);
738 		o1 |= p->to.reg << 12;
739 		break;
740 
741 	case 10:	/* swi [$con] */
742 		o1 = oprrr(p->as, p->scond);
743 		if(p->to.type != D_NONE) {
744 			aclass(&p->to);
745 			o1 |= instoffset & 0xffffff;
746 		}
747 		break;
748 
749 	case 11:	/* word */
750 		switch(aclass(&p->to)) {
751 		case C_LCON:
752 			if(!dlm)
753 				break;
754 			if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
755 				break;
756 		case C_ADDR:
757 			if(p->to.sym->type == SUNDEF)
758 				ckoff(p->to.sym, p->to.offset);
759 			dynreloc(p->to.sym, p->pc, 1);
760 		}
761 		o1 = instoffset;
762 		break;
763 
764 	case 12:	/* movw $lcon, reg */
765 		o1 = omvl(p, &p->from, p->to.reg);
766 		break;
767 
768 	case 13:	/* op $lcon, [R], R */
769 		o1 = omvl(p, &p->from, REGTMP);
770 		if(!o1)
771 			break;
772 		o2 = oprrr(p->as, p->scond);
773 		o2 |= REGTMP;
774 		r = p->reg;
775 		if(r == NREG)
776 			r = p->to.reg;
777 		o2 |= r << 16;
778 		if(p->to.type != D_NONE)
779 			o2 |= p->to.reg << 12;
780 		break;
781 
782 	case 14:	/* movb/movbu/movh/movhu R,R */
783 		o1 = oprrr(ASLL, p->scond);
784 
785 		if(p->as == AMOVBU || p->as == AMOVHU)
786 			o2 = oprrr(ASRL, p->scond);
787 		else
788 			o2 = oprrr(ASRA, p->scond);
789 
790 		r = p->to.reg;
791 		o1 |= (p->from.reg)|(r<<12);
792 		o2 |= (r)|(r<<12);
793 		if(p->as == AMOVB || p->as == AMOVBU) {
794 			o1 |= (24<<7);
795 			o2 |= (24<<7);
796 		} else {
797 			o1 |= (16<<7);
798 			o2 |= (16<<7);
799 		}
800 		break;
801 
802 	case 15:	/* mul r,[r,]r */
803 		o1 = oprrr(p->as, p->scond);
804 		rf = p->from.reg;
805 		rt = p->to.reg;
806 		r = p->reg;
807 		if(r == NREG)
808 			r = rt;
809 		if(rt == r) {
810 			r = rf;
811 			rf = rt;
812 		}
813 		if(0)
814 		if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
815 			diag("bad registers in MUL");
816 			prasm(p);
817 		}
818 		o1 |= (rf<<8) | r | (rt<<16);
819 		break;
820 
821 
822 	case 16:	/* div r,[r,]r */
823 		o1 = 0xf << 28;
824 		o2 = 0;
825 		break;
826 
827 	case 17:
828 		o1 = oprrr(p->as, p->scond);
829 		rf = p->from.reg;
830 		rt = p->to.reg;
831 		rt2 = p->to.offset;
832 		r = p->reg;
833 		o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
834 		break;
835 
836 	case 20:	/* mov/movb/movbu R,O(R) */
837 		aclass(&p->to);
838 		r = p->to.reg;
839 		if(r == NREG)
840 			r = o->param;
841 		o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
842 		break;
843 
844 	case 21:	/* mov/movbu O(R),R -> lr */
845 		aclass(&p->from);
846 		r = p->from.reg;
847 		if(r == NREG)
848 			r = o->param;
849 		o1 = olr(instoffset, r, p->to.reg, p->scond);
850 		if(p->as != AMOVW)
851 			o1 |= 1<<22;
852 		break;
853 
854 	case 22:	/* movb/movh/movhu O(R),R -> lr,shl,shr */
855 		aclass(&p->from);
856 		r = p->from.reg;
857 		if(r == NREG)
858 			r = o->param;
859 		o1 = olr(instoffset, r, p->to.reg, p->scond);
860 
861 		o2 = oprrr(ASLL, p->scond);
862 		o3 = oprrr(ASRA, p->scond);
863 		r = p->to.reg;
864 		if(p->as == AMOVB) {
865 			o2 |= (24<<7)|(r)|(r<<12);
866 			o3 |= (24<<7)|(r)|(r<<12);
867 		} else {
868 			o2 |= (16<<7)|(r)|(r<<12);
869 			if(p->as == AMOVHU)
870 				o3 = oprrr(ASRL, p->scond);
871 			o3 |= (16<<7)|(r)|(r<<12);
872 		}
873 		break;
874 
875 	case 23:	/* movh/movhu R,O(R) -> sb,sb */
876 		aclass(&p->to);
877 		r = p->to.reg;
878 		if(r == NREG)
879 			r = o->param;
880 		o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond);
881 
882 		o2 = oprrr(ASRL, p->scond);
883 		o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12);
884 
885 		o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond);
886 		break;
887 
888 	case 30:	/* mov/movb/movbu R,L(R) */
889 		o1 = omvl(p, &p->to, REGTMP);
890 		if(!o1)
891 			break;
892 		r = p->to.reg;
893 		if(r == NREG)
894 			r = o->param;
895 		o2 = osrr(p->from.reg, REGTMP,r, p->scond);
896 		if(p->as != AMOVW)
897 			o2 |= 1<<22;
898 		break;
899 
900 	case 31:	/* mov/movbu L(R),R -> lr[b] */
901 	case 32:	/* movh/movb L(R),R -> lr[b] */
902 		o1 = omvl(p, &p->from, REGTMP);
903 		if(!o1)
904 			break;
905 		r = p->from.reg;
906 		if(r == NREG)
907 			r = o->param;
908 		o2 = olrr(REGTMP,r, p->to.reg, p->scond);
909 		if(p->as == AMOVBU || p->as == AMOVB)
910 			o2 |= 1<<22;
911 		if(o->type == 31)
912 			break;
913 
914 		o3 = oprrr(ASLL, p->scond);
915 
916 		if(p->as == AMOVBU || p->as == AMOVHU)
917 			o4 = oprrr(ASRL, p->scond);
918 		else
919 			o4 = oprrr(ASRA, p->scond);
920 
921 		r = p->to.reg;
922 		o3 |= (r)|(r<<12);
923 		o4 |= (r)|(r<<12);
924 		if(p->as == AMOVB || p->as == AMOVBU) {
925 			o3 |= (24<<7);
926 			o4 |= (24<<7);
927 		} else {
928 			o3 |= (16<<7);
929 			o4 |= (16<<7);
930 		}
931 		break;
932 
933 	case 33:	/* movh/movhu R,L(R) -> sb, sb */
934 		o1 = omvl(p, &p->to, REGTMP);
935 		if(!o1)
936 			break;
937 		r = p->to.reg;
938 		if(r == NREG)
939 			r = o->param;
940 		o2 = osrr(p->from.reg, REGTMP, r, p->scond);
941 		o2 |= (1<<22) ;
942 
943 		o3 = oprrr(ASRL, p->scond);
944 		o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
945 		o3 |= (1<<6);	/* ROR 8 */
946 
947 		o4 = oprrr(AADD, p->scond);
948 		o4 |= (REGTMP << 12) | (REGTMP << 16);
949 		o4 |= immrot(1);
950 
951 		o5 = osrr(p->from.reg, REGTMP,r,p->scond);
952 		o5 |= (1<<22);
953 
954 		o6 = oprrr(ASRL, p->scond);
955 		o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
956 		o6 |= (1<<6);	/* ROL 8 */
957 
958 		break;
959 
960 	case 34:	/* mov $lacon,R */
961 		o1 = omvl(p, &p->from, REGTMP);
962 		if(!o1)
963 			break;
964 
965 		o2 = oprrr(AADD, p->scond);
966 		o2 |= REGTMP;
967 		r = p->from.reg;
968 		if(r == NREG)
969 			r = o->param;
970 		o2 |= r << 16;
971 		if(p->to.type != D_NONE)
972 			o2 |= p->to.reg << 12;
973 		break;
974 
975 	case 35:	/* mov PSR,R */
976 		o1 = (2<<23) | (0xf<<16) | (0<<0);
977 		o1 |= (p->scond & C_SCOND) << 28;
978 		o1 |= (p->from.reg & 1) << 22;
979 		o1 |= p->to.reg << 12;
980 		break;
981 
982 	case 36:	/* mov R,PSR */
983 		o1 = (2<<23) | (0x29f<<12) | (0<<4);
984 		if(p->scond & C_FBIT)
985 			o1 ^= 0x010 << 12;
986 		o1 |= (p->scond & C_SCOND) << 28;
987 		o1 |= (p->to.reg & 1) << 22;
988 		o1 |= p->from.reg << 0;
989 		break;
990 
991 	case 37:	/* mov $con,PSR */
992 		aclass(&p->from);
993 		o1 = (2<<23) | (0x29f<<12) | (0<<4);
994 		if(p->scond & C_FBIT)
995 			o1 ^= 0x010 << 12;
996 		o1 |= (p->scond & C_SCOND) << 28;
997 		o1 |= immrot(instoffset);
998 		o1 |= (p->to.reg & 1) << 22;
999 		o1 |= p->from.reg << 0;
1000 		break;
1001 
1002 	case 38:	/* movm $con,oreg -> stm */
1003 		o1 = (0x4 << 25);
1004 		o1 |= p->from.offset & 0xffff;
1005 		o1 |= p->to.reg << 16;
1006 		aclass(&p->to);
1007 		goto movm;
1008 
1009 	case 39:	/* movm oreg,$con -> ldm */
1010 		o1 = (0x4 << 25) | (1 << 20);
1011 		o1 |= p->to.offset & 0xffff;
1012 		o1 |= p->from.reg << 16;
1013 		aclass(&p->from);
1014 	movm:
1015 		if(instoffset != 0)
1016 			diag("offset must be zero in MOVM");
1017 		o1 |= (p->scond & C_SCOND) << 28;
1018 		if(p->scond & C_PBIT)
1019 			o1 |= 1 << 24;
1020 		if(p->scond & C_UBIT)
1021 			o1 |= 1 << 23;
1022 		if(p->scond & C_SBIT)
1023 			o1 |= 1 << 22;
1024 		if(p->scond & C_WBIT)
1025 			o1 |= 1 << 21;
1026 		break;
1027 
1028 	case 40:	/* swp oreg,reg,reg */
1029 		aclass(&p->from);
1030 		if(instoffset != 0)
1031 			diag("offset must be zero in SWP");
1032 		o1 = (0x2<<23) | (0x9<<4);
1033 		if(p->as != ASWPW)
1034 			o1 |= 1 << 22;
1035 		o1 |= p->from.reg << 16;
1036 		o1 |= p->reg << 0;
1037 		o1 |= p->to.reg << 12;
1038 		o1 |= (p->scond & C_SCOND) << 28;
1039 		break;
1040 
1041 	case 41:	/* rfe -> movm.s.w.u 0(r13),[r15] */
1042 		o1 = 0xe8fd8000;
1043 		break;
1044 
1045 	case 50:	/* floating point store */
1046 		v = regoff(&p->to);
1047 		r = p->to.reg;
1048 		if(r == NREG)
1049 			r = o->param;
1050 		o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
1051 		break;
1052 
1053 	case 51:	/* floating point load */
1054 		v = regoff(&p->from);
1055 		r = p->from.reg;
1056 		if(r == NREG)
1057 			r = o->param;
1058 		o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
1059 		break;
1060 
1061 	case 52:	/* floating point store, long offset UGLY */
1062 		o1 = omvl(p, &p->to, REGTMP);
1063 		if(!o1)
1064 			break;
1065 		r = p->to.reg;
1066 		if(r == NREG)
1067 			r = o->param;
1068 		o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
1069 		o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
1070 		break;
1071 
1072 	case 53:	/* floating point load, long offset UGLY */
1073 		o1 = omvl(p, &p->from, REGTMP);
1074 		if(!o1)
1075 			break;
1076 		r = p->from.reg;
1077 		if(r == NREG)
1078 			r = o->param;
1079 		o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
1080 		o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
1081 		break;
1082 
1083 	case 54:	/* floating point arith */
1084 		o1 = oprrr(p->as, p->scond);
1085 		if(p->from.type == D_FCONST) {
1086 			rf = chipfloat(p->from.ieee);
1087 			if(rf < 0){
1088 				diag("invalid floating-point immediate\n%P", p);
1089 				rf = 0;
1090 			}
1091 			rf |= (1<<3);
1092 		} else
1093 			rf = p->from.reg;
1094 		rt = p->to.reg;
1095 		r = p->reg;
1096 		if(p->to.type == D_NONE)
1097 			rt = 0;	/* CMP[FD] */
1098 		else if(o1 & (1<<15))
1099 			r = 0;	/* monadic */
1100 		else if(r == NREG)
1101 			r = rt;
1102 		o1 |= rf | (r<<16) | (rt<<12);
1103 		break;
1104 
1105 	case 55:	/* floating point fix and float */
1106 		o1 = oprrr(p->as, p->scond);
1107 		rf = p->from.reg;
1108 		rt = p->to.reg;
1109 		if(p->to.type == D_NONE){
1110 			rt = 0;
1111 			diag("to.type==D_NONE (asm/fp)");
1112 		}
1113 		if(p->from.type == D_REG)
1114 			o1 |= (rf<<12) | (rt<<16);
1115 		else
1116 			o1 |= rf | (rt<<12);
1117 		break;
1118 
1119 	case 56:	/* move to FP[CS]R */
1120 		o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
1121 		o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
1122 		break;
1123 
1124 	case 57:	/* move from FP[CS]R */
1125 		o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
1126 		o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
1127 		break;
1128 	case 58:	/* movbu R,R */
1129 		o1 = oprrr(AAND, p->scond);
1130 		o1 |= immrot(0xff);
1131 		rt = p->to.reg;
1132 		r = p->from.reg;
1133 		if(p->to.type == D_NONE)
1134 			rt = 0;
1135 		if(r == NREG)
1136 			r = rt;
1137 		o1 |= (r<<16) | (rt<<12);
1138 		break;
1139 
1140 	case 59:	/* movw/bu R<<I(R),R -> ldr indexed */
1141 		if(p->from.reg == NREG) {
1142 			if(p->as != AMOVW)
1143 				diag("byte MOV from shifter operand");
1144 			goto mov;
1145 		}
1146 		if(p->from.offset&(1<<4))
1147 			diag("bad shift in LDR");
1148 		o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
1149 		if(p->as == AMOVBU)
1150 			o1 |= 1<<22;
1151 		break;
1152 
1153 	case 60:	/* movb R(R),R -> ldrsb indexed */
1154 		if(p->from.reg == NREG) {
1155 			diag("byte MOV from shifter operand");
1156 			goto mov;
1157 		}
1158 		if(p->from.offset&(~0xf))
1159 			diag("bad shift in LDRSB");
1160 		o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
1161 		o1 ^= (1<<5)|(1<<6);
1162 		break;
1163 
1164 	case 61:	/* movw/b/bu R,R<<[IR](R) -> str indexed */
1165 		if(p->to.reg == NREG)
1166 			diag("MOV to shifter operand");
1167 		o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
1168 		if(p->as == AMOVB || p->as == AMOVBU)
1169 			o1 |= 1<<22;
1170 		break;
1171 
1172 	case 62:	/* case R -> movw	R<<2(PC),PC */
1173 		o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
1174 		o1 |= 2<<7;
1175 		break;
1176 
1177 	case 63:	/* bcase */
1178 		if(p->cond != P) {
1179 			o1 = p->cond->pc;
1180 			if(dlm)
1181 				dynreloc(S, p->pc, 1);
1182 		}
1183 		break;
1184 
1185 	/* reloc ops */
1186 	case 64:	/* mov/movb/movbu R,addr */
1187 		o1 = omvl(p, &p->to, REGTMP);
1188 		if(!o1)
1189 			break;
1190 		o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1191 		break;
1192 
1193 	case 65:	/* mov/movbu addr,R */
1194 	case 66:	/* movh/movhu/movb addr,R */
1195 		o1 = omvl(p, &p->from, REGTMP);
1196 		if(!o1)
1197 			break;
1198 		o2 = olr(0, REGTMP, p->to.reg, p->scond);
1199 		if(p->as == AMOVBU || p->as == AMOVB)
1200 			o2 |= 1<<22;
1201 		if(o->type == 65)
1202 			break;
1203 
1204 		o3 = oprrr(ASLL, p->scond);
1205 
1206 		if(p->as == AMOVBU || p->as == AMOVHU)
1207 			o4 = oprrr(ASRL, p->scond);
1208 		else
1209 			o4 = oprrr(ASRA, p->scond);
1210 
1211 		r = p->to.reg;
1212 		o3 |= (r)|(r<<12);
1213 		o4 |= (r)|(r<<12);
1214 		if(p->as == AMOVB || p->as == AMOVBU) {
1215 			o3 |= (24<<7);
1216 			o4 |= (24<<7);
1217 		} else {
1218 			o3 |= (16<<7);
1219 			o4 |= (16<<7);
1220 		}
1221 		break;
1222 
1223 	case 67:	/* movh/movhu R,addr -> sb, sb */
1224 		o1 = omvl(p, &p->to, REGTMP);
1225 		if(!o1)
1226 			break;
1227 		o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1228 
1229 		o3 = oprrr(ASRL, p->scond);
1230 		o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
1231 		o3 |= (1<<6);	/* ROR 8 */
1232 
1233 		o4 = oprrr(AADD, p->scond);
1234 		o4 |= (REGTMP << 12) | (REGTMP << 16);
1235 		o4 |= immrot(1);
1236 
1237 		o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
1238 
1239 		o6 = oprrr(ASRL, p->scond);
1240 		o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
1241 		o6 |= (1<<6);	/* ROL 8 */
1242 		break;
1243 
1244 	case 68:	/* floating point store -> ADDR */
1245 		o1 = omvl(p, &p->to, REGTMP);
1246 		if(!o1)
1247 			break;
1248 		o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
1249 		break;
1250 
1251 	case 69:	/* floating point load <- ADDR */
1252 		o1 = omvl(p, &p->from, REGTMP);
1253 		if(!o1)
1254 			break;
1255 		o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
1256 		break;
1257 
1258 	/* ArmV4 ops: */
1259 	case 70:	/* movh/movhu R,O(R) -> strh */
1260 		aclass(&p->to);
1261 		r = p->to.reg;
1262 		if(r == NREG)
1263 			r = o->param;
1264 		o1 = oshr(p->from.reg, instoffset, r, p->scond);
1265 		break;
1266 	case 71:	/* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
1267 		aclass(&p->from);
1268 		r = p->from.reg;
1269 		if(r == NREG)
1270 			r = o->param;
1271 		o1 = olhr(instoffset, r, p->to.reg, p->scond);
1272 		if(p->as == AMOVB)
1273 			o1 ^= (1<<5)|(1<<6);
1274 		else if(p->as == AMOVH)
1275 			o1 ^= (1<<6);
1276 		break;
1277 	case 72:	/* movh/movhu R,L(R) -> strh */
1278 		o1 = omvl(p, &p->to, REGTMP);
1279 		if(!o1)
1280 			break;
1281 		r = p->to.reg;
1282 		if(r == NREG)
1283 			r = o->param;
1284 		o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
1285 		break;
1286 	case 73:	/* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
1287 		o1 = omvl(p, &p->from, REGTMP);
1288 		if(!o1)
1289 			break;
1290 		r = p->from.reg;
1291 		if(r == NREG)
1292 			r = o->param;
1293 		o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
1294 		if(p->as == AMOVB)
1295 			o2 ^= (1<<5)|(1<<6);
1296 		else if(p->as == AMOVH)
1297 			o2 ^= (1<<6);
1298 		break;
1299 	}
1300 
1301 	if(debug['a'] > 1)
1302 		Bprint(&bso, "%2d ", o->type);
1303 
1304 	v = p->pc;
1305 	switch(o->size) {
1306 	default:
1307 		if(debug['a'])
1308 			Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
1309 		break;
1310 	case 4:
1311 		if(debug['a'])
1312 			Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
1313 		lputl(o1);
1314 		break;
1315 	case 8:
1316 		if(debug['a'])
1317 			Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
1318 		lputl(o1);
1319 		lputl(o2);
1320 		break;
1321 	case 12:
1322 		if(debug['a'])
1323 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
1324 		lputl(o1);
1325 		lputl(o2);
1326 		lputl(o3);
1327 		break;
1328 	case 16:
1329 		if(debug['a'])
1330 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
1331 				v, o1, o2, o3, o4, p);
1332 		lputl(o1);
1333 		lputl(o2);
1334 		lputl(o3);
1335 		lputl(o4);
1336 		break;
1337 	case 20:
1338 		if(debug['a'])
1339 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1340 				v, o1, o2, o3, o4, o5, p);
1341 		lputl(o1);
1342 		lputl(o2);
1343 		lputl(o3);
1344 		lputl(o4);
1345 		lputl(o5);
1346 		break;
1347 	case 24:
1348 		if(debug['a'])
1349 			Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
1350 				v, o1, o2, o3, o4, o5, o6, p);
1351 		lputl(o1);
1352 		lputl(o2);
1353 		lputl(o3);
1354 		lputl(o4);
1355 		lputl(o5);
1356 		lputl(o6);
1357 		break;
1358 	}
1359 }
1360 
1361 long
1362 oprrr(int a, int sc)
1363 {
1364 	long o;
1365 
1366 	o = (sc & C_SCOND) << 28;
1367 	if(sc & C_SBIT)
1368 		o |= 1 << 20;
1369 	if(sc & (C_PBIT|C_WBIT))
1370 		diag(".P/.W on dp instruction");
1371 	switch(a) {
1372 	case AMULU:
1373 	case AMUL:	return o | (0x0<<21) | (0x9<<4);
1374 	case AMULA:	return o | (0x1<<21) | (0x9<<4);
1375 	case AMULLU:	return o | (0x4<<21) | (0x9<<4);
1376 	case AMULL:	return o | (0x6<<21) | (0x9<<4);
1377 	case AMULALU:	return o | (0x5<<21) | (0x9<<4);
1378 	case AMULAL:	return o | (0x7<<21) | (0x9<<4);
1379 	case AAND:	return o | (0x0<<21);
1380 	case AEOR:	return o | (0x1<<21);
1381 	case ASUB:	return o | (0x2<<21);
1382 	case ARSB:	return o | (0x3<<21);
1383 	case AADD:	return o | (0x4<<21);
1384 	case AADC:	return o | (0x5<<21);
1385 	case ASBC:	return o | (0x6<<21);
1386 	case ARSC:	return o | (0x7<<21);
1387 	case ATST:	return o | (0x8<<21) | (1<<20);
1388 	case ATEQ:	return o | (0x9<<21) | (1<<20);
1389 	case ACMP:	return o | (0xa<<21) | (1<<20);
1390 	case ACMN:	return o | (0xb<<21) | (1<<20);
1391 	case AORR:	return o | (0xc<<21);
1392 	case AMOVW:	return o | (0xd<<21);
1393 	case ABIC:	return o | (0xe<<21);
1394 	case AMVN:	return o | (0xf<<21);
1395 	case ASLL:	return o | (0xd<<21) | (0<<5);
1396 	case ASRL:	return o | (0xd<<21) | (1<<5);
1397 	case ASRA:	return o | (0xd<<21) | (2<<5);
1398 	case ASWI:	return o | (0xf<<24);
1399 
1400 	case AADDD:	return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
1401 	case AADDF:	return o | (0xe<<24) | (0x0<<20) | (1<<8);
1402 	case AMULD:	return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
1403 	case AMULF:	return o | (0xe<<24) | (0x1<<20) | (1<<8);
1404 	case ASUBD:	return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
1405 	case ASUBF:	return o | (0xe<<24) | (0x2<<20) | (1<<8);
1406 	case ADIVD:	return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
1407 	case ADIVF:	return o | (0xe<<24) | (0x4<<20) | (1<<8);
1408 	case ACMPD:
1409 	case ACMPF:	return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4);	/* arguably, ACMPF should expand to RNDF, CMPD */
1410 
1411 	case AMOVF:
1412 	case AMOVDF:	return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
1413 	case AMOVD:
1414 	case AMOVFD:	return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
1415 
1416 	case AMOVWF:	return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
1417 	case AMOVWD:	return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
1418 	case AMOVFW:	return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
1419 	case AMOVDW:	return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
1420 	}
1421 	diag("bad rrr %d", a);
1422 	prasm(curp);
1423 	return 0;
1424 }
1425 
1426 long
1427 opbra(int a, int sc)
1428 {
1429 
1430 	if(sc & (C_SBIT|C_PBIT|C_WBIT))
1431 		diag(".S/.P/.W on bra instruction");
1432 	sc &= C_SCOND;
1433 	if(a == ABL)
1434 		return (sc<<28)|(0x5<<25)|(0x1<<24);
1435 	if(sc != 0xe)
1436 		diag(".COND on bcond instruction");
1437 	switch(a) {
1438 	case ABEQ:	return (0x0<<28)|(0x5<<25);
1439 	case ABNE:	return (0x1<<28)|(0x5<<25);
1440 	case ABCS:	return (0x2<<28)|(0x5<<25);
1441 	case ABHS:	return (0x2<<28)|(0x5<<25);
1442 	case ABCC:	return (0x3<<28)|(0x5<<25);
1443 	case ABLO:	return (0x3<<28)|(0x5<<25);
1444 	case ABMI:	return (0x4<<28)|(0x5<<25);
1445 	case ABPL:	return (0x5<<28)|(0x5<<25);
1446 	case ABVS:	return (0x6<<28)|(0x5<<25);
1447 	case ABVC:	return (0x7<<28)|(0x5<<25);
1448 	case ABHI:	return (0x8<<28)|(0x5<<25);
1449 	case ABLS:	return (0x9<<28)|(0x5<<25);
1450 	case ABGE:	return (0xa<<28)|(0x5<<25);
1451 	case ABLT:	return (0xb<<28)|(0x5<<25);
1452 	case ABGT:	return (0xc<<28)|(0x5<<25);
1453 	case ABLE:	return (0xd<<28)|(0x5<<25);
1454 	case AB:	return (0xe<<28)|(0x5<<25);
1455 	}
1456 	diag("bad bra %A", a);
1457 	prasm(curp);
1458 	return 0;
1459 }
1460 
1461 long
1462 olr(long v, int b, int r, int sc)
1463 {
1464 	long o;
1465 
1466 	if(sc & C_SBIT)
1467 		diag(".S on LDR/STR instruction");
1468 	o = (sc & C_SCOND) << 28;
1469 	if(!(sc & C_PBIT))
1470 		o |= 1 << 24;
1471 	if(!(sc & C_UBIT))
1472 		o |= 1 << 23;
1473 	if(sc & C_WBIT)
1474 		o |= 1 << 21;
1475 	o |= (0x1<<26) | (1<<20);
1476 	if(v < 0) {
1477 		v = -v;
1478 		o ^= 1 << 23;
1479 	}
1480 	if(v >= (1<<12))
1481 		diag("literal span too large: %d (R%d)\n%P", v, b, PP);
1482 	o |= v;
1483 	o |= b << 16;
1484 	o |= r << 12;
1485 	return o;
1486 }
1487 
1488 long
1489 olhr(long v, int b, int r, int sc)
1490 {
1491 	long o;
1492 
1493 	if(sc & C_SBIT)
1494 		diag(".S on LDRH/STRH instruction");
1495 	o = (sc & C_SCOND) << 28;
1496 	if(!(sc & C_PBIT))
1497 		o |= 1 << 24;
1498 	if(sc & C_WBIT)
1499 		o |= 1 << 21;
1500 	o |= (1<<23) | (1<<20)|(0xb<<4);
1501 	if(v < 0) {
1502 		v = -v;
1503 		o ^= 1 << 23;
1504 	}
1505 	if(v >= (1<<8))
1506 		diag("literal span too large: %d (R%d)\n%P", v, b, PP);
1507 	o |= (v&0xf)|((v>>4)<<8)|(1<<22);
1508 	o |= b << 16;
1509 	o |= r << 12;
1510 	return o;
1511 }
1512 
1513 long
1514 osr(int a, int r, long v, int b, int sc)
1515 {
1516 	long o;
1517 
1518 	o = olr(v, b, r, sc) ^ (1<<20);
1519 	if(a != AMOVW)
1520 		o |= 1<<22;
1521 	return o;
1522 }
1523 
1524 long
1525 oshr(int r, long v, int b, int sc)
1526 {
1527 	long o;
1528 
1529 	o = olhr(v, b, r, sc) ^ (1<<20);
1530 	return o;
1531 }
1532 
1533 
1534 long
1535 osrr(int r, int i, int b, int sc)
1536 {
1537 
1538 	return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
1539 }
1540 
1541 long
1542 oshrr(int r, int i, int b, int sc)
1543 {
1544 	return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
1545 }
1546 
1547 long
1548 olrr(int i, int b, int r, int sc)
1549 {
1550 
1551 	return olr(i, b, r, sc) ^ (1<<25);
1552 }
1553 
1554 long
1555 olhrr(int i, int b, int r, int sc)
1556 {
1557 	return olhr(i, b, r, sc) ^ (1<<22);
1558 }
1559 
1560 long
1561 ofsr(int a, int r, long v, int b, int sc, Prog *p)
1562 {
1563 	long o;
1564 
1565 	if(sc & C_SBIT)
1566 		diag(".S on FLDR/FSTR instruction");
1567 	o = (sc & C_SCOND) << 28;
1568 	if(!(sc & C_PBIT))
1569 		o |= 1 << 24;
1570 	if(sc & C_WBIT)
1571 		o |= 1 << 21;
1572 	o |= (6<<25) | (1<<24) | (1<<23);
1573 	if(v < 0) {
1574 		v = -v;
1575 		o ^= 1 << 23;
1576 	}
1577 	if(v & 3)
1578 		diag("odd offset for floating point op: %d\n%P", v, p);
1579 	else if(v >= (1<<10))
1580 		diag("literal span too large: %d\n%P", v, p);
1581 	o |= (v>>2) & 0xFF;
1582 	o |= b << 16;
1583 	o |= r << 12;
1584 	o |= 1 << 8;
1585 
1586 	switch(a) {
1587 	default:
1588 		diag("bad fst %A", a);
1589 	case AMOVD:
1590 		o |= 1<<15;
1591 	case AMOVF:
1592 		break;
1593 	}
1594 	return o;
1595 }
1596 
1597 long
1598 omvl(Prog *p, Adr *a, int dr)
1599 {
1600 	long v, o1;
1601 	if(!p->cond) {
1602 		aclass(a);
1603 		v = immrot(~instoffset);
1604 		if(v == 0) {
1605 			diag("missing literal");
1606 			prasm(p);
1607 			return 0;
1608 		}
1609 		o1 = oprrr(AMVN, p->scond&C_SCOND);
1610 		o1 |= v;
1611 		o1 |= dr << 12;
1612 	} else {
1613 		v = p->cond->pc - p->pc - 8;
1614 		o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
1615 	}
1616 	return o1;
1617 }
1618 
1619 static Ieee chipfloats[] = {
1620 	{0x00000000, 0x00000000}, /* 0 */
1621 	{0x00000000, 0x3ff00000}, /* 1 */
1622 	{0x00000000, 0x40000000}, /* 2 */
1623 	{0x00000000, 0x40080000}, /* 3 */
1624 	{0x00000000, 0x40100000}, /* 4 */
1625 	{0x00000000, 0x40140000}, /* 5 */
1626 	{0x00000000, 0x3fe00000}, /* .5 */
1627 	{0x00000000, 0x40240000}, /* 10 */
1628 };
1629 
1630 int
1631 chipfloat(Ieee *e)
1632 {
1633 	Ieee *p;
1634 	int n;
1635 
1636 	for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
1637 		p = &chipfloats[n];
1638 		if(p->l == e->l && p->h == e->h)
1639 			return n;
1640 	}
1641 	return -1;
1642 }
1643