- }
- }
- locp = cch->chptr + (loc - cch->chloc);
-
- eattr = 0;
-
- // Compute expression/symbol value and attribs
- if(w & FU_EXPR) { // Complex expression
- i = *fup.wp++;
- if(evexpr(fup.tk, &eval, &eattr, &esym) != OK) {
- fup.lp += i;
- continue;
- }
- fup.lp += i;
- } else { // Simple symbol
- sy = *fup.sy++;
- eattr = sy->sattr;
- if(eattr & DEFINED)
- eval = sy->svalue;
- else eval = 0;
-
- if((eattr & (GLOBAL|DEFINED)) == GLOBAL)
- esym = sy;
- }
- tdb = (WORD)(eattr & TDB);
- // If the expression is undefined and no external symbol is involved, then it's an error.
- if(!(eattr & DEFINED) && esym == NULL) {
- error(undef_error);
- continue;
- }
-
-
- if(((w & 0x0F00) == FU_MOVEI) && esym)
- esym->sattre |= RISCSYM;
-
- // Do the fixup
- //
- // If a PC-relative fixup is undefined, its value is *not* subtracted from the location
- // (that will happen in the linker when the external reference is resolved).
- //
- // MWC expects PC-relative things to have the LOC subtracted from the value, if the
- // value is external (that is, undefined at this point).
- //
- // PC-relative fixups must be DEFINED and either in the same section (whereupon the
- // subtraction takes place) or ABS (with no subtract).
- if(w & FU_PCREL) {
- if(eattr & DEFINED) {
- if(tdb == sno) eval -= (VALUE)loc;
- else if(tdb) {
- error("PC-relative expr across sections");
- continue;
- }
-
- if(sbra_flag && (w & FU_LBRA) && (eval + 0x80 < 0x100))
- warn("unoptimized short branch");
- } else
- if(obj_format == MWC) eval -= (VALUE)loc;
-
- tdb = 0;
- eattr &= ~TDB;
- }
-
- // Do fixup classes
- switch((int)(w & FUMASK)) {
- // FU_BBRA fixes up a one-byte branch offset.
- case FU_BBRA:
- if(!(eattr & DEFINED)) {
- error("external short branch");
- continue;
- }
- eval -= 2;
- if(eval + 0x80 >= 0x100)
- goto range;
- if(eval == 0) {
- error("illegal bra.s with zero offset");
- continue;
- }
- *++locp = (char)eval;
- break;
- // Fixup one-byte value at locp + 1.
- case FU_WBYTE:
- ++locp;
- // FALLTHROUGH
- // Fixup one-byte forward references
- case FU_BYTE:
- if(!(eattr & DEFINED)) {
- error("external byte reference");
- continue;
- }
- if(tdb) {
- error("non-absolute byte reference");
- continue;
- }
- if((w & FU_PCREL) && eval + 0x80 >= 0x100) goto range;
- if(w & FU_SEXT) {
- if(eval + 0x100 >= 0x200) goto range;
- } else
- if(eval >= 0x100) goto range;
-
- *locp = (char)eval;
- break;
- // Fixup WORD forward references;
- // the word could be unaligned in the section buffer, so we have to be careful.
- case FU_WORD:
- if(((w & 0x0F00) == FU_JR) || ((w & 0x0F00) == FU_MJR)) {
- oaddr = *fup.lp++;
- if(oaddr) {
- reg2 = (signed)((eval - (oaddr + 2)) / 2);// & 0x1F;
- } else {
- reg2 = (signed)((eval - (loc + 2)) / 2);// & 0x1F;
- }
- if((w & 0x0F00) == FU_MJR) {
- // Main code destination alignment checking here for forward declared labels
- address = (oaddr) ? oaddr : loc;
- if(((address >= 0xF03000) && (address < 0xF04000) && (eval < 0xF03000)) ||
- ((eval >= 0xF03000) && (eval < 0xF04000) && (address < 0xF03000)) ) {
- warni("* \'jr\' at $%08X - cannot jump relative between "
- "main memory and local gpu ram", address);
- } else {
- page_jump = (address & 0xFFFFFF00) - (eval & 0xFFFFFF00);
- if(page_jump) {
- // This jump is to a page outside of the current 256 byte page
- if(eval % 4) {
- warni("* \'jr\' at $%08X - destination address not aligned for long page jump, "
- "insert a \'nop\' before the destination address", address);
- }
- } else {
- // This jump is in the current 256 byte page
- if((eval - 2) % 4) {
- warni("* \'jr\' at $%08X - destination address not aligned for short page jump, "
- "insert a \'nop\' before the destination address", address);
- }
- }
- }
- }
- if((reg2 < -16) || (reg2 > 15)) {
- error("relative jump out of range");
- break;
- }
- *locp = (char)(*locp | ((reg2 >> 3) & 0x03));
- locp++;
- *locp = (char)(*locp | ((reg2 & 0x07) << 5));
- break;
- }
- if((w & 0x0F00) == FU_NUM15) {
- if(eval < -16 || eval > 15) {
- error("constant out of range");
- break;
- }
- *locp = (char)(*locp | ((eval >> 3) & 0x03));
- locp++;
- *locp = (char)(*locp | ((eval & 0x07) << 5));
- break;
- }
- if((w & 0x0F00) == FU_NUM31) {
- if(eval < 0 || eval > 31) {
- error("constant out of range");
- break;
- }
- *locp = (char)(*locp | ((eval >> 3) & 0x03));
- locp++;
- *locp = (char)(*locp | ((eval & 0x07) << 5));
- break;
- }
- if((w & 0x0F00) == FU_NUM32) {
- if(eval < 1 || eval > 32) {
- error("constant out of range");
- break;
- }
- if(w & FU_SUB32)
- eval = (32 - eval);
- eval = (eval == 32) ? 0 : eval;
- *locp = (char)(*locp | ((eval >> 3) & 0x03));
- locp++;
- *locp = (char)(*locp | ((eval & 0x07) << 5));
- break;
- }
- if((w & 0x0F00) == FU_REGONE) {
- if(eval < 0 || eval > 31) {
- error("register value out of range");
- break;
- }
- *locp = (char)(*locp | ((eval >> 3) & 0x03));
- locp++;
- *locp = (char)(*locp | ((eval & 0x07) << 5));
- break;
- }
- if((w & 0x0F00) == FU_REGTWO) {
- if(eval < 0 || eval > 31) {
- error("register value out of range");
- break;
- }
- locp++;
- *locp = (char)(*locp | (eval & 0x1F));
- break;
- }
-
- if(!(eattr & DEFINED)) {
- if(w & FU_PCREL)
- w = MPCREL | MWORD;
- else w = MWORD;
- rmark(sno, loc, 0, w, esym);
- } else {
- if(tdb)
- rmark(sno, loc, tdb, MWORD, NULL);
- if(w & FU_SEXT) {
- if(eval + 0x10000 >= 0x20000)
- goto range;
- } else
- if(w & FU_ISBRA) { // Range-check BRA and DBRA
- if(eval + 0x8000 >= 0x10000)
- goto range;
- } else
- if(eval >= 0x10000)
- goto range;
- }
-
- *locp++ = (char)(eval >> 8);
- *locp = (char)eval;
- break;
- // Fixup LONG forward references;
- // the long could be unaligned in the section buffer, so be careful (again).
- case FU_LONG:
- if((w & 0x0F00) == FU_MOVEI) {
- address = loc + 4;
- if(eattr & DEFINED) {
- for(j = 0; j < fwindex; j++) {
- if(fwdjump[j] == address) {
- page_jump = (address & 0xFFFFFF00) - (eval & 0xFFFFFF00);
- if(page_jump) {
- if(eval % 4) {
- err_setup();
- sprintf(buf, "* \'jump\' at $%08X - destination address not aligned for long page jump, "
- "insert a \'nop\' before the destination address", address);
- if(listing > 0) ship_ln(buf);
- if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
- else printf("%s\n", buf);
- }
- } else {
- if(!(eval & 0x0000000F) || ((eval - 2) % 4)) {
- err_setup();
- sprintf(buf, "* \'jump\' at $%08X - destination address not aligned for short page jump, "
- "insert a \'nop\' before the destination address", address);
- if(listing > 0) ship_ln(buf);
- if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
- else printf("%s\n", buf);
- }
- }
- // Clear this jump as it has been checked
- fwdjump[j] = 0;
- j = fwindex;
- }
- }
- }
- eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
- flags = (MLONG|MMOVEI);
- } else flags = MLONG;
- if(!(eattr & DEFINED)) {
- rmark(sno, loc, 0, flags, esym);
- }
- else if(tdb) {
- rmark(sno, loc, tdb, flags, NULL);
- }
- *locp++ = (char)(eval >> 24);
- *locp++ = (char)(eval >> 16);
- *locp++ = (char)(eval >> 8);
- *locp = (char)eval;
- break;
- // Fixup a 3-bit "QUICK" reference in bits 9..1
- // (range of 1..8) in a word. Really bits 1..3 in a byte.
- case FU_QUICK:
- if(!(eattr & DEFINED)) {
- error("External quick reference");
- continue;
- }
-
- if(eval < 1 || eval > 8)
- goto range;
- *locp |= (eval & 7) << 1;
- break;
- // Fix up 6502 funny branch
- case FU_6BRA:
- eval -= (loc + 1);
- if(eval + 0x80 >= 0x100)
- goto range;
- *locp = (char)eval;
- break;
- default:
- interror(4); // Bad fixup type
- // NOTREACHED
- }
- continue;
-
- range:
-
- error("expression out of range");
- }
-
- ch = ch->chnext;
- } while(ch != NULL);
-
- return(0);
+ }
+ }
+
+ locp = cch->chptr + (loc - cch->chloc);
+ eattr = 0;
+
+ // Compute expression/symbol value and attribs
+ // Complex expression
+ if (w & FU_EXPR)
+ {
+ i = *fup.wp++;
+
+ if (evexpr(fup.tk, &eval, &eattr, &esym) != OK)
+ {
+ fup.lp += i;
+ continue;
+ }
+
+ fup.lp += i;
+ }
+ // Simple symbol
+ else
+ {
+ sy = *fup.sy++;
+ eattr = sy->sattr;
+
+ if (eattr & DEFINED)
+ eval = sy->svalue;
+ else
+ eval = 0;
+
+ if ((eattr & (GLOBAL | DEFINED)) == GLOBAL)
+ esym = sy;
+ }
+
+ tdb = (WORD)(eattr & TDB);
+
+ // If the expression is undefined and no external symbol is
+ // involved, then it's an error.
+ if (!(eattr & DEFINED) && esym == NULL)
+ {
+ error(undef_error);
+ continue;
+ }
+
+ if (((w & 0x0F00) == FU_MOVEI) && esym)
+ esym->sattre |= RISCSYM;
+
+ // Do the fixup
+ //
+ // If a PC-relative fixup is undefined, its value is *not*
+ // subtracted from the location (that will happen in the linker
+ // when the external reference is resolved).
+ //
+ // MWC expects PC-relative things to have the LOC subtracted from
+ // the value, if the value is external (that is, undefined at this
+ // point).
+ //
+ // PC-relative fixups must be DEFINED and either in the same
+ // section (whereupon the subtraction takes place) or ABS (with no
+ // subtract).
+ if (w & FU_PCREL)
+ {
+ if (eattr & DEFINED)
+ {
+ if (tdb == sno)
+ eval -= (VALUE)loc;
+ else if (tdb)
+ {
+ error("PC-relative expr across sections");
+ continue;
+ }
+
+ if (sbra_flag && (w & FU_LBRA) && (eval + 0x80 < 0x100))
+ warn("unoptimized short branch");
+ }
+ else if (obj_format == MWC)
+ eval -= (VALUE)loc;
+
+ tdb = 0;
+ eattr &= ~TDB;
+ }
+
+ // Do fixup classes
+ switch ((int)(w & FUMASK))
+ {
+ // FU_BBRA fixes up a one-byte branch offset.
+ case FU_BBRA:
+ if (!(eattr & DEFINED))
+ {
+ error("external short branch");
+ continue;
+ }
+
+ eval -= 2;
+
+ if (eval + 0x80 >= 0x100)
+ goto range;
+
+ if (eval == 0)
+ {
+ error("illegal bra.s with zero offset");
+ continue;
+ }
+
+ *++locp = (char)eval;
+ break;
+ // Fixup one-byte value at locp + 1.
+ case FU_WBYTE:
+ locp++;
+ // FALLTHROUGH
+ // Fixup one-byte forward references
+ case FU_BYTE:
+ if (!(eattr & DEFINED))
+ {
+ error("external byte reference");
+ continue;
+ }
+
+ if (tdb)
+ {
+ error("non-absolute byte reference");
+ continue;
+ }
+
+ if ((w & FU_PCREL) && eval + 0x80 >= 0x100)
+ goto range;
+
+ if (w & FU_SEXT)
+ {
+ if (eval + 0x100 >= 0x200)
+ goto range;
+ }
+ else if (eval >= 0x100)
+ goto range;
+
+ *locp = (char)eval;
+ break;
+ // Fixup WORD forward references;
+ // the word could be unaligned in the section buffer, so we have to
+ // be careful.
+ case FU_WORD:
+ if ((w & 0x0F00) == FU_JR)// || ((w & 0x0F00) == FU_MJR))
+ {
+ oaddr = *fup.lp++;
+
+ if (oaddr)
+ reg2 = (signed)((eval - (oaddr + 2)) / 2);// & 0x1F;
+ else
+ reg2 = (signed)((eval - (loc + 2)) / 2);// & 0x1F;
+
+#if 0
+ if ((w & 0x0F00) == FU_MJR)
+ {
+ // Main code destination alignment checking here for
+ // forward declared labels
+ address = (oaddr) ? oaddr : loc;
+
+ if (((address >= 0xF03000) && (address < 0xF04000)
+ && (eval < 0xF03000)) || ((eval >= 0xF03000)
+ && (eval < 0xF04000) && (address < 0xF03000)))
+ {
+ warni("* \'jr\' at $%08X - cannot jump relative between "
+ "main memory and local gpu ram", address);
+ }
+ else
+ {
+ page_jump = (address & 0xFFFFFF00) - (eval & 0xFFFFFF00);
+
+ if (page_jump)
+ {
+ // This jump is to a page outside of the
+ // current 256 byte page
+ if (eval % 4)
+ {
+ warni("* \'jr\' at $%08X - destination address not aligned for long page jump, insert a \'nop\' before the destination address", address);
+ }
+ }
+ else
+ {
+ // This jump is in the current 256 byte page
+ if ((eval - 2) % 4)
+ {
+ warni("* \'jr\' at $%08X - destination address not aligned for short page jump, insert a \'nop\' before the destination address", address);
+ }
+ }
+ }
+ }
+#endif
+
+ if ((reg2 < -16) || (reg2 > 15))
+ {
+ error("relative jump out of range");
+ break;
+ }
+
+ *locp = (char)(*locp | ((reg2 >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((reg2 & 0x07) << 5));
+ break;
+ }
+
+ if ((w & 0x0F00) == FU_NUM15)
+ {
+ if (eval < -16 || eval > 15)
+ {
+ error("constant out of range");
+ break;
+ }
+
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+
+ if ((w & 0x0F00) == FU_NUM31)
+ {
+ if (eval < 0 || eval > 31)
+ {
+ error("constant out of range");
+ break;
+ }
+
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+
+ if ((w & 0x0F00) == FU_NUM32)
+ {
+ if (eval < 1 || eval > 32)
+ {
+ error("constant out of range");
+ break;
+ }
+
+ if (w & FU_SUB32)
+ eval = (32 - eval);
+
+ eval = (eval == 32) ? 0 : eval;
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+
+ if ((w & 0x0F00) == FU_REGONE)
+ {
+ if (eval < 0 || eval > 31)
+ {
+ error("register value out of range");
+ break;
+ }
+
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+
+ if ((w & 0x0F00) == FU_REGTWO)
+ {
+ if (eval < 0 || eval > 31)
+ {
+ error("register value out of range");
+ break;
+ }
+
+ locp++;
+ *locp = (char)(*locp | (eval & 0x1F));
+ break;
+ }
+
+ if (!(eattr & DEFINED))
+ {
+ if (w & FU_PCREL)
+ w = MPCREL | MWORD;
+ else
+ w = MWORD;
+
+ rmark(sno, loc, 0, w, esym);
+ }
+ else
+ {
+ if (tdb)
+ rmark(sno, loc, tdb, MWORD, NULL);
+
+ if (w & FU_SEXT)
+ {
+ if (eval + 0x10000 >= 0x20000)
+ goto range;
+ }
+ else
+ {
+ // Range-check BRA and DBRA
+ if (w & FU_ISBRA)
+ {
+ if (eval + 0x8000 >= 0x10000)
+ goto range;
+ }
+ else if (eval >= 0x10000)
+ goto range;
+ }
+ }
+
+ *locp++ = (char)(eval >> 8);
+ *locp = (char)eval;
+ break;
+ // Fixup LONG forward references;
+ // the long could be unaligned in the section buffer, so be careful
+ // (again).
+ case FU_LONG:
+ if ((w & 0x0F00) == FU_MOVEI)
+ {
+#if 0
+ address = loc + 4;
+
+ if (eattr & DEFINED)
+ {
+ for(j=0; j<fwindex; j++)
+ {
+ if (fwdjump[j] == address)
+ {
+ page_jump = (address & 0xFFFFFF00) - (eval & 0xFFFFFF00);
+
+ if (page_jump)
+ {
+ if (eval % 4)
+ {
+ err_setup();
+ sprintf(buf, "* \'jump\' at $%08X - destination address not aligned for long page jump, insert a \'nop\' before the destination address", address);
+
+ if (listing > 0)
+ ship_ln(buf);
+
+ if (err_flag)
+ write(err_fd, buf, (LONG)strlen(buf));
+ else
+ printf("%s\n", buf);
+ }
+ }
+ else
+ {
+ if (!(eval & 0x0000000F) || ((eval - 2) % 4))
+ {
+ err_setup();
+ sprintf(buf, "* \'jump\' at $%08X - destination address not aligned for short page jump, insert a \'nop\' before the destination address", address);
+
+ if (listing > 0)
+ ship_ln(buf);
+
+ if (err_flag)
+ write(err_fd, buf, (LONG)strlen(buf));
+ else
+ printf("%s\n", buf);
+ }
+ }
+
+ // Clear this jump as it has been checked
+ fwdjump[j] = 0;
+ j = fwindex;
+ }
+ }
+ }
+#endif
+
+ eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
+ flags = (MLONG | MMOVEI);
+ }
+ else
+ flags = MLONG;
+
+ if (!(eattr & DEFINED))
+ {
+//printf("Fixup (long): Symbol undefined. loc = $%X, long = $%X, flags = $%x\n", loc, eval, flags);
+ rmark(sno, loc, 0, flags, esym);
+ }
+ else if (tdb)
+ {
+//printf("Fixup (long): TDB = $%X. loc =$%X, long = $%X, flags = $%x\n", tdb, loc, eval, flags);
+ rmark(sno, loc, tdb, flags, NULL);
+ }
+//else
+//printf("Fixup (long): TDB = $%X. loc =$%X, long = $%X, flags = $%x\n", tdb, loc, eval, flags);
+
+ *locp++ = (char)(eval >> 24);
+ *locp++ = (char)(eval >> 16);
+ *locp++ = (char)(eval >> 8);
+ *locp = (char)eval;
+ break;
+
+ // Fixup a 3-bit "QUICK" reference in bits 9..1
+ // (range of 1..8) in a word. Really bits 1..3 in a byte.
+ case FU_QUICK:
+ if (!(eattr & DEFINED))
+ {
+ error("External quick reference");
+ continue;
+ }
+
+ if (eval < 1 || eval > 8)
+ goto range;
+
+ *locp |= (eval & 7) << 1;
+ break;
+
+ // Fix up 6502 funny branch
+ case FU_6BRA:
+ eval -= (loc + 1);
+
+ if (eval + 0x80 >= 0x100)
+ goto range;
+
+ *locp = (char)eval;
+ break;
+
+ default:
+ interror(4); // Bad fixup type
+ // NOTREACHED
+ }
+ continue;
+range:
+ error("expression out of range");
+ }
+
+ ch = ch->chnext;
+ }
+ while (ch != NULL);
+
+ return 0;