xref: /inferno-os/utils/5l/asm.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
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