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