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