|
|
1.1 root 1: /*
2: * Instruction formatting
3: * and decoding. This is for the Intel
4: * iAPX-86 microprocessor.
5: * Small addressing model (perhaps with
6: * separated CS and SS,DS,ES).
7: * No formatting for the large model calls,
8: * returns or jumps.
9: */
10: #include "asm.h"
11:
12: /*
13: * Branch map.
14: */
15: int *bp;
16: int bm;
17: int bb[NB];
18:
19: /*
20: * Read and format machine instructions.
21: * The argument `sp' is a pointer to the symbol
22: * table entry of the opcode. The `s_kind' field
23: * holds the operation kind; this determines the
24: * format and the semantics of the operation.
25: */
26: machine(sp)
27: struct sym *sp;
28: {
29: register op, m1, m2;
30: struct expr e1, e2;
31: int disp, flag, ob, rf, si, rn;
32:
33: op = sp->s_addr;
34: switch (sp->s_kind) {
35:
36: case S_EVEN:
37: if ((dot->s_addr&01) != 0) {
38: if (inbss == 0)
39: outab(0);
40: else
41: ++dot->s_addr;
42: }
43: lmode = ALIST;
44: break;
45:
46: case S_ODD:
47: if ((dot->s_addr&01) == 0) {
48: if (inbss == 0)
49: outab(0);
50: else
51: ++dot->s_addr;
52: }
53: lmode = ALIST;
54: break;
55:
56: case S_INH:
57: outab(op);
58: if (op==AAM || op==AAD) /* Need suffix byte */
59: outab(APB);
60: break;
61:
62: case S_INT:
63: expr(&e1, 0);
64: if (isabsn(&e1, 3)) {
65: outab(INT3);
66: break;
67: }
68: outab(INT);
69: outrb(&e1, 0);
70: break;
71:
72: case S_SYS:
73: expr(&e1, 0);
74: if (e1.e_type == E_ACON) {
75: outab(INT);
76: e1.e_addr += 128;
77: outrb(&e1, 0);
78: break;
79: }
80: aerr("expected constant");
81: break;
82:
83: case S_OVER:
84: if (addr(&e1) == SEGR) {
85: out3(SEGPFX, rof(e1));
86: break;
87: }
88: aerr("segment override by non-segment register");
89: break;
90:
91: case S_RET:
92: if (more() == 0) {
93: outab(op);
94: break;
95: }
96: expr(&e1, 0);
97: outab(op-1); /* Use ret n form */
98: outrw(&e1, 0);
99: break;
100:
101: case S_PUSH:
102: m1 = addr(&e1);
103: rn = rof(e1);
104: if (m1 == SEGR) {
105: if (op == PUSH)
106: out3(PUSHSR, rn);
107: else {
108: if (e1.e_mode == CS) /* No pop CS */
109: aerr("no 'pop CS' instruction");
110: out3(POPSR, rn);
111: }
112: break;
113: }
114: if (m1 == WR) {
115: if (op == PUSH)
116: outab(PUSHR | rn);
117: else
118: outab(POPR | rn);
119: break;
120: }
121: if ( m1 == IM ) {
122: if ( (e1.e_type == E_ACON)
123: && ( ((e1.e_addr & 0xFF80) == 0xFF80)
124: || ((e1.e_addr & 0xFF80) == 0x0000) ) ) {
125: outab( PUSHIB );
126: outab( e1.e_addr );
127: }
128: else {
129: outab( PUSHIW );
130: outrw(&e1, 0);
131: }
132: break;
133: }
134: outgen(op, ((op==PUSH) ? 6 : 0), &e1);
135: break;
136:
137: case S_IN:
138: m1 = addr(&e1);
139: comma();
140: m2 = addr(&e2);
141: IN_OUT:
142: if (m1 == WR && rof(e1) == AX)
143: op |= W;
144: else if (m1 == BR && rof(e1) == reg(AL))
145: op &= ~W;
146: else {
147: aerr("(in|out)(b|) must use AX or AL");
148: break;
149: }
150: if (m2 == WR && rof(e2) == DX) {
151: outab(op|010);
152: break;
153: } else if (m2 == DIR) {
154: outab(op);
155: outrb(&e2, 0);
156: break;
157: }
158: aerr("(in|out)(b|) must use DX or constant");
159: break;
160:
161: case S_OUT:
162: m2 = addr(&e2);
163: comma();
164: m1 = addr(&e1);
165: goto IN_OUT;
166:
167: case S_SHL:
168: case S_SHLB:
169: m1 = addr(&e1);
170: comma();
171: m2 = addr(&e2);
172: ob = SHL;
173: if (sp->s_kind == S_SHL)
174: ob |= W;
175: bytecheck(ob, m1, NONE);
176: if (m2 == BR && e2.e_addr == CL)
177: ob |= V;
178: else if ( (m2 == IM) && (e2.e_type == E_ACON) ) {
179: if ( e2.e_addr != 1 )
180: ob = (ob & W) ? (SHLI|W) : SHLI;
181: }
182: else
183: aerr("Improper shift amount");
184: outgen(ob, op, &e1);
185: if ( (ob & ~W) == SHLI )
186: outab( e2.e_addr );
187: break;
188:
189: case S_JMP:
190: if (addr(&e1) != DIR)
191: aerr("jmp must be direct address");
192: if (pass == 0) {
193: dot->s_addr += 3;
194: if (op != JMP)
195: dot->s_addr += 2;
196: } else if (pass == 1) {
197: if (e1.e_type != E_DIR
198: || e1.e_base.e_lp != dot->s_base.s_lp) {
199: /* long */
200: dot->s_addr += 3;
201: if (op != JMP)
202: dot->s_addr += 2;
203: flag = 1;
204: } else {
205: if (e1.e_addr >= dot->s_addr)
206: e1.e_addr -= fuzz;
207: dot->s_addr += 2;
208: disp = e1.e_addr - dot->s_addr;
209: flag = 0;
210: if (disp<-128 || disp>127) {
211: /* long */
212: flag = 1;
213: ++dot->s_addr;
214: if (op != JMP)
215: dot->s_addr += 2;
216: }
217: }
218: setbit(flag);
219: } else if (getbit()) {
220: if (op != JMP) {
221: outab(op ^ 01);
222: outab(03);
223: }
224: outab(0xE9);
225: outrw(&e1, 1);
226: } else {
227: disp = e1.e_addr - dot->s_addr - 2;
228: outab(op);
229: outab(disp);
230: }
231: break;
232:
233: case S_REL:
234: if (addr(&e1) != DIR
235: || e1.e_type != E_DIR
236: || e1.e_base.e_lp != dot->s_base.s_lp)
237: aerr("not a direct address in this segment");
238: disp = e1.e_addr - dot->s_addr - 2;
239: if (disp<-128 || disp>127)
240: aerr("address out of range");
241: outab(op);
242: outab(disp);
243: break;
244:
245: case S_IJMP:
246: addr(&e1);
247: outgen(IJORC, op, &e1);
248: break;
249:
250: case S_CALL:
251: if (addr(&e1) != DIR)
252: aerr("not a direct address");
253: outab(DCALL);
254: outrw(&e1, 1);
255: break;
256:
257: case S_DOP:
258: m1 = addr(&e1);
259: comma();
260: m2 = addr(&e2);
261: bytecheck(op, m1, m2);
262: if (m2 == IM) {
263: si = 0;
264: if (isalax(&e1)) {
265: if (op == TESTW)
266: op = TESTAW;
267: else if (op == TESTB)
268: op = TESTAB;
269: else
270: op |= 04;
271: outab(op);
272: } else {
273: if (op==TESTW || op==TESTB) {
274: rf = 0;
275: if (op == TESTW)
276: op = TESTMW;
277: else
278: op = TESTMB;
279: } else {
280: rf = (op&070)>>3;
281: op = (op&W)|0200;
282: if (ishort(sp, &e2)) {
283: ++si;
284: op |= S;
285: }
286: }
287: outgen(op, rf, &e1);
288: }
289: if (si || (op&W)==0)
290: outrb(&e2, 0);
291: else
292: outrw(&e2, 0);
293: break;
294: }
295: /* Dest is reg */
296: if (m1==BR || m1==WR) {
297: if (op!=TESTB && op!=TESTW)
298: op |= D;
299: outgen(op, rof(e1), &e2);
300: break;
301: }
302: /* Dest is mem */
303: outgen(op, rof(e2), &e1);
304: break;
305:
306: case S_XCHG:
307: m1 = addr(&e1);
308: comma();
309: m2 = addr(&e2);
310: bytecheck(op, m1, m2);
311: if (m1==WR && m2==WR) {
312: if (isalax(&e1)) {
313: outab(XCHGR | rof(e2));
314: break;
315: }
316: if (isalax(&e2)) {
317: outab(XCHGR | rof(e1));
318: break;
319: }
320: }
321: if (m1==BR || m1==WR) {
322: outgen(op, rof(e1), &e2);
323: break;
324: }
325: if (m2==BR || m2==WR) {
326: outgen(op, rof(e2), &e1);
327: break;
328: }
329: aerr("improper operand pair");
330: break;
331:
332: case S_SOP:
333: case S_SOPB:
334: m1 = addr(&e1);
335: ob = (op < 2) ? INCDEC : NOTNEG;
336: if (sp->s_kind == S_SOP)
337: ob |= W;
338: bytecheck(ob, m1, NONE);
339: if (op<2 && m1==WR) {
340: outab(IDREG | (op<<3) | rof(e1));
341: break;
342: }
343: outgen(ob, op, &e1);
344: break;
345:
346: case S_ESC:
347: addr(&e1);
348: outgen(ESC, 0, &e1);
349: break;
350:
351: case S_LEA:
352: m1 = addr(&e1);
353: comma();
354: m2 = addr(&e2);
355: if (m1!=WR)
356: aerr("must load address into register");
357: if(m2!=DIR && m2!=X)
358: aerr("must load direct address");
359: outgen(op, rof(e1), &e2);
360: break;
361:
362: case S_MOV:
363: m1 = addr(&e1);
364: comma();
365: m2 = addr(&e2);
366: bytecheck(op, m1, m2);
367: if (m2 == IM) {
368: if (m1 == BR) {
369: outab(MVIB | rof(e1));
370: outrb(&e2, 0);
371: break;
372: }
373: if (m1 == WR) {
374: outab(MVIW | rof(e1));
375: outrw(&e2, 0);
376: break;
377: }
378: /* To memory */
379: outgen((MVI|(op&W)), 0, &e1);
380: if ((op&W) == 0)
381: outrb(&e2, 0);
382: else
383: outrw(&e2, 0);
384: break;
385: }
386: /* Quick load */
387: if (isalax(&e1) && m2==DIR) {
388: outab(MOVMA|(op&W));
389: outrw(&e2, 0);
390: break;
391: }
392: /* Quick store */
393: if (m1==DIR && isalax(&e2)) {
394: outab(MOVAM|(op&W));
395: outrw(&e1, 0);
396: break;
397: }
398: if (m1 == SEGR)
399: outgen(MOVSEG|D, rof(e1), &e2);
400: else if (m2 == SEGR)
401: outgen(MOVSEG, rof(e2), &e1);
402: else if (m1==WR || m1==BR)
403: outgen(op|D, rof(e1), &e2);
404: else
405: outgen(op, rof(e2), &e1);
406: break;
407:
408: case S_MUL:
409: case S_MULB:
410: m1 = addr(&e1);
411: ob = MULDIV;
412: if (sp->s_kind == S_MUL)
413: ob |= W;
414: bytecheck(ob, m1, NONE);
415: outgen(ob, op, &e1);
416: break;
417: case S_PROT0:
418: case S_PROT1:
419: /*
420: * Protection control.
421: */
422: m1 = addr(&e1);
423: if ( (m1 != WR) && (m1 != DIR) && (m1 != X) )
424: aerr();
425: outab( 0x0F );
426: outgen( (sp->s_kind == S_PROT0) ? 0x00 : 0x01, op, &e1 );
427: break;
428:
429: case S_PROTR:
430: /*
431: * Protection control to register.
432: */
433: if ( op == ARPL ) {
434: m2 = addr(&e2);
435: comma();
436: m1 = addr(&e1 );
437: }
438: else if ( op == CLTS ) {
439: outab( 0x0F );
440: outab( op );
441: break;
442: }
443: else {
444: m1 = addr(&e1);
445: comma();
446: m2 = addr(&e2);
447: }
448: if (m1!=WR || (m2!=WR &&m2!=DIR && m2!=X))
449: aerr("Improper operand");
450: if ( op != ARPL )
451: outab( 0x0F );
452: outgen(op, rof(e1), &e2);
453: break;
454:
455: case S_ENTER:
456: m1 = addr(&e1);
457: comma();
458: m2 = addr(&e2);
459: if ( (m1 != DIR) || (e1.e_type != E_ACON)
460: || (m2 != DIR) || (e2.e_type != E_ACON) )
461: aerr();
462: outab( op );
463: outrw( &e1, 0);
464: outrb( &e2, 0 );
465: break;
466:
467: /* Floating point operations. */
468: /* No operands. */
469: case S_FP_F:
470: outab((sp->s_flag==S_NW) ? FNOP : FWAIT);
471: outab(BYTE1(op));
472: outab(BYTE2(op));
473: break;
474: /* Memory operand. */
475: case S_FP_M:
476: outab((sp->s_flag==S_NW) ? FNOP : FWAIT);
477: m1 = addr(&e1);
478: if (m1 != DIR && m1 != X)
479: qerr("invalid operand type");
480: outgen(BYTE1(op), BYTE2(op), &e1);
481: break;
482: /* Two optional fp stack operands. */
483: /* The opcode in the table is for the format "f<op> st<n>,st". */
484: /* Some nasty fudging here; thanks again, Intel. */
485: case S_FP_S:
486: outab(FWAIT);
487: if (fp_reg2(&e1, &e2)) {
488: if (e1.e_mode == ST) {
489: /* "f<op> st,st<n>". */
490: /* Change BYTE1 from 0xDC to 0xD8. */
491: outab(BYTE1(op)^4);
492: if (sp->s_flag == S_FIX)
493: outab((BYTE2(op)^8)|rof(e2));
494: else
495: outab(BYTE2(op)|rof(e2));
496: }
497: else {
498: /* "f<op> st<n>,st". */
499: outab(BYTE1(op));
500: outab(BYTE2(op)|rof(e1));
501: }
502: }
503: else { /* No args supplied; "f<op>" means "f<op>p st1,st". */
504: /* Change BYTE1 from 0xDC to 0xDE. */
505: outab(BYTE1(op)|2);
506: outab(BYTE2(op)|1);
507: }
508: break;
509: /* Two optional fp stack operands. */
510: case S_FP_SP:
511: fp_reg2(&e1, &e2);
512: if (e2.e_mode != ST)
513: qerr("invalid operand type");
514: outab(FWAIT);
515: outab(BYTE1(op));
516: outab((BYTE2(op))|rof(e1));
517: break;
518: /* One optional fp stack operand (default: ST). */
519: case S_FP_S1:
520: fp_reg(&e1);
521: outab(FWAIT);
522: outab(BYTE1(op));
523: outab(BYTE2(op)|rof(e1));
524: break;
525:
526: default:
527: err('o', "unknown operator");
528: }
529: }
530:
531: /*
532: * Check if the next non blank
533: * character is a comma. Give an error if
534: * not (and give up).
535: */
536: comma()
537: {
538: if (getnb() != ',')
539: qerr("expected comma");
540: }
541:
542: /*
543: * Output `general' format instructions.
544: * `Op' is the opcode, `r' is the general
545: * register (bits 3-5 of the postbyte) and
546: * `esp' is an address.
547: * The address must not be the flags, a
548: * segment register, (dx) or an immediate
549: * thing.
550: */
551: outgen(op, r, esp)
552: register struct expr *esp;
553: {
554: register disp, mode, regm;
555:
556: outab(op);
557: mode = esp->e_mode & MMASK;
558: regm = esp->e_mode & RMASK;
559: if (mode==IDX || mode==ICL || mode==IM || mode==SEGR) {
560: aerr("invalid operand");
561: return;
562: }
563: if (mode==BR || mode==WR) {
564: outab(0300 | (r<<3) | regm);
565: return;
566: }
567: if (mode == DIR) {
568: outab(0006 | (r<<3));
569: outrw(esp, 0);
570: return;
571: }
572: /* Mode is X */
573: if (esp->e_type == E_ACON) {
574: disp = esp->e_addr; /* Displacement */
575: if (regm!=6 && disp==0) {
576: outab((r<<3) | regm);
577: return;
578: }
579: if (disp>=-128 && disp<=127) {
580: outab(0100 | (r<<3) | regm);
581: outab(disp);
582: return;
583: }
584: }
585: outab(0200 | (r<<3) | regm);
586: outrw(esp, 0);
587: }
588:
589: /*
590: * Output a byte that looks like
591: * `bbbbbaaa'; this is a somewhat common
592: * format on the iAPX-86.
593: */
594: out3(a, b)
595: {
596: outab(a | (b<<3));
597: }
598:
599: /*
600: * Some consistancy checks.
601: * The `op' is an opcode with a valid `W' bit.
602: * `m1' and `m2' are modes.
603: */
604: bytecheck(op, m1, m2)
605: register op, m1, m2;
606: {
607: register bad;
608:
609: bad = 0;
610: if (m1 == BR) {
611: if ((op&W) != 0)
612: ++bad;
613: if (m2==WR || m2==SEGR)
614: ++bad;
615: }
616: if (m1==WR || m1==SEGR) {
617: if ((op&W) == 0)
618: ++bad;
619: if (m2 == BR)
620: ++bad;
621: }
622: if (m2 == BR) {
623: if ((op&W) != 0)
624: ++bad;
625: if (m1==WR || m1==SEGR)
626: ++bad;
627: }
628: if (m2==WR || m2==SEGR) {
629: if ((op&W) == 0)
630: ++bad;
631: if (m1 == BR)
632: ++bad;
633: }
634: if (bad)
635: aerr("invalid operand");
636: }
637:
638: /*
639: * Check to see if an address is
640: * one of the two machine accumulator registers.
641: * (AX or AL).
642: * True return if so.
643: */
644: isalax(esp)
645: register struct expr *esp;
646: {
647: if (esp->e_mode==AX || esp->e_mode==AL)
648: return (1);
649: return (0);
650: }
651:
652: /*
653: * Set up the big bit table
654: * used by the branch adjustment code.
655: */
656: minit()
657: {
658: bp = bb;
659: bm = 1;
660: }
661:
662: /*
663: * Store `b' in the next slot of the
664: * bit table.
665: * If no room, throw it away.
666: */
667: setbit(b)
668: {
669: if (bp >= &bb[NB])
670: return;
671: if (b)
672: *bp |= bm;
673: bm <<= 1;
674: if (bm == 0) {
675: bm = 1;
676: ++bp;
677: }
678: }
679:
680: /*
681: * Get the next bit from the bit
682: * table.
683: * If none left, return a `1'.
684: * This will get the long form of
685: * branches.
686: */
687: getbit()
688: {
689: register f;
690:
691: if (bp >= &bb[NB])
692: return (1);
693: f = *bp & bm;
694: bm <<= 1;
695: if (bm == 0) {
696: bm = 1;
697: ++bp;
698: }
699: return (f);
700: }
701:
702: /*
703: * This routine checks if the expression
704: * pointed to by `esp' is an absolute expression
705: * and has value `n'. This is used to check out
706: * the address fields of shifts and of interrupt
707: * request instructions.
708: */
709: isabsn(esp, n)
710: register struct expr *esp;
711: {
712: if (esp->e_type==E_ACON && esp->e_addr==n)
713: return (1);
714: return (0);
715: }
716:
717: /*
718: * This routine checks if an immediate
719: * operand fits in 8 bits. It is used to check
720: * for immediate length in instructions that
721: * can take the w:s immediate.
722: */
723: ishort(sp, esp)
724: register struct sym *sp;
725: register struct expr *esp;
726: {
727: register n;
728:
729: if ((sp->s_flag&S_OBL) == 0)
730: return (0);
731: if (esp->e_type != E_ACON)
732: return (0);
733: n = esp->e_addr&0177600;
734: if (n!=0 && n!=0177600)
735: return (0);
736: return (1);
737: }
738:
739: /*
740: * Make up the initial set of
741: * location counters.
742: * Poke one in every nonsegmented
743: * space. Add a special one for
744: * the C compiler's strings.
745: */
746: locinit()
747: {
748: struct loc *locdef();
749:
750: defloc = locdef(".shri", L_SHRI);
751: locdef(".prvi", L_PRVI);
752: locdef(".bssi", L_BSSI);
753: locdef(".shrd", L_SHRD);
754: locdef(".prvd", L_PRVD);
755: locdef(".bssd", L_BSSD);
756: locdef(".strn", L_PRVD);
757: locdef(".symt", L_DEBUG);
758: nloc = NLSEG;
759: }
760:
761: struct loc *
762: locdef(cp, t)
763: char *cp;
764: {
765: register char *cp1, *cp2;
766: register struct loc *lp;
767: struct sym *sp;
768: struct loc *lp1, *lp2;
769: int c;
770: char id[NCPLN];
771:
772: lp = (struct loc *) new(sizeof(struct loc));
773: lp->l_seg = t;
774: lp->l_lp = NULL;
775: lp->l_fuzz = 0;
776: lp->l_break = 0;
777: lp->l_offset = 0;
778: lp1 = NULL;
779: lp2 = loc[t];
780: while (lp2 != NULL) {
781: lp1 = lp2;
782: lp2 = lp2->l_lp;
783: }
784: if (lp1 == NULL)
785: loc[t] = lp; else
786: lp1->l_lp = lp;
787: cp1 = cp;
788: cp2 = &id[0];
789: while (c = *cp1++)
790: if (cp2 < &id[NCPLN])
791: *cp2++ = c;
792: while (cp2 < &id[NCPLN])
793: *cp2++ = 0;
794: sp = lookup(id, 1);
795: sp->s_kind = S_LOC;
796: sp->s_flag = 0;
797: sp->s_addr = (address)lp;
798: return (lp);
799: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.