|
|
1.1 root 1: /*
2: * The routines in this file assemble buffered code
3: * and write the code to the output file.
4: * This version is for the SMALL and LARGE models of segmentation.
5: */
6:
7: #ifdef vax
8: #include "INC$LIB:cc2.h"
9: #else
10: #include "cc2.h"
11: #endif
12:
13: #define W 0x01 /* W (word) bit */
14: #define D 0x02 /* D (direction) bit */
15: #define ESC 0xD8 /* Escape */
16: #define WAIT 0x9B /* Wait */
17:
18: static ADDRESS pc; /* Current assembly pc */
19: static ADDRESS pcdot[NSEG]; /* Working copy of seg '.' fields */
20: static int pcseg; /* Current segment */
21: static int pass; /* Pass flag; only 1 emits code */
22:
23: extern int hasfloat; /* function uses floating point */
24:
25: /*
26: * Driving routine.
27: * Run pass 0 of the assembly to get sizes.
28: * All jumps are assumed to be short.
29: * Fix up any that don't reach.
30: * Run the second assembly pass to generate the final code.
31: */
32: genfunc()
33: {
34: register INS *ip1, *ip2;
35: register int i;
36:
37: pc = dot;
38: pass = 0;
39: pcseg = dotseg;
40: for (i=0; i<NSEG; ++i)
41: pcdot[i] = seg[i].s_dot;
42: ip1 = ins.i_fp;
43: while (ip1 != &ins) {
44: assemble(ip1);
45: ip1 = ip1->i_fp;
46: }
47: sdi();
48: pc = dot;
49: pass = 1;
50: pcseg = dotseg;
51: for (i=0; i<NSEG; ++i)
52: pcdot[i] = seg[i].s_dot;
53: ip1 = ins.i_fp;
54: while (ip1 != &ins) {
55: asmdbgt(ip1);
56: if (isvariant(VASM))
57: unassemble(ip1);
58: else
59: assemble(ip1);
60: ip2 = ip1->i_fp;
61: free((char *) ip1);
62: ip1 = ip2;
63: }
64: asmdbgt(&ins);
65: }
66:
67: /*
68: * Generate code for a single instruction.
69: * Used to compile external data definitions, etc.
70: */
71: genins(ip)
72: register INS *ip;
73: {
74: register int i;
75:
76: for (pass=0; pass!=2; ++pass) {
77: pc = dot;
78: pcseg = dotseg;
79: for (i=0; i<NSEG; ++i)
80: pcdot[i] = seg[i].s_dot;
81: if (isvariant(VASM) && pass != 0) {
82: if (ip->i_type != LINE
83: || isvariant(VLINES))
84: unassemble(ip);
85: } else
86: assemble(ip);
87: }
88: }
89:
90: /*
91: * This function fixes up the span dependent instructions.
92: * The only case on the iAPX-86 is the jump, which has limited range.
93: * There is nothing to be done with the adjustable displacements,
94: * bacause these are always absolute and do not change.
95: */
96: sdi()
97: {
98: register INS *ip1, *ip2;
99: register SYM *sp;
100: register int bump, changes;
101: SIGNEDADDRESS disp;
102:
103: do {
104: changes = 0;
105: ip1 = ins.i_fp;
106: while (ip1 != &ins) {
107: if (isoptjump(ip1)) {
108: if ((sp=ip1->i_sp) == NULL)
109: cbotch("sdi");
110: if (ip1->i_pcseg != sp->s_seg)
111: cbotch("x seg #1");
112: disp = sp->s_value-ip1->i_pc-2;
113: if (disp<-128 || disp>127) {
114: ip1->i_long = 1;
115: changes = 1;
116: bump = 1;
117: if (ip1->i_rel != ZJMP)
118: bump = 3;
119: ip2 = ip1->i_fp;
120: while (ip2 != &ins) {
121: sdibump(ip1, ip2, bump);
122: ip2 = ip2->i_fp;
123: }
124: }
125: }
126: ip1 = ip1->i_fp;
127: }
128: } while (changes);
129: }
130:
131: /*
132: * This routine performs the nitty gritty
133: * of bumping an instruction to a higher address because
134: * an sdi changed from short to long.
135: * The 'ip1' argument is a pointer to the INS of the jump.
136: * The 'ip2' argument is the node to be bumped by 'bump' bytes.
137: * Only labels and code in the same segment as the 'ip1' node are adjusted.
138: */
139: sdibump(ip1, ip2, bump)
140: register INS *ip1;
141: register INS *ip2;
142: {
143: register int type;
144: register SYM *sp;
145:
146: if ((type=ip2->i_type) == LLABEL) {
147: if ((sp=ip2->i_sp) == NULL)
148: cbotch("sdibump");
149: if (sp->s_seg == ip1->i_pcseg)
150: sp->s_value += bump;
151: } else if (type==JUMP || type==CODE) {
152: if (ip2->i_pcseg == ip1->i_pcseg)
153: ip2->i_pc += bump;
154: }
155: }
156:
157: /*
158: * This routine checks if a node is an optimizable short jump.
159: * The node must be a jump,
160: * it must be short and it must either be the unconditional
161: * jump or one of the jumps that has a reverse.
162: */
163: isoptjump(ip1)
164: register INS *ip1;
165: {
166: register int rel;
167:
168: if (ip1->i_type==JUMP && ip1->i_long==0) {
169: rel = ip1->i_rel;
170: if (rel!=ZJCXZ && rel!=ZLOOP && rel!=ZLOOPE && rel!=ZLOOPNE)
171: return (1);
172: }
173: return (0);
174: }
175:
176: /*
177: * Assemble a line.
178: * If pass 1 the binary goes straight out.
179: * The ip1 argument points to the INS node that is to be assembled.
180: */
181: assemble(ip1)
182: register INS *ip1;
183: {
184: SIGNEDADDRESS disp;
185: int opbits;
186: int escape;
187: OPINFO *opinfop;
188: int opcode;
189: SYM *sp;
190: int ostyle;
191: AFIELD a1;
192: int prefix;
193: int m1, m2, regm, rn;
194: int shortflag;
195: sizeof_t length;
196: int segreg;
197: int m3;
198:
199: switch (ip1->i_type) {
200:
201: case ENTER:
202: pcdot[pcseg] = pc;
203: pcseg = ip1->i_seg;
204: pc = pcdot[pcseg];
205: if (pass != 0)
206: genseg(pcseg);
207: break;
208:
209: case BLOCK:
210: if ((length=ip1->i_len) != 0) {
211: if (pcseg == SBSS) {
212: pc += length;
213: if (pass != 0)
214: dot += length;
215: } else {
216: #if 0 /* i8086 outnzb() not implemented yet */
217: outnzb(length);
218: #else
219: do {
220: asmab(0);
221: } while (--length);
222: #endif
223: }
224: }
225: break;
226:
227: case ALIGN:
228: if ((pc&01) != 0) {
229: if (pcseg == SBSS) {
230: ++pc;
231: if (pass != 0)
232: ++dot;
233: } else
234: asmab(0);
235: }
236: break;
237:
238: case JUMP:
239: ip1->i_pc = pc;
240: ip1->i_pcseg = pcseg;
241: if ((sp=ip1->i_sp) == NULL) {
242: sp = llookup(ip1->i_labno, 0);
243: ip1->i_sp = sp;
244: }
245: if (pass != 0) {
246: if (sp==NULL || (sp->s_flag&S_DEF)==0)
247: cbotch("undef");
248: if (ip1->i_long == 0) {
249: if (sp->s_seg != ip1->i_pcseg)
250: cbotch("x seg #2");
251: disp = sp->s_value - pc - 2;
252: if (disp<-128 || disp>127)
253: cbotch("reach, disp=%d", disp);
254: }
255: }
256: opbits = opinfo[ip1->i_rel].op_opcode;
257: if (ip1->i_long == 0) {
258: asmab(opbits);
259: asmab(disp);
260: } else {
261: if (ip1->i_rel != ZJMP) {
262: asmab(opbits ^ 01);
263: asmab(03);
264: }
265: asmab(0xE9); /* Jump */
266: a1.a_mode = A_DIR;
267: a1.a_sp = sp;
268: a1.a_value = 0;
269: asmxw(&a1, 1);
270: }
271: break;
272:
273: case LLABEL:
274: if ((sp=ip1->i_sp) == NULL) {
275: sp = llookup(ip1->i_labno, 1);
276: ip1->i_sp = sp;
277: }
278: sp->s_seg = pcseg;
279: sp->s_value = pc;
280: break;
281:
282: case LLLINK:
283: if ((sp=ip1->i_sp) == NULL) {
284: sp = llookup(ip1->i_labno, 0);
285: ip1->i_sp = sp;
286: }
287: if (pass!=0 && (sp==NULL || (sp->s_flag&S_DEF)==0))
288: cbotch("undef");
289: a1.a_mode = A_DIR;
290: a1.a_sp = sp;
291: a1.a_value = 0;
292: asmxw(&a1, 0);
293: break;
294:
295: case CODE:
296: ip1->i_pc = pc;
297: ip1->i_pcseg = pcseg;
298: opcode = ip1->i_op;
299: opinfop = &opinfo[opcode];
300: opbits = opinfop->op_opcode;
301: switch (ostyle = opinfop->op_style) {
302:
303: case OF_INH2:
304: asmab(opbits);
305: asmab(0x0A);
306: break;
307:
308: case OF_INH:
309: asmab(opbits);
310: break;
311:
312: case OF_PUSH:
313: case OF_POP:
314: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
315: rn = ip1->i_af[0].a_mode&A_REGM;
316: if (isvariant(V80186)) {
317: if ((ostyle == OF_PUSH) && (m1 == A_IMM)) {
318: if (isshort(&ip1->i_af[0])) {
319: asmab(0x6A);
320: asmxb(&ip1->i_af[0], 0);
321: }
322: else {
323: asmab(0x68);
324: asmxw(&ip1->i_af[0], 0);
325: }
326: break;
327: }
328: }
329: if (m1 == A_SR) {
330: if (ostyle == OF_PUSH)
331: asmab(0x06 | (rn<<3));
332: else
333: asmab(0x07 | (rn<<3));
334: break;
335: }
336: if (m1 == A_WR) {
337: if (ostyle == OF_PUSH)
338: asmab(0x50 | rn);
339: else
340: asmab(0x58 | rn);
341: break;
342: }
343: if (ostyle == OF_PUSH)
344: asmgen(0xFF, 0x30, &ip1->i_af[0]);
345: else
346: asmgen(0x8F, 0x00, &ip1->i_af[0]);
347: break;
348:
349: case OF_SHR:
350: prefix = 0xD0 | (opbits&W);
351: opbits &= ~W;
352: if (ip1->i_af[1].a_mode == A_RCL)
353: prefix |= 0x02;
354: else if ((ip1->i_af[1].a_mode&A_AMOD) != A_IMM
355: || (notvariant(V80186) && ip1->i_af[1].a_value != 1)
356: || ip1->i_af[1].a_sp != NULL)
357: aerr(ip1);
358: if (isvariant(V80186)) {
359: disp = ip1->i_af[1].a_value;
360: if ((ip1->i_af[1].a_mode != A_RCL) && (disp != 1)) {
361: /* 286 shift immediate */
362: prefix &= 0xEF; /* Change 0xD0|W to 0xC0|W */
363: asmgen(prefix, opbits, &ip1->i_af[0]);
364: /* Be wary of shift counts > 16 */
365: asmab((disp <= 16) ? disp : 16);
366: break;
367: }
368: }
369: asmgen(prefix, opbits, &ip1->i_af[0]);
370: break;
371:
372: case OF_ICALL:
373: asmgen(0xFF, opbits, &ip1->i_af[0]);
374: break;
375:
376: case OF_CALL:
377: if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR)
378: aerr(ip1);
379: asmab(0xE8);
380: asmxw(&ip1->i_af[0], 1);
381: break;
382:
383: case OF_XCALL:
384: if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR)
385: aerr(ip1);
386: asmab(0x9A);
387: asmxw(&ip1->i_af[0], 0);
388: asmsb(&ip1->i_af[0]);
389: break;
390:
391: case OF_DOPS:
392: case OF_DOP:
393: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
394: m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX);
395: if (m2 == A_IMM) {
396: shortflag = 0;
397: if (isalax(&ip1->i_af[0])) {
398: /* Test[b] */
399: if (opbits == 0x85)
400: opbits = 0xA9;
401: else if (opbits == 0x84)
402: opbits = 0xA8;
403: else
404: opbits |= 0x04;
405: asmab(opbits);
406: } else {
407: /* Test[b] */
408: if (opbits==0x84 || opbits==0x85) {
409: regm = 0;
410: if (opbits == 0x84)
411: opbits = 0xF6;
412: else
413: opbits = 0xF7;
414: } else {
415: regm = opbits & 0x38;
416: opbits = (opbits&W)|0x80;
417: if (ostyle == OF_DOPS
418: && isshort(&ip1->i_af[1])) {
419: shortflag = 1;
420: opbits |= 0x02;
421: }
422: }
423: asmgen(opbits, regm, &ip1->i_af[0]);
424: }
425: if (shortflag || (opbits&W)==0)
426: asmxb(&ip1->i_af[1], 0);
427: else
428: asmxw(&ip1->i_af[1], 0);
429: break;
430: }
431: /* To reg */
432: if (m1==A_BR || m1==A_WR) {
433: /* Test[b] */
434: if (opbits!=0x84 && opbits!=0x85)
435: opbits |= 0x02; /* D */
436: asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3,
437: &ip1->i_af[1]);
438: break;
439: }
440: /* To mem */
441: asmgen(opbits, (ip1->i_af[1].a_mode&A_REGM)<<3,
442: &ip1->i_af[0]);
443: break;
444:
445: case OF_MUL3:
446: if (notvariant(V80186))
447: aerr(ip1);
448: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
449: m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX);
450: m3 = ip1->i_af[2].a_mode&(A_AMOD|A_PREFX);
451: if (m1 != A_WR || m3 != A_IMM)
452: aerr(ip1);
453: shortflag = 0;
454: if (isshort(&ip1->i_af[2])) {
455: shortflag = 1;
456: opbits |= 0x02; /* Change 0x69 to 0x6B */
457: }
458: asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3, &ip1->i_af[1]);
459: if (shortflag)
460: asmxb(&ip1->i_af[2], 0);
461: else
462: asmxw(&ip1->i_af[2], 0);
463: break;
464:
465: case OF_SOP:
466: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
467: prefix = ((opbits<0x10)?0xFE:0xF6) | (opbits&W);
468: opbits &= ~W;
469: if (prefix==0xFF && m1==A_WR) {
470: asmab(0x40 | opbits |
471: (ip1->i_af[0].a_mode&A_REGM));
472: break;
473: }
474: asmgen(prefix, opbits, &ip1->i_af[0]);
475: break;
476:
477: case OF_LEA:
478: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
479: m2 = ip1->i_af[1].a_mode&A_AMOD;
480: if (m1!=A_WR || (m2!=A_DIR && m2!=A_X))
481: aerr(ip1);
482: asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3,
483: &ip1->i_af[1]);
484: break;
485:
486: case OF_MOV:
487: m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
488: m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX);
489: if (m2 == A_IMM) {
490: if (m1 == A_BR) {
491: asmab(0xB0 |
492: (ip1->i_af[0].a_mode&A_REGM));
493: asmxb(&ip1->i_af[1], 0);
494: break;
495: }
496: if (m1 == A_WR) {
497: asmab(0xB8 |
498: (ip1->i_af[0].a_mode&A_REGM));
499: asmxw(&ip1->i_af[1], 0);
500: break;
501: }
502: /* To mem */
503: asmgen((0xC6 | (opbits&W)), 0, &ip1->i_af[0]);
504: if ((opbits&W) == 0)
505: asmxb(&ip1->i_af[1], 0);
506: else
507: asmxw(&ip1->i_af[1], 0);
508: break;
509: }
510: if (isalax(&ip1->i_af[0]) && m2==A_DIR) {
511: asmprefix(&ip1->i_af[1]);
512: asmab(0xA0 | (opbits&W));
513: asmxw(&ip1->i_af[1], 0);
514: break;
515: }
516: if (m1==A_DIR && isalax(&ip1->i_af[1])) {
517: asmprefix(&ip1->i_af[0]);
518: asmab(0xA2 | (opbits&W));
519: asmxw(&ip1->i_af[0], 0);
520: break;
521: }
522: if (m1 == A_SR) {
523: if (m2 != A_SR) {
524: asmgen(0x8E, (ip1->i_af[0].a_mode&A_REGM)<<3,
525: &ip1->i_af[1]);
526: }
527: else { /* Kludge MOV SR1, SR2
528: * into PUSH SR2, POP SR1.
529: * This should not happen but
530: * better safe than sorry...
531: */
532: asmab(0x06 | ((ip1->i_af[1].a_mode&A_REGM)<<3));
533: asmab(0x07 | ((ip1->i_af[0].a_mode&A_REGM)<<3));
534: }
535: }
536: else if (m2 == A_SR)
537: asmgen(0x8C, (ip1->i_af[1].a_mode&A_REGM)<<3,
538: &ip1->i_af[0]);
539: else if (m1==A_WR || m1==A_BR)
540: asmgen(opbits|D,
541: (ip1->i_af[0].a_mode&A_REGM)<<3,
542: &ip1->i_af[1]);
543: else
544: asmgen(opbits,
545: (ip1->i_af[1].a_mode&A_REGM)<<3,
546: &ip1->i_af[0]);
547: break;
548:
549: case OF_MUL:
550: prefix = 0xF6 | (opbits&W);
551: opbits &= ~W;
552: asmgen(prefix, opbits, &ip1->i_af[0]);
553: break;
554:
555: case OF_WORD:
556: case OF_BYTE:
557: case OF_LPTR:
558: case OF_GPTR:
559: if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR)
560: aerr(ip1);
561: if (ostyle == OF_BYTE)
562: asmxb(&ip1->i_af[0], 0);
563: else {
564: asmxw(&ip1->i_af[0], 0);
565: if (ostyle == OF_GPTR)
566: asmsb(&ip1->i_af[0]);
567: }
568: break;
569:
570: /*
571: * 8087 or 80287 floating point operations.
572: * See comments preceding "asmfwait()" below.
573: */
574: case OF_FWAIT:
575: asmfwait();
576: break;
577:
578: case OF_FD9:
579: asmfop(0xD9, 0);
580: asmab(opbits);
581: break;
582:
583: case OF_FDD:
584: asmfop(0xDD, 0);
585: asmab(opbits);
586: break;
587:
588: case OF_FDE:
589: asmfop(0xDE, 0);
590: asmab(opbits);
591: break;
592:
593: case OF_FRM:
594: escape = ESC | (opbits&0x07);
595: if ((ip1->i_af[0].a_mode&A_PREFX) != 0) {
596: prefix = ip1->i_af[0].a_mode&A_PREFX;
597: segreg = (prefix>>8) - 1;
598: asmfop(0x26|(segreg<<3), prefix);
599: asmab(escape);
600: } else
601: asmfop(escape, 0);
602: asmgen(-1, opbits&0x38, &ip1->i_af[0]);
603: break;
604:
605: default:
606: cbotch("cannot assemble %d", opcode);
607: }
608: }
609: }
610:
611: /*
612: * General output.
613: * Understands MOD/R/M bytes and all that.
614: * An opcode of -1 is a flag that says don't put
615: * out the opcode and treat a register address field as an error.
616: * It is used for the 8087.
617: * The r field is preshifted left by 3 bits.
618: */
619: asmgen(op, r, afp)
620: register AFIELD *afp;
621: {
622: SIGNEDADDRESS disp;
623: int mode, regm;
624:
625: if (op >= 0) {
626: asmprefix(afp);
627: asmab(op);
628: }
629: mode = afp->a_mode & A_AMOD;
630: regm = afp->a_mode & A_REGM;
631: if (mode==A_IMM || mode==A_SR)
632: cbotch("asmgen op=%d r=%d mode=%d regm=%d",
633: op, r, mode, regm);
634: if (mode==A_BR || mode==A_WR) {
635: if (op < 0)
636: cbotch("asmgen");
637: asmab(0xC0 | r | regm);
638: return;
639: }
640: if (mode == A_DIR) {
641: asmab(0x06 | r);
642: asmxw(afp, 0);
643: return;
644: }
645: if (afp->a_sp == NULL) {
646: disp = afp->a_value;
647: if (regm!=6 && disp==0) {
648: asmab(r | regm);
649: return;
650: }
651: if (disp>=-128 && disp<=127) {
652: asmab(0x40 | r | regm);
653: asmab(disp);
654: return;
655: }
656: }
657: asmab(0x80 | r | regm);
658: asmxw(afp, 0);
659: }
660:
661: /*
662: * Given an address field description,
663: * look at the A_PREFX field of the mode and
664: * output an escape prefix byte, if one is required.
665: * The codes assigned to the segment registers have been cleverly chosen
666: * so that code-1 is the right number to put in the prefix byte.
667: */
668: asmprefix(afp)
669: register AFIELD *afp;
670: {
671: register int segreg;
672:
673: if ((afp->a_mode&A_PREFX) != 0) {
674: segreg = ((afp->a_mode&A_PREFX)>>8) - 1;
675: asmab(0x26 | (segreg<<3));
676: }
677: }
678:
679: /*
680: * Output an absolute byte.
681: * Toss the byte away if this is not the second pass.
682: * Check for compiling code into the bss segment.
683: */
684: asmab(b)
685: {
686: if (pass != 0) {
687: berr();
688: outab(b);
689: }
690: ++pc;
691: }
692:
693: /*
694: * Output an absolute word.
695: * Toss the word away if this is not the second pass.
696: * Check for compiling code into the bss segment.
697: */
698: asmaw(w)
699: {
700: if (pass != 0) {
701: berr();
702: outaw(w);
703: }
704: pc += 2;
705: }
706:
707: /*
708: * Output a general byte.
709: * The 'afp' argument is a pointer to an 'afield'.
710: * The 'flag' is true for pc relative addressing.
711: */
712: asmxb(afp, flag)
713: register AFIELD *afp;
714: {
715: if (pass != 0) {
716: berr();
717: outxb(afp->a_sp, afp->a_value, flag);
718: }
719: ++pc;
720: }
721:
722: /*
723: * Output a general word.
724: * The 'afp' parameter is a pointer to an 'afield'.
725: * The 'flag' is true for pc relative addressing.
726: */
727: asmxw(afp, flag)
728: register AFIELD *afp;
729: {
730: if (pass != 0) {
731: berr();
732: outxw(afp->a_sp, afp->a_value, flag);
733: }
734: pc += 2;
735: }
736:
737: /*
738: * Output a segment base.
739: */
740: asmsb(afp)
741: register AFIELD *afp;
742: {
743: register SYM *sp;
744:
745: if (pass != 0) {
746: berr();
747: if ((sp=afp->a_sp) == NULL)
748: outaw(0);
749: else
750: outsb(sp);
751: }
752: pc += 2;
753: }
754:
755: /*
756: * Notes on 8087 and 80287 opcode generation:
757: * The 8086 does not check the coprocessor BUSY line when it encounters
758: * a coprocessor escape (an 8087 opcode).
759: * Therefore, an FWAIT must precede every 8087 opcode.
760: * Sequences which require coprocessor synchronization
761: * (e.g., awaiting completion of store from 8087 to 8086 memory)
762: * can include explicit FWAITs which do not precede 8087 ops.
763: * The 80286 checks its coprocessor BUSY line when it sees an 80287 opcode.
764: * Therefore, the 80287 does not require an FWAIT before each 80287 opcode,
765: * but explicit FWAITs are still required for synchronization.
766: *
767: * If EMUFIXUPS is true when the compiler is built,
768: * the OMF output writer targets the FWAIT which precedes an 8087 opcode
769: * with a magic "M:..." fixup;
770: * this happens only in the OMF output writer n1/i8086/outomf.c.
771: * The linker can then create objects which use either 8087 hardware
772: * or software floating point emulation. In the latter case, the
773: * linker changes the 8087 instructions into traps to the emulator.
774: *
775: * If the compile-time variant VEMU87 is set,
776: * the compiler writes "call emu87" before each 8087 opcode
777: * and suppresses the leading FWAIT.
778: * The emulator "emu87" can execute "fwait; ret" or replace "call emu87" with
779: * "nop; nop; fwait" if an 8087 is actually present at runtime.
780: */
781:
782: /*
783: * Output an explicit FWAIT opcode for the 8087.
784: * The byte will be fiddled by an M:_WT fixup #if EMUFIXUPS.
785: */
786: asmfwait()
787: {
788: hasfloat = 1;
789: if (isvariant(VEMU87)) {
790: asmemucall(); /* call emu87 */
791: return; /* and suppress the FWAIT */
792: }
793: if (pass != 0) {
794: berr();
795: outfb(WAIT);
796: }
797: ++pc;
798: }
799:
800: /*
801: * Output an 8087 opcode for the 8087.
802: * The "prefix" argument is just the A_PREFX code from the address.
803: * The opcode will be preceded by an FWAIT if necessary,
804: * and the FWAIT will be fiddled by an M:_W?S fixup #if EMUFIXUPS.
805: */
806: asmfop(op, prefix)
807: {
808: hasfloat = 1;
809: if (isvariant(VEMU87)) {
810: asmemucall(); /* call emu87 */
811: if (pass != 0)
812: outfb(op); /* and suppress FWAIT */
813: pc++;
814: return;
815: }
816: #if !EMUFIXUPS
817: if (isvariant(V80287)) {
818: if (pass != 0) {
819: berr();
820: outfb(op); /* also suppress FWAIT for 80287 */
821: }
822: pc++;
823: return;
824: }
825: #endif
826: if (pass != 0) {
827: berr();
828: outfw(op<<8|WAIT, prefix);
829: }
830: pc += 2;
831: }
832:
833: /*
834: * Assemble a call to the IEEE software floating point 8087 emulator.
835: */
836: asmemucall(){
837: if (pass != 0) {
838: berr();
839: outemucall();
840: }
841: pc += (isvariant(VSMALL)) ? 3 : 5;
842: }
843:
844: /*
845: * Output a call to the 8087 emulator.
846: * Called from above and from genepilog (for FWAIT in epilog).
847: */
848: outemucall(){
849: static SYM *emu87p;
850:
851: if (emu87p == NULL)
852: emu87p = glookup("emu87", 0);
853: if (isvariant(VSMALL)) { /* SMALL model */
854: outab(0xE8); /* near call */
855: outxw(emu87p, 0, 1); /* emu87, pc-relative */
856: } else { /* LARGE model */
857: outab(0x9A); /* far call */
858: outxw(emu87p, 0, 0); /* offset, absolute */
859: outsb(emu87p); /* segment */
860: }
861: }
862:
863: aerr(ip1)
864: register INS *ip1;
865: {
866: register SYM *sp;
867: register int i;
868:
869: printf("aerr: op=%d\n", ip1->i_op);
870: for (i=0; i<ip1->i_naddr; ++i) {
871: printf("Operand %d:", i);
872: printf(" mode=%04x", ip1->i_af[i].a_mode);
873: printf(" offs=%d", ip1->i_af[i].a_value);
874: if ((sp=ip1->i_af[i].a_sp) != NULL) {
875: if ((sp->s_flag&S_LABNO) != 0)
876: printf(" off L%d", sp->s_labno);
877: else
878: printf(" off %s", sp->s_id);
879: }
880: printf("\n");
881: }
882: cbotch("aerr");
883: }
884:
885: berr()
886: {
887: if (pcseg == SBSS)
888: cbotch("bss");
889: }
890:
891: isalax(afp)
892: register AFIELD *afp;
893: {
894: if (afp->a_mode==A_RAX || afp->a_mode==A_RAL)
895: return (1);
896: return (0);
897: }
898:
899: /*
900: * This routine checks if the argument AFIELD is a valid short word immediate,
901: * as used by the special s:w encoding on some instructions.
902: * True return if so.
903: * The legality of the mode and the fact that
904: * the AFIELD is an immediate have already been checked.
905: */
906: isshort(afp)
907: register AFIELD *afp;
908: {
909: register ADDRESS value;
910:
911: if (afp->a_sp == NULL) {
912: value = afp->a_value & 0xFF80; /* Top 9 */
913: if (value==0xFF80 || value==0x0000)
914: return (1);
915: }
916: return (0);
917: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.