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