|
|
1.1 root 1: static char *ID_swagen="@(#) swagen.c: 1.3 5/4/84";
2: #include <stdio.h>
3: #include "systems.h"
4: #include "symbols.h"
5: #include "instab.h"
6: #include "parse.h"
7: #include "gendefs.h"
8: #include "expand.h"
9: #include "expand2.h"
10:
11: #define MULOP 0
12: #define DIVOP 1
13: #define MODOP 2
14:
15: #define SIGNED 0
16: #define UNSIGNED 1
17:
18: extern upsymins
19: *lookup();
20: extern short
21: workaround, /* no software workaround flag */
22: opt; /* no optimize flag */
23: extern unsigned short
24: line; /* current line number */
25:
26: /*
27: * chip fix routines:
28: * The following three routines (mtoregcheck, intaft1check, and intaft2check)
29: * are chip fix routines for the Interrupt After TSTW bug.
30: *
31: * If an interupt is responded to after a certain sequence of instructions,
32: * (described below) the last instruction in the sequence may not set flags
33: * at all.
34: *
35: * Instruction Sequences which can cause problems:
36: * First Instruction:
37: * Type 1) Instruction which does a store to a register and whose
38: * last source operand comes from memory. This does not
39: * include any discontinuities, SWAPs, RESTORE, or instructions
40: * without destinations (ie. BIT, TST, CMP).
41: * Type 2) Instruction which does a store to a register and is a
42: * multiple cycle ALU operation (ie. multiply, divide, modulo,
43: * insert field, move negate).
44: * Second Instruction:
45: * Any instruction which is executed in 3 cycles. These are:
46: * TSTW %reg MOVW %reg,%reg MCOMW %reg %reg
47: * INCW %reg DECW %reg CLRW %reg
48: * The fix for thisproblem is to insert a NOP before the second instruction
49: * in the sequence.
50: *
51: */
52:
53: /* This routine will return a 1 so that an indicator may be set if
54: * the first instruction in the dangerous sequence is assembled.
55: */
56: mtoregcheck(src, dest)
57: register addrmode *src, *dest;
58: {
59: #ifdef CHIPFIX
60: if ((dest->admode == REGMD) && (src->admode == REGDFMD ||
61: src->admode == DSPMD || src->admode == DSPDFMD ||
62: src->admode == EXADMD || src->admode == ABSMD ||
63: src->admode == EXADDFMD || src->admode == ABSDFMD)
64: && workaround )
65: return(1);
66: else
67: return(0);
68: #else
69: return(0);
70: #endif
71: } /* mtoregcheck */
72:
73:
74: /* This routine will generate a NOP if the indicator is set, and
75: * the operand is a register operand.
76: */
77: intaft1check(opnd, mtoreg)
78: register addrmode *opnd;
79: short mtoreg;
80: {
81: #ifdef CHIPFIX
82: instr *newins;
83: if (mtoreg != 1)
84: return;
85: if ( (opnd->admode == REGMD) && workaround ) {
86: newins = (*lookup("NOP",N_INSTALL,MNEMON)).itp;
87: generate(newins->nbits, NOACTION, newins->opcode, NULLSYM);
88: }
89: #endif
90: } /* intaft1check */
91:
92:
93: /* This routine will generate a NOP if the indicator is set, and
94: * both of the operands are register operands.
95: */
96: intaft2check(opnd1, opnd2, mtoreg)
97: register addrmode *opnd1, *opnd2;
98: short mtoreg;
99: {
100: #ifdef CHIPFIX
101: instr *newins;
102: if (mtoreg != 1)
103: return;
104: if ((opnd1->admode == REGMD) && (opnd2->admode == REGMD &&
105: workaround)) {
106: newins = (*lookup("NOP",N_INSTALL,MNEMON)).itp;
107: generate(newins->nbits, NOACTION, newins->opcode, NULLSYM);
108: }
109: #endif
110: } /* intaft2check */
111:
112:
113: /*
114: * chip fix routine: Due to pipelining on the cpu chip
115: * it is possible for the chip to have the "next" instruction
116: * almost completely executed while it is waiting for the memory
117: * write of the "current" instr. to be completed, even executed
118: * to the point where the PC is incremented past the "next" instr.
119: * If an interrupt occurs in a situation like this then the PC
120: * will be restored to one past the "next" instr, thereby, in effect,
121: * skipping one instr. The fix for this is to place a NOP after
122: * every instr. that does a memory write, except for:
123: * CALL, call, SAVE, save, PUSHW, pushw, PUSHAW, pushaw
124: * These don't need the NOP padding.
125: */
126: pcintcheck(insptr, dest)
127: register instr *insptr;
128: register addrmode *dest;
129: {
130: #ifdef CHIPFIX
131: instr *newins;
132:
133: if ( (dest->admode == DSPMD || dest->admode == DSPDFMD ||
134: dest->admode == EXADMD || dest->admode == ABSMD ||
135: dest->admode == EXADDFMD || dest->admode == ABSDFMD ||
136: dest->admode == REGDFMD) && (workaround) ) {
137:
138: newins = (*lookup("NOP",N_INSTALL,MNEMON)).itp;
139: generate(newins->nbits,NOACTION,newins->opcode,NULLSYM);
140: }
141: #endif
142: } /* pcintcheck */
143:
144: #if 0
145: /* The following routine is ifdef'ed out because it is not
146: * needed in DBO Mask 2 chips.
147: */
148: /*
149: * chip fix routine: if one of the following instructions:
150: * MUL[BHW]3, DIV[BHW]3, MOD[BHW]3
151: * occurs and, during execution, the result from the first two
152: * operands is computed before the third (destination) operand
153: * has been latched and decoded then the CPU will hang.
154: * This problem is fixed with the following mapping:
155: *
156: * MULX3, DIVX3, MODX3 is mapped into
157: *
158: * pushYX arg1
159: * if arg2 is %sp
160: * subw3 &4, %sp, marg3
161: * else
162: * movX marg2, marg3
163: * "offending instr"2 {Z}spoff(%sp), marg3
164: * SUBW2 &4, %sp
165: * TSTX {Z}arg3
166: *
167: * where: X = B, H, or W
168: * Y = z (zero extend) for bytes
169: * b (bit extend) for halfs
170: * Z = user specified expand byte
171: * marg[2|3] indicates arg[2|3] has been
172: * modified if it references the stack
173: * pointer. (The first instruction in
174: * the mapping is a push which changes
175: * the stack pointer.)
176: * spoff is -4L if X = W
177: * is -2L if X = H
178: * is -1L if X = B
179: */
180: trimulcheck(insptr, arg1, arg2, arg3)
181: register instr *insptr;
182: register addrmode *arg1, *arg2, *arg3;
183: {
184: #ifdef CHIPFIX
185: instr *newins, *movins, *tstins;
186: short usrexp1, usrexp2, usrexp3, adjarg3, otype;
187: long spoffset;
188:
189: /* Save user specified expand bytes (if there are any)
190: * so that we can push arg1 on the stack using our own
191: * expand byte
192: */
193: usrexp1 = arg1->newtype;
194: usrexp2 = arg2->newtype;
195: usrexp3 = arg3->newtype;
196: /* check if USER specified an expand byte in an IS25 instruction */
197: if (insptr->tag & IS25) {
198: if (( usrexp1 != NOTYPE) || (usrexp2 != NOTYPE) || (usrexp3 != NOTYPE))
199: yyerror("Expand byte invalid in IS25 instruction");
200: }
201: arg1->newtype = NOTYPE;
202:
203: /* PUSHYX arg1
204: *
205: * Generate push instruction. Also look up the correct forms
206: * of the MOV and TST instructions.
207: */
208: otype = optype(insptr->tag,1);
209: switch (otype) {
210: case 0: newins = (*lookup("pushzb",N_INSTALL,MNEMON)).itp; /* BYTE */
211: pushopgen(newins, arg1);
212: movins = (*lookup("MOVB",N_INSTALL,MNEMON)).itp;
213: tstins = (*lookup("TSTB",N_INSTALL,MNEMON)).itp;
214: spoffset = -1L;
215: break;
216: case 1: newins = (*lookup("pushbh",N_INSTALL,MNEMON)).itp; /* HALF */
217: pushopgen(newins, arg1);
218: movins = (*lookup("MOVH",N_INSTALL,MNEMON)).itp;
219: tstins = (*lookup("TSTH",N_INSTALL,MNEMON)).itp;
220: spoffset = -2L;
221: break;
222: case 2: newins = (*lookup("pushw",N_INSTALL,MNEMON)).itp; /* WORD */
223: generate (newins->nbits, NOACTION, newins->opcode, NULLSYM);
224: addrgen (newins, arg1, NOTYPE, 1);
225: movins = (*lookup("MOVW",N_INSTALL,MNEMON)).itp;
226: tstins = (*lookup("TSTW",N_INSTALL,MNEMON)).itp;
227: spoffset = -4L;
228: break;
229: }
230:
231: /* adjust arg3 if it references the stack pointer */
232: adjarg3 = 0;
233: if (((arg3->admode == DSPMD) || (arg3->admode == DSPDFMD)
234: || (arg3->admode == REGDFMD)) && (arg3->adreg == SPREG)) {
235: adjarg3 = 1;
236: arg3->adexpr.expval -= 4L;
237: }
238: if ((arg2->admode == REGMD) && (arg2->adreg == SPREG)) {
239: /* SUBW3 &4,%sp,marg3 */
240: movins = (*lookup("SUBW3",N_INSTALL,MNEMON)).itp;
241: generate(movins->nbits, NOACTION, movins->opcode, NULLSYM);
242: generate(8, NOACTION, 0x4L, NULLSYM);
243: generate(8, NOACTION, (long)((CREGMD<<4)|SPREG), NULLSYM);
244: addrgen(movins, arg3, NOTYPE, 3);
245: }
246: else {
247: /* adjust arg2 if it references the stack pointer */
248: if (((arg2->admode == DSPMD) || (arg2->admode == DSPDFMD)
249: || (arg3->admode == REGDFMD)) && (arg2->adreg == SPREG))
250: arg2->adexpr.expval -= 4L;
251:
252: /* MOVX marg2,marg3 */
253: generate(movins->nbits, NOACTION, movins->opcode, NULLSYM);
254: if (insptr->name[0] == 'u')
255: generate(8, NOACTION, (long)((CEXPAND<<4)|UWORD), NULLSYM);
256: else if (usrexp2 == NOTYPE)
257: arg2->newtype = usrexp1;
258: addrgen(movins, arg2, NOTYPE, 1);
259: addrgen(movins, arg3, NOTYPE, 2);
260: }
261: pcintcheck(movins, arg3);
262:
263: /* <instr>X2 {expand}spoff(%sp),marg3 */
264: switch ((int)insptr->opcode) {
265: case 0xe4: newins = (*lookup("MODW2",N_INSTALL,MNEMON)).itp;
266: break;
267: case 0xe6: newins = (*lookup("MODH2",N_INSTALL,MNEMON)).itp;
268: break;
269: case 0xe7: newins = (*lookup("MODB2",N_INSTALL,MNEMON)).itp;
270: break;
271: case 0xe8: newins = (*lookup("MULW2",N_INSTALL,MNEMON)).itp;
272: break;
273: case 0xea: newins = (*lookup("MULH2",N_INSTALL,MNEMON)).itp;
274: break;
275: case 0xeb: newins = (*lookup("MULB2",N_INSTALL,MNEMON)).itp;
276: break;
277: case 0xec: newins = (*lookup("DIVW2",N_INSTALL,MNEMON)).itp;
278: break;
279: case 0xee: newins = (*lookup("DIVH2",N_INSTALL,MNEMON)).itp;
280: break;
281: case 0xef: newins = (*lookup("DIVB2",N_INSTALL,MNEMON)).itp;
282: break;
283: }
284: generate(newins->nbits, NOACTION, newins->opcode, NULLSYM);
285: if (insptr->name[0] == 'u')
286: generate(8,NOACTION,(long)((CEXPAND<<4)|UWORD),NULLSYM);
287: else
288: if (usrexp1 != NOTYPE)
289: generate(8,NOACTION,(long)((CEXPAND<<4)|usrexp1),NULLSYM);
290:
291: generate(8, NOACTION, (long)((CBDSPMD<<4)|SPREG), NULLSYM);
292: generate(8, NOACTION, spoffset, NULLSYM);
293: arg3->newtype = usrexp2;
294: addrgen(newins, arg3, NOTYPE, 2);
295: pcintcheck(newins, arg3);
296:
297: /* SUBW2 &4,%sp */
298: newins = (*lookup("SUBW2",N_INSTALL,MNEMON)).itp;
299: generate(newins->nbits, NOACTION, newins->opcode, NULLSYM);
300: generate(8, NOACTION, 0x4L, NULLSYM);
301: generate(8, NOACTION, (long)((CREGMD<<4)|SPREG), NULLSYM);
302:
303: /* TSTX arg3
304: * This instruction is generated in order to restore the flag settings
305: * of the mul, div, or mod instruction.
306: *
307: * If arg3 was adjusted because of a stack reference it must now
308: * be readjusted.
309: */
310: if (adjarg3 != 0)
311: arg3->adexpr.expval += 4L;
312: generate(tstins->nbits, NOACTION, tstins->opcode, NULLSYM);
313: if (insptr->name[0] == 'u')
314: arg3->newtype = UWORD;
315: else if (usrexp3 != NOTYPE)
316: arg3->newtype = usrexp3;
317: else if (usrexp2 != NOTYPE)
318: arg3->newtype = usrexp2;
319: else
320: arg3->newtype = usrexp1;
321: addrgen(tstins, arg3, NOTYPE, 1);
322: #endif
323: } /* trimulcheck */
324: #endif
325:
326: /*
327: * chip fix routine: if the psw register is used as the source of
328: * an instruction, the flag values may not be set yet from the
329: * previous instruction due to a timing problem. If the instruction
330: * is preceded by a NOP then the bits have time to settle and all
331: * is well.
332: * This chip fix routine will only fix IS25 instructions, BELLMAC-32B
333: * instructions are left untouched.
334: */
335: pswcheck( insptr, addr)
336: register instr *insptr;
337: register addrmode *addr;
338: {
339: instr *newins;
340:
341: if ( (addr->admode == REGMD) && (addr->adreg == PSWREG) ) {
342: newins = (*lookup("NOP",N_INSTALL,MNEMON)).itp;
343: generate(newins->nbits,NOACTION,newins->opcode,NULLSYM);
344: return(0); /* indicate that NOP was generated */
345: } else {
346: return(1); /* NOP not needed */
347: }
348: }
349:
350: #if M32RSTFIX
351: /*
352: * The following routine is a workaround for the
353: * RESTORE chip bug.
354: *
355: * The RESTORE instruction will be mapped into the
356: * following sequence of instructions.
357: *
358: * RESTORE %rX ===> MOVAW -Y(%fp), %sp
359: * POPW %r8
360: * POPW %rZ
361: * .
362: * .
363: * POPW %rX
364: * POPW %fp
365: *
366: * where:
367: * Y is 4 * (3 - X) (ie. 12-4X )
368: * Z is Y - 1
369: *
370: * and if %rW is %fp then the sequence is the following:
371: * RESTORE %fp ===> MOVAW -24(%fp),%sp
372: * POPW %fp
373: */
374: restorefix(num)
375: register addrmode *num;
376: {
377: register int numregs, rnum;
378: instr *newins;
379: static addrmode dispfp = {NOTYPE, DSPMD,FPREG,{ABS,NULLSYM,1L}};
380:
381: if (num->admode == REGMD)
382: numregs = 9 - num->adreg;
383: if (num->admode == IMMD)
384: numregs = num->adexpr.expval;
385: newins = (*lookup("MOVAW",N_INSTALL,MNEMON)).itp;
386: generate(newins->nbits,NOACTION,newins->opcode,NULLSYM);
387: dispfp.adexpr.expval = -24 + (4 * numregs);
388: addrgen(newins,&dispfp,NOTYPE,1);
389: generate(8,NOACTION,(long)(CREGMD<<4|SPREG),NULLSYM);
390: /* generate MOVAW (12-4X)(%fp),%sp */
391: newins = (*lookup("POPW",N_INSTALL,MNEMON)).itp;
392: for (rnum=8; numregs > 0; numregs--,rnum--) {
393: /* generate POPW with the register being 9-numreg */
394: generate(newins->nbits,NOACTION,newins->opcode,NULLSYM);
395: generate(8,NOACTION,(long)(CREGMD<<4|rnum),NULLSYM);
396: }
397: generate(newins->nbits,NOACTION,newins->opcode,NULLSYM);
398: generate(8,NOACTION,(long)(CREGMD<<4|FPREG),NULLSYM);
399: }
400: #endif /* M32RSTFIX */
401:
402: flags(flag)
403: char flag;
404: {
405: char errmsg[28];
406:
407: switch(flag) {
408:
409: default:
410: sprintf(errmsg,"Illegal flag (%c) - ignored",flag);
411: werror(errmsg);
412: break;
413: } /* switch */
414: } /* flags */
415:
416: #if MLDVFIX
417: /*
418: * Number: er 1
419: *
420: * Name: Flag Setting for Multiply/Divide
421: *
422: * Description: There are two situations where the CPU sets the N & V
423: * flags but not the Z flag, even though the result is zero.
424: * The source operands must be of opposite signs, with
425: * an unsigned destination. For multiply one source must be 0.
426: * For divide the absolute value of the numerator must be
427: * non-zero and greater than the absolute value of the denominator.
428: *
429: * Resolution: generate a warning diagnostic
430: *
431: */
432:
433: mulchk3(insptr,addr1,addr2,addr3)
434: instr *
435: insptr;
436: addrmode *
437: addr1;
438: addrmode *
439: addr2;
440: addrmode *
441: addr3;
442: {
443: if (compare(insptr->name, "MULB3") == EQUAL ||
444: compare(insptr->name, "MULH3") == EQUAL ||
445: compare(insptr->name, "MULW3") == EQUAL ||
446: compare(insptr->name, "DIVB3") == EQUAL ||
447: compare(insptr->name, "DIVH3") == EQUAL ||
448: compare(insptr->name, "DIVW3") == EQUAL ||
449: compare(insptr->name, "MULB2") == EQUAL ||
450: compare(insptr->name, "MULH2") == EQUAL ||
451: compare(insptr->name, "MULW2") == EQUAL ||
452: compare(insptr->name, "DIVB2") == EQUAL ||
453: compare(insptr->name, "DIVH2") == EQUAL ||
454: compare(insptr->name, "DIVW2") == EQUAL)
455: {
456: int
457: type1, type2, type3;
458:
459: switch (addr1->newtype)
460: {
461: case SBYTE:
462: case SHALF:
463: case SWORD:
464: type1 = SIGNED;
465: break;
466: case UBYTE:
467: case UHALF:
468: case UWORD:
469: type1 = UNSIGNED;
470: break;
471: case NOTYPE:
472: switch(optype(insptr->tag,1))
473: {
474: case 0: /* byte */
475: type1 = UNSIGNED;
476: break;
477: case 1: /* half */
478: type1 = SIGNED;
479: break;
480: case 2: /* word */
481: type1 = SIGNED;
482: break;
483: }
484: }
485: switch (addr2->newtype)
486: {
487: case SBYTE:
488: case SHALF:
489: case SWORD:
490: type2 = SIGNED;
491: break;
492: case UBYTE:
493: case UHALF:
494: case UWORD:
495: type2 = UNSIGNED;
496: break;
497: case NOTYPE:
498: type2 = type1;
499: }
500: switch (addr3->newtype)
501: {
502: case SBYTE:
503: case SHALF:
504: case SWORD:
505: type3 = SIGNED;
506: break;
507: case UBYTE:
508: case UHALF:
509: case UWORD:
510: type3 = UNSIGNED;
511: break;
512: case NOTYPE:
513: type3 = type2;
514: }
515: if ( (addr1->admode == IMMD) && (addr1->adexpr.expval < 0 ) )
516: type1 = SIGNED;
517: if ( (addr2->admode == IMMD) && (addr2->adexpr.expval < 0 ) )
518: type2 = SIGNED;
519:
520: if ( ( ( type1 == SIGNED ) || ( type2 == SIGNED ) ) &&
521: ( type3 == UNSIGNED ) )
522:
523: {
524: werror("Mixed signs with unsignd destination can cause erroneous flags");
525: }
526: }
527: } /* mulchk3 */
528:
529: #endif
530:
531: #if ER21FIX
532:
533: er21(insptr,addr1,addr2,addr3)
534: instr *
535: insptr;
536: addrmode *
537: addr1;
538: addrmode *
539: addr2;
540: addrmode *
541: addr3;
542: {
543: if (compare(insptr->name, "MODB3") == EQUAL ||
544: compare(insptr->name, "MODH3") == EQUAL ||
545: compare(insptr->name, "MODW3") == EQUAL )
546: {
547: int
548: type1, type2, type3;
549:
550: switch (addr1->newtype)
551: {
552: case SBYTE:
553: case SHALF:
554: case SWORD:
555: type1 = SIGNED;
556: break;
557: case UBYTE:
558: case UHALF:
559: case UWORD:
560: type1 = UNSIGNED;
561: break;
562: case NOTYPE:
563: switch(optype(insptr->tag,1))
564: {
565: case 0: /* byte */
566: type1 = UNSIGNED;
567: break;
568: case 1: /* half */
569: type1 = SIGNED;
570: break;
571: case 2: /* word */
572: type1 = SIGNED;
573: break;
574: }
575: }
576: switch (addr2->newtype)
577: {
578: case SBYTE:
579: case SHALF:
580: case SWORD:
581: type2 = SIGNED;
582: break;
583: case UBYTE:
584: case UHALF:
585: case UWORD:
586: type2 = UNSIGNED;
587: break;
588: case NOTYPE:
589: type2 = type1;
590: }
591: switch (addr3->newtype)
592: {
593: case SBYTE:
594: case SHALF:
595: case SWORD:
596: type3 = SIGNED;
597: break;
598: case UBYTE:
599: case UHALF:
600: case UWORD:
601: type3 = UNSIGNED;
602: break;
603: case NOTYPE:
604: type3 = type2;
605: }
606: if ( (addr1->admode == IMMD) && (addr1->adexpr.expval < 0 ) )
607: type1 = SIGNED;
608: if ( (addr2->admode == IMMD) && (addr2->adexpr.expval < 0 ) )
609: type2 = SIGNED;
610:
611: if ( ( type2 == SIGNED ) && ( type3 == UNSIGNED ) )
612: {
613: werror
614: ("Mixed signs with unsignd destination can cause erroneous flags");
615: }
616: }
617: } /* er21 */
618:
619: #endif
620:
621: #if ER16FIX
622:
623: decrstk(i)
624: int
625: i;
626: { /* decrstk */
627: instr *
628: tmpins;
629:
630: tmpins = (*lookup("SUBW2",N_INSTALL,MNEMON)).itp;
631: generate(8, NOACTION, tmpins->opcode, NULLSYM);
632: generate(8, NOACTION, i, NULLSYM);
633: generate(8, NOACTION, (long)((CREGMD<<4)|SPREG), NULLSYM);
634: } /* decrstk */
635:
636: incrstk(i)
637: int
638: i;
639: { /* incrstk */
640: instr *
641: tmpins;
642:
643: tmpins = (*lookup("ADDW2",N_INSTALL,MNEMON)).itp;
644: generate(8, NOACTION, tmpins->opcode, NULLSYM);
645: generate(8, NOACTION, i, NULLSYM);
646: generate(8, NOACTION, (long)((CREGMD<<4)|SPREG), NULLSYM);
647: } /* incrstk */
648:
649: copyadd(addr1,addr2)
650: addrmode *
651: addr1;
652: addrmode *
653: addr2;
654: { /* copyadd */
655: addr2->newtype = addr1->newtype;
656: addr2->admode = addr1->admode;
657: addr2->adreg = addr1->adreg;
658: addr2->adexpr.exptype = addr1->adexpr.exptype;
659: addr2->adexpr.symptr = addr1->adexpr.symptr;
660: addr2->adexpr.expval = addr1->adexpr.expval;
661: addr2->adexpr.fdexpval2 = addr1->adexpr.fdexpval2;
662: addr2->expspec = addr1->expspec;
663: } /* copyadd */
664:
665: gen2(op,addr1,addr2)
666: char *
667: op;
668: addrmode *
669: addr1;
670: addrmode *
671: addr2;
672: { /* gen2 */
673: instr *
674: tmpins;
675:
676: tmpins = (*lookup(op,N_INSTALL,MNEMON)).itp;
677: generate (tmpins->nbits, NOACTION, tmpins->opcode, NULLSYM);
678: addrgen(tmpins,addr1,NOTYPE,1);
679: addrgen(tmpins,addr2,NOTYPE,2);
680: } /* gen2 */
681:
682: er16fix(insptr, arg1, arg2, arg3)
683: instr *
684: insptr;
685: addrmode *
686: arg1;
687: addrmode *
688: arg2;
689: addrmode *
690: arg3;
691: { /* er16fix */
692: addrmode
693: c_tmp1;
694: addrmode *
695: c_arg1 = &c_tmp1;
696: addrmode
697: c_tmp2;
698: addrmode *
699: c_arg2 = &c_tmp2;
700: addrmode
701: c_tmp3;
702: addrmode *
703: c_arg3 = &c_tmp3;
704: instr *
705: tmpins;
706:
707: if ( ! ( (compare(insptr->name, "MULH3") == EQUAL ) ||
708: (compare(insptr->name, "MULB3") == EQUAL ) ||
709: (compare(insptr->name, "MULW3") == EQUAL ) ||
710: (compare(insptr->name, "DIVH3") == EQUAL ) ||
711: (compare(insptr->name, "DIVB3") == EQUAL ) ||
712: (compare(insptr->name, "DIVW3") == EQUAL ) ||
713: (compare(insptr->name, "MODH3") == EQUAL ) ||
714: (compare(insptr->name, "MODB3") == EQUAL ) ||
715: (compare(insptr->name, "MODW3") == EQUAL ) ||
716: (compare(insptr->name, "mulw3") == EQUAL ) ||
717: (compare(insptr->name, "umulw3") == EQUAL ) ||
718: (compare(insptr->name, "divw3") == EQUAL ) ||
719: (compare(insptr->name, "udivw3") == EQUAL ) ||
720: (compare(insptr->name, "modw3") == EQUAL ) ||
721: (compare(insptr->name, "umodw3") == EQUAL ) ) )
722: return(0);
723:
724: if( ! ( (er16chk(arg1,arg3)) || (er16chk(arg2,arg3)) ) )
725: return(0);
726: if( ! workaround )
727: return(0);
728:
729: if ( compare(insptr->name, "mulw3") == EQUAL)
730: insptr = (*lookup("MULW3",N_INSTALL,MNEMON)).itp;
731: if (compare(insptr->name, "umulw3") == EQUAL )
732: {
733: insptr = (*lookup("MULW3",N_INSTALL,MNEMON)).itp;
734: arg1->newtype = UWORD;
735: }
736:
737: if ( compare(insptr->name, "divw3") == EQUAL)
738: insptr = (*lookup("DIVW3",N_INSTALL,MNEMON)).itp;
739: if (compare(insptr->name, "udivw3") == EQUAL )
740: {
741: insptr = (*lookup("DIVW3",N_INSTALL,MNEMON)).itp;
742: arg1->newtype = UWORD;
743: }
744:
745: if ( compare(insptr->name, "modw3") == EQUAL)
746: insptr = (*lookup("MODW3",N_INSTALL,MNEMON)).itp;
747: if (compare(insptr->name, "umodw3") == EQUAL )
748: {
749: insptr = (*lookup("MODW3",N_INSTALL,MNEMON)).itp;
750: arg1->newtype = UWORD;
751: }
752:
753: incrstk(12);
754:
755: if (arg1->newtype == NOTYPE)
756: switch(optype(insptr->tag,1))
757: {
758: case 0: /* byte */
759: arg1->newtype = UBYTE;
760: break;
761: case 1: /* half */
762: arg1->newtype = SHALF;
763: break;
764: case 2: /* word */
765: arg1->newtype = SWORD;
766: break;
767: }
768: if (arg2->newtype == NOTYPE)
769: arg2->newtype = arg1->newtype;
770: if (arg3->newtype == NOTYPE)
771: arg3->newtype = arg2->newtype;
772:
773: copyadd(arg1,c_arg1);
774: copyadd(arg2,c_arg2);
775: copyadd(arg3,c_arg3);
776:
777: if ( ( (c_arg1->admode == DSPMD ) ||
778: (c_arg1->admode == DSPDFMD) ||
779: (c_arg1->admode == REGDFMD) ) &&
780: ( c_arg1->adreg == SPREG ) )
781: c_arg1->adexpr.expval -= 12;
782: if ( (c_arg1->admode == REGMD) && (c_arg1->adreg == SPREG) )
783: {
784: /* SUBW3 &12,%sp,c_arg1 */
785: c_arg1->admode = DSPMD;
786: c_arg1->adexpr.exptype = ABS;
787: c_arg1->adexpr.symptr = NULLSYM;
788: c_arg1->adexpr.expval = -12;
789:
790: tmpins = (*lookup("SUBW3",N_INSTALL,MNEMON)).itp;
791: generate(tmpins->nbits, NOACTION, tmpins->opcode, NULLSYM);
792: generate(8, NOACTION, 0x12L, NULLSYM);
793: generate(8, NOACTION, (long)((CREGMD<<4)|SPREG), NULLSYM);
794: addrgen(tmpins, c_arg1, NOTYPE, 3);
795: }
796:
797: if ( ( (c_arg2->admode == DSPMD ) ||
798: (c_arg2->admode == DSPDFMD) ||
799: (c_arg2->admode == REGDFMD) ) &&
800: ( c_arg2->adreg == SPREG ) )
801: c_arg2->adexpr.expval -= 12;
802: if ( (c_arg2->admode == REGMD) && (c_arg2->adreg == SPREG) )
803: {
804: /* SUBW3 &12,%sp,c_arg2 */
805: c_arg2->admode = DSPMD;
806: c_arg2->adexpr.exptype = ABS;
807: c_arg2->adexpr.symptr = NULLSYM;
808: c_arg2->adexpr.expval = -8;
809:
810:
811: tmpins = (*lookup("SUBW3",N_INSTALL,MNEMON)).itp;
812: generate(tmpins->nbits, NOACTION, tmpins->opcode, NULLSYM);
813: generate(8, NOACTION, 0x12L, NULLSYM);
814: generate(8, NOACTION, (long)((CREGMD<<4)|SPREG), NULLSYM);
815: addrgen(tmpins, c_arg2, NOTYPE, 3);
816: }
817:
818: c_arg3->admode = DSPMD;
819: c_arg3->adreg = SPREG;
820: c_arg3->adexpr.exptype = ABS;
821: c_arg3->adexpr.symptr = NULLSYM;
822: c_arg3->adexpr.expval = -4;
823:
824: generate(8,NOACTION,insptr->opcode,NULLSYM);
825: addrgen(insptr,c_arg1,NOTYPE,1);
826: addrgen(insptr,c_arg2,NOTYPE,2);
827: addrgen(insptr,c_arg3,NOTYPE,3);
828:
829: if ( ( (arg3->admode == DSPMD ) ||
830: (arg3->admode == DSPDFMD) ||
831: (arg3->admode == REGDFMD) ) &&
832: ( arg3->adreg == SPREG ) )
833: arg3->adexpr.expval -= 12;
834:
835: gen2("MOVW",c_arg3,arg3);
836:
837: decrstk(12);
838:
839: c_arg3->adexpr.expval = 0;
840: generate(8,NOACTION,insptr->opcode,NULLSYM);
841: addrgen(insptr,arg1,NOTYPE,1);
842: addrgen(insptr,arg2,NOTYPE,2);
843: addrgen(insptr,c_arg3,NOTYPE,3);
844:
845: return(1);
846:
847: } /* er16fix */
848:
849:
850: er16chk(addr1,addr2)
851: addrmode
852: *addr1;
853: addrmode
854: *addr2;
855: { /* er16chk */
856: switch(addr2->admode)
857: { /* switch(addr2->admode) */
858: case REGDFMD: /* register deferred mode */
859: switch(addr1->admode)
860: {
861: case DSPMD: /* displacement mode */
862: if ( ( addr1->adreg == addr2->adreg ) &&
863: ( abs(addr1->adexpr.expval - 0) >= 4 ) )
864: return(NO);
865: break;
866: case REGMD: /* register mode */
867: return(NO);
868: }
869: break;
870: case DSPMD: /* displacement mode */
871: switch(addr1->admode)
872: {
873: case DSPMD: /* displacement mode */
874: if ( ( addr1->adreg == addr2->adreg ) &&
875: ( abs(addr1->adexpr.expval - addr2->adexpr.expval) >=4 ) )
876: return(NO);
877: break;
878: case REGMD: /* register mode */
879: return(NO);
880: }
881: break;
882: case DSPDFMD: /* displacement deferred mode */
883: switch(addr1->admode)
884: {
885: case REGMD: /* register mode */
886: return(NO);
887: }
888: break;
889: case EXADMD: /* external address mode */
890: switch(addr1->admode)
891: {
892: case REGMD: /* register mode */
893: return(NO);
894: }
895: break;
896: case ABSMD: /* absolute address mode */
897: switch(addr1->admode)
898: {
899: case ABSMD: /* absolute address mode */
900: if ( abs(addr1->adexpr.expval - addr2->adexpr.expval) >= 4 )
901: return(NO);
902: break;
903: case REGMD: /* register mode */
904: return(NO);
905: }
906: break;
907: case EXADDFMD: /* external address deferred mode (PC relative deferred) */
908: switch(addr1->admode)
909: {
910: case REGMD: /* register mode */
911: return(NO);
912: }
913: break;
914: case ABSDFMD: /* absolute address deferred mode */
915: switch(addr1->admode)
916: {
917: case REGMD: /* register mode */
918: return(NO);
919: }
920: break;
921: case IMMD: /* immediate mode */
922: return(NO);
923: case REGMD: /* register mode */
924: return(NO);
925: } /* switch(addr2->admode) */
926: return(YES);
927: } /* er16chk */
928:
929: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.