X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=sect.c;h=9c1a586b18dbd68d92bf3b06cf9edf72e2432776;hp=fe630b15d3a2f8aaf1b4f8a36ac0d33f34b65f78;hb=bdbf34766f4d074a5933eb1326fe4ce03d249e10;hpb=b10167d55798ea184f97fafda075255c0852f3b6 diff --git a/sect.c b/sect.c index fe630b1..9c1a586 100644 --- a/sect.c +++ b/sect.c @@ -1,12 +1,13 @@ // -// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// RMAC - Reboot's Macro Assembler for all Atari computers // SECT.C - Code Generation, Fixups and Section Management -// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2019 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 -// Source Utilised with the Kind Permission of Landon Dyer +// Source utilised with the kind permission of Landon Dyer // #include "sect.h" +#include "6502.h" #include "direct.h" #include "error.h" #include "expr.h" @@ -19,104 +20,103 @@ // Function prototypes -void mksect(int, WORD); -void switchsect(int); +void MakeSection(int, uint16_t); +void SwitchSection(int); // Section descriptors -SECT sect[NSECTS]; // All sections... -int cursect; // Current section number +SECT sect[NSECTS]; // All sections... +int cursect; // Current section number // These are copied from the section descriptor, the current code chunk // descriptor and the current fixup chunk descriptor when a switch is made into -// a section. They are copied back to the descriptors when the section is left. -WORD scattr; // Section attributes -LONG sloc; // Current loc in section +// a section. They are copied back to the descriptors when the section is left. +uint16_t scattr; // Section attributes +uint32_t sloc; // Current loc in section -CHUNK * scode; // Current (last) code chunk -LONG challoc; // # bytes alloc'd to code chunk -LONG ch_size; // # bytes used in code chunk -char * chptr; // Deposit point in code chunk buffer - -CHUNK * sfix; // Current (last) fixup chunk -LONG fchalloc; // # bytes alloc'd to fixup chunk -LONG fchsize; // # bytes used in fixup chunk -PTR fchptr; // Deposit point in fixup chunk buffer +CHUNK * scode; // Current (last) code chunk +uint32_t challoc; // # bytes alloc'd to code chunk +uint32_t ch_size; // # bytes used in code chunk +uint8_t * chptr; // Deposit point in code chunk buffer +uint8_t * chptr_opcode; // Backup of chptr, updated before entering code generators // Return a size (SIZB, SIZW, SIZL) or 0, depending on what kind of fixup is // associated with a location. -static char fusiztab[] = { - 0, // FU_QUICK - 1, // FU_BYTE - 2, // FU_WORD - 2, // FU_WBYTE - 4, // FU_LONG - 1, // FU_BBRA - 0, // (unused) - 1, // FU_6BRA +static uint8_t fusiztab[] = { + 0, // FU_QUICK + 1, // FU_BYTE + 2, // FU_WORD + 2, // FU_WBYTE + 4, // FU_LONG + 1, // FU_BBRA + 0, // (unused) + 1, // FU_6BRA }; // Offset to REAL fixup location -static char fusizoffs[] = { - 0, // FU_QUICK - 0, // FU_BYTE - 0, // FU_WORD - 1, // FU_WBYTE - 0, // FU_LONG - 1, // FU_BBRA - 0, // (unused) - 0, // FU_6BRA +static uint8_t fusizoffs[] = { + 0, // FU_QUICK + 0, // FU_BYTE + 0, // FU_WORD + 1, // FU_WBYTE + 0, // FU_LONG + 1, // FU_BBRA + 0, // (unused) + 0, // FU_6BRA }; // -// Initialize Sections; Setup initial ABS, TEXT, DATA and BSS sections +// Initialize sections; setup initial ABS, TEXT, DATA and BSS sections // void InitSection(void) { - int i; - - // Cleanup all sections - for(i=0; iscattr = attr; - p->sloc = 0; - p->scode = p->sfcode = NULL; - p->sfix = p->sffix = NULL; + SECT * sp = §[sno]; + sp->scattr = attr; + sp->sloc = 0; + sp->orgaddr = 0; + sp->scode = sp->sfcode = NULL; + sp->sfix = sp->sffix = NULL; } // -// Switch to Another Section (Copy Section & Chunk Descriptors to Global Vars -// for Fast Access) +// Switch to another section (copy section & chunk descriptors to global vars +// for fast access) // -void switchsect(int sno) +void SwitchSection(int sno) { - CHUNK * cp; // Chunk pointer + CHUNK * cp; cursect = sno; - SECT * p = §[sno]; + SECT * sp = §[sno]; + + m6502 = (sno == M6502); // Set 6502-mode flag - scattr = p->scattr; // Copy section vars - sloc = p->sloc; - scode = p->scode; - sfix = p->sfix; + // Copy section vars + scattr = sp->scattr; + sloc = sp->sloc; + scode = sp->scode; + orgaddr = sp->orgaddr; // Copy code chunk vars if ((cp = scode) != NULL) @@ -124,105 +124,85 @@ void switchsect(int sno) challoc = cp->challoc; ch_size = cp->ch_size; chptr = cp->chptr + ch_size; - } - else - challoc = ch_size = 0; - // Copy fixup chunk vars - if ((cp = sfix) != NULL) - { - fchalloc = cp->challoc; - fchsize = cp->ch_size; - fchptr.cp = cp->chptr + fchsize; + // For 6502 mode, add the last org'd address +// Why? +/* +Because the way this is set up it treats the 6502 assembly space as a single 64K space (+ 16 bytes, for some reason) and just bobbles around inside that space and uses a stack of org "pointers" to show where the data ended up. + +This is a piss poor way to handle things, and for fucks sake, we can do better than this! +*/ + if (m6502) + chptr = cp->chptr + orgaddr; } else - fchalloc = fchsize = 0; + challoc = ch_size = 0; } // -// Save Current Section +// Save current section // -void savsect(void) +void SaveSection(void) { - SECT * p = §[cursect]; + SECT * sp = §[cursect]; - p->scattr = scattr; // Bailout section vars - p->sloc = sloc; + sp->scattr = scattr; // Bailout section vars + sp->sloc = sloc; + sp->orgaddr = orgaddr; - if (scode != NULL) // Bailout code chunk + if (scode != NULL) // Bailout code chunk scode->ch_size = ch_size; - - if (sfix != NULL) // Bailout fixup chunk - sfix->ch_size = fchsize; } // -// Test to see if a location has a fixup sic'd on it. This is used by the +// Test to see if a location has a fixup set on it. This is used by the // listing generator to print 'xx's instead of '00's for forward references // -int fixtest(int sno, LONG loc) +int fixtest(int sno, uint32_t loc) { - CHUNK * ch; - PTR fup; - char * fuend; - WORD w; - LONG xloc; - - stopmark(); // Force update to sect[] variables - - // Hairy, ugly linear search for a mark on our location; - // the speed doesn't matter, since this is only done when generating a - // listing, which is SLOW. - for(ch=sect[sno].sffix; ch!=NULL; ch=ch->chnext) - { - fup.cp = (char *)ch->chptr; - fuend = fup.cp + ch->ch_size; - - while (fup.cp < fuend) - { - w = *fup.wp++; - xloc = *fup.lp++ + (int)fusizoffs[w & FUMASK]; - fup.wp += 2; + // Force update to sect[] variables + StopMark(); - if (xloc == loc) - return (int)fusiztab[w & FUMASK]; + // Ugly linear search for a mark on our location. The speed doesn't + // matter, since this is only done when generating a listing, which is + // SLOW anyway. + for(FIXUP * fp=sect[sno].sffix; fp!=NULL; fp=fp->next) + { + uint32_t w = fp->attr; + uint32_t xloc = fp->loc + (int)fusizoffs[w & FUMASK]; - if (w & FU_EXPR) - { - w = *fup.wp++; - fup.lp += w; - } - else - ++fup.lp; - } + if (xloc == loc) + return (int)fusiztab[w & FUMASK]; } return 0; } -// -// Check that there are at least `amt' bytes left in the current chunk. If -// there are not, allocate another chunk of at least `amt' bytes (and probably -// more). -// -// If `amt' is zero, ensure there are at least CH_THRESHOLD bytes, likewise. // -int chcheck(LONG amt) +// Check that there are at least 'amt' bytes left in the current chunk. If +// there are not, allocate another chunk of at least CH_CODE_SIZE bytes or +// 'amt', whichever is larger. +// +// If 'amt' is zero, ensure there are at least CH_THRESHOLD bytes, likewise. +// +void chcheck(uint32_t amt) { DEBUG { printf("chcheck(%u)\n", amt); } + // If in BSS section, no allocation required if (scattr & SBSS) - return 0; + return; - if (!amt) + if (amt == 0) amt = CH_THRESHOLD; - DEBUG { printf(" challoc=%i, ch_size=%i, diff=%i\n", challoc, ch_size, challoc-ch_size); } - if ((int)(challoc - ch_size) >= (int)amt) - return 0; + DEBUG { printf(" challoc=%i, ch_size=%i, diff=%i\n", challoc, ch_size, challoc - ch_size); } + + if ((int)(challoc - ch_size) >= (int)amt) + return; if (amt < CH_CODE_SIZE) amt = CH_CODE_SIZE; @@ -242,7 +222,7 @@ int chcheck(LONG amt) { cp->chprev = scode; scode->chnext = cp; - scode->ch_size = ch_size; // Save old chunk's globals + scode->ch_size = ch_size; // Save old chunk's globals } // Setup chunk and global vars @@ -250,669 +230,724 @@ int chcheck(LONG amt) cp->chnext = NULL; challoc = cp->challoc = amt; ch_size = cp->ch_size = 0; - chptr = cp->chptr = ((char *)cp) + sizeof(CHUNK); + chptr = cp->chptr = ((uint8_t *)cp) + sizeof(CHUNK); scode = p->scode = cp; - return 0; + return; } -// This is really wrong. We need to make some proper structures here so we don't -// have to count sizes of objects, that's what the compiler's for! :-P -#define FIXUP_BASE_SIZE (sizeof(WORD) + sizeof(LONG) + sizeof(WORD) + sizeof(WORD)) // // Arrange for a fixup on a location // -int fixup(WORD attr, LONG loc, TOKEN * fexpr) +int AddFixup(uint32_t attr, uint32_t loc, TOKEN * fexpr) { - LONG i; - LONG len = 0; - CHUNK * cp; - SECT * p; - // Shamus: Expression lengths are voodoo ATM (variable "i"). Need to fix this. -#warning "!!! fixup() is filled with VOODOO !!!" - DEBUG printf("FIXUP@$%X: $%X\n", loc, attr); - - // Compute length of expression (could be faster); determine if it's the - // single-symbol case; no expression if it's just a mark. This code assumes - // 16 bit WORDs and 32 bit LONGs - if (*fexpr == SYMBOL && fexpr[2] == ENDEXPR) + uint16_t exprlen = 0; + SYM * symbol = NULL; + uint32_t _orgaddr = 0; + + // First, check to see if the expression is a bare label, otherwise, force + // the FU_EXPR flag into the attributes and count the tokens. + if ((fexpr[0] == SYMBOL) && (fexpr[2] == ENDEXPR)) { - // Just a single symbol - // SCPCD : correct bit mask for attr (else other FU_xxx will match) NYAN ! - if ((attr & 0x0F00) == FU_JR) - { -// i = 18; -// i = FIXUP_BASE_SIZE + (sizeof(LONG) * 2); - i = FIXUP_BASE_SIZE + sizeof(SYM *) + sizeof(LONG); - } - else - { -// i = 14; - i = FIXUP_BASE_SIZE + sizeof(SYM *); - } + symbol = symbolPtr[fexpr[1]]; + + // Save the org address for JR RISC instruction + if ((attr & FUMASKRISC) == FU_JR) + _orgaddr = orgaddr; } else { attr |= FU_EXPR; - - for(len=0; fexpr[len]!=ENDEXPR; len++) - { - if (fexpr[len] == CONST || fexpr[len] == SYMBOL) - len++; - } - - len++; // Add 1 for ENDEXPR -// i = (len << 2) + 12; - i = FIXUP_BASE_SIZE + sizeof(WORD) + (len * sizeof(TOKEN)); + exprlen = ExpressionLength(fexpr); } - // Maybe alloc another fixup chunk for this one to fit in - if ((fchalloc - fchsize) < i) + // Second, check to see if it's a DSP56001 fixup, and force the FU_56001 + // flag into the attributes if so; also save the current org address. + if (attr & FUMASKDSP) { - p = §[cursect]; - cp = (CHUNK *)malloc(sizeof(CHUNK) + CH_FIXUP_SIZE); - - // First fixup chunk in section - if (sfix == NULL) - { - cp->chprev = NULL; - p->sffix = cp; - } - // Add to other chunks - else - { - cp->chprev = sfix; - sfix->chnext = cp; - sfix->ch_size = fchsize; - } - - // Setup fixup chunk and its global vars - cp->chnext = NULL; - fchalloc = cp->challoc = CH_FIXUP_SIZE; - fchsize = cp->ch_size = 0; - fchptr.cp = cp->chptr = ((char *)cp) + sizeof(CHUNK); - sfix = p->sfix = cp; + attr |= FU_56001; + _orgaddr = orgaddr; } - // Record fixup type, fixup location, and the file number and line number - // the fixup is located at. - *fchptr.wp++ = attr; - *fchptr.lp++ = loc; - *fchptr.wp++ = cfileno; - *fchptr.wp++ = (WORD)curlineno; - - // Store postfix expression or pointer to a single symbol, or nothing for a - // mark. - if (attr & FU_EXPR) + // Allocate space for the fixup + any expression + FIXUP * fixup = malloc(sizeof(FIXUP) + (sizeof(TOKEN) * exprlen)); + + // Store the relevant fixup information in the FIXUP + fixup->next = NULL; + fixup->attr = attr; + fixup->loc = loc; + fixup->fileno = cfileno; + fixup->lineno = curlineno; + fixup->expr = NULL; + fixup->symbol = symbol; + fixup->orgaddr = _orgaddr; + + // Copy the passed in expression to the FIXUP, if any + if (exprlen > 0) { - *fchptr.wp++ = (WORD)len; + fixup->expr = (TOKEN *)((uint8_t *)fixup + sizeof(FIXUP)); + memcpy(fixup->expr, fexpr, sizeof(TOKEN) * exprlen); + } - while (len--) - *fchptr.lp++ = (LONG)*fexpr++; + // Finally, put the FIXUP in the current section's linked list + if (sect[cursect].sffix == NULL) + { + sect[cursect].sffix = fixup; + sect[cursect].sfix = fixup; } else { -// *fchptr.lp++ = (LONG)fexpr[1]; - *fchptr.sy++ = symbolPtr[fexpr[1]]; + sect[cursect].sfix->next = fixup; + sect[cursect].sfix = fixup; } - // SCPCD : correct bit mask for attr (else other FU_xxx will match) NYAN ! - if ((attr & 0x0F00) == FU_JR) - { - if (orgactive) - *fchptr.lp++ = orgaddr; - else - *fchptr.lp++ = 0x00000000; + DEBUG { printf("AddFixup: sno=%u, l#=%u, attr=$%X, loc=$%X, expr=%p, sym=%p, org=$%X\n", cursect, fixup->lineno, fixup->attr, fixup->loc, (void *)fixup->expr, (void *)fixup->symbol, fixup->orgaddr); + if (symbol != NULL) + printf(" name: %s, value: $%lX\n", symbol->sname, symbol->svalue); } - fchsize += i; return 0; } // -// Resolve all Fixups +// Resolve fixups in the passed in section // -int ResolveAllFixups(void) +int ResolveFixups(int sno) { - unsigned i; - char buf[EBUFSIZ]; + SECT * sc = §[sno]; - // Make undefined symbols GLOBL - if (glob_flag) - syg_fix(); + // "Cache" first chunk + CHUNK * cch = sc->sfcode; - DEBUG printf("Resolving TEXT sections...\n"); - ResolveFixups(TEXT); - DEBUG printf("Resolving DATA sections...\n"); - ResolveFixups(DATA); + // Can't fixup a section with nothing in it + if (cch == NULL) + return 0; + + // Wire the 6502 segment's size to its allocated size (64K) + if (sno == M6502) + cch->ch_size = cch->challoc; -//No, no we don't. -#if 0 - // We need to do a final check of forward 'jump' destination addresses that - // are external - for(i=0; inext; + + uint32_t dw = fup->attr; // Fixup long (type + modes + flags) + uint32_t loc = fup->loc; // Location to fixup + cfileno = fup->fileno; + curlineno = fup->lineno; + DEBUG { printf("ResolveFixups: sect#=%u, l#=%u, attr=$%X, loc=$%X, expr=%p, sym=%p, org=$%X\n", sno, fup->lineno, fup->attr, fup->loc, (void *)fup->expr, (void *)fup->symbol, fup->orgaddr); } + + // This is based on global vars cfileno, curfname :-P + // This approach is kinda meh as well. I think we can do better + // than this. + SetFilenameForErrorReporting(); + + // Search for chunk containing location to fix up; compute a + // pointer to the location (in the chunk). Often we will find the + // Fixup is in the "cached" chunk, so the linear-search is seldom + // executed. + if (loc < cch->chloc || loc >= (cch->chloc + cch->ch_size)) { - err_setup(); - sprintf(buf, "* \'jump\' at $%08X - destination address is external to this source file and cannot have its aligment validated", fwdjump[i]); - - if (listing > 0) - ship_ln(buf); + for(cch=sc->sfcode; cch!=NULL; cch=cch->chnext) + { + if (loc >= cch->chloc && loc < (cch->chloc + cch->ch_size)) + break; + } - if (err_flag) - write(err_fd, buf, (LONG)strlen(buf)); - else - printf("%s\n", buf); + if (cch == NULL) + { + // Fixup (loc) is out of range--this should never happen! + // Once we call this function, it winds down immediately; it + // doesn't return. + interror(7); + } } - } -#endif - return 0; -} + // Location to fix (in current chunk) + // We use the address of the chunk that loc is actually in, then + // subtract the chunk's starting location from loc to get the offset + // into the current chunk. + uint8_t * locp = cch->chptr + (loc - cch->chloc); + uint16_t eattr = 0; // Expression attrib + SYM * esym = NULL; // External symbol involved in expr + uint64_t eval; // Expression value + uint16_t flags; // Mark flags -// -// Resolve Fixups in a Section -// -int ResolveFixups(int sno) -{ - PTR fup; // Current fixup - WORD * fuend; // End of last fixup (in this chunk) - WORD w; // Fixup word (type+modes+flags) - char * locp; // Location to fix (in cached chunk) - LONG loc; // Location to fixup - VALUE eval; // Expression value - WORD eattr; // Expression attrib - SYM * esym; // External symbol involved in expr - SYM * sy; // (Temp) pointer to a symbol - WORD i; // (Temp) word - WORD tdb; // eattr & TDB - LONG oaddr; - int reg2; - WORD flags; - unsigned page_jump = 0; - unsigned address = 0; - unsigned j; - char buf[EBUFSIZ]; - - SECT * sc = §[sno]; - CHUNK * ch = sc->sffix; + // Compute expression/symbol value and attributes - if (ch == NULL) - return 0; + // Complex expression + if (dw & FU_EXPR) + { + if (evexpr(fup->expr, &eval, &eattr, &esym) != OK) + continue; + } + // Simple symbol + else + { + SYM * sy = fup->symbol; + eattr = sy->sattr; - CHUNK * cch = sc->sfcode; // "cache" first chunk + if (eattr & DEFINED) + eval = sy->svalue; + else + eval = 0; - if (cch == NULL) // Can't fixup a sect with nothing in it - return 0; + // If the symbol is not defined, but global, set esym to sy + if ((eattr & (GLOBAL | DEFINED)) == GLOBAL) + esym = sy; + } - do - { - fup.cp = ch->chptr; // fup -> start of chunk - fuend = (WORD *)(fup.cp + ch->ch_size); // fuend -> end of chunk + uint16_t tdb = eattr & TDB; + + // If the expression/symbol is undefined and no external symbol is + // involved, then that's an error. + if (!(eattr & DEFINED) && (esym == NULL)) + { + error(undef_error); + continue; + } - while (fup.wp < fuend) + // 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 (dw & FU_PCREL) { - w = *fup.wp++; - loc = *fup.lp++; - cfileno = *fup.wp++; - curlineno = (int)*fup.wp++; -DEBUG { printf("ResolveFixups: cfileno=%u\n", cfileno); } - // This is based on global vars cfileno, curfname :-P - // This approach is kinda meh as well. I think we can do better than this. - SetFilenameForErrorReporting(); - - esym = NULL; - - // Search for chunk containing location to fix up; compute a - // pointer to the location (in the chunk). Often we will find the - // fixup is in the "cached" chunk, so the linear-search is seldom - // executed. - if (loc < cch->chloc || loc >= (cch->chloc + cch->ch_size)) + if (eattr & DEFINED) { - for(cch=sc->sfcode; cch!=NULL; cch=cch->chnext) + if (tdb == sno) + eval -= loc; + else if (tdb) { - if (loc >= cch->chloc && loc < (cch->chloc + cch->ch_size)) + // Allow cross-section PCREL fixups in Alcyon mode + if (prg_flag) + { + switch (tdb) + { + case TEXT: +// Shouldn't there be a break here, since otherwise, it will point to the DATA section? +// break; + case DATA: + eval += sect[TEXT].sloc; + break; + case BSS: + eval += sect[TEXT].sloc + sect[DATA].sloc; + break; + default: + error("invalid section"); break; - } + } - if (cch == NULL) - { - interror(7); // Fixup (loc) out of range - // NOTREACHED + eval -= loc; + } + else + { + error("PC-relative expr across sections"); + continue; + } } + + if (sbra_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100)) + warn("unoptimized short branch"); } + else if (obj_format == MWC) + eval -= loc; - locp = cch->chptr + (loc - cch->chloc); - eattr = 0; + tdb = 0; + eattr &= ~TDB; + } - // Compute expression/symbol value and attribs - // Complex expression - if (w & FU_EXPR) + // Handle fixup classes + switch (dw & FUMASK) + { + // FU_BBRA fixes up a one-byte branch offset. + case FU_BBRA: + if (!(eattr & DEFINED)) { - i = *fup.wp++; + error("external short branch"); + continue; + } + + eval -= 2; - if (evexpr(fup.tk, &eval, &eattr, &esym) != OK) + if (eval + 0x80 >= 0x100) + goto rangeErr; + + if (eval == 0) + { + if (CHECK_OPTS(OPT_NULL_BRA)) { - fup.lp += i; + // Just output a NOP + *locp++ = 0x4E; + *locp = 0x71; + continue; + } + else + { + error("illegal bra.s with zero offset"); continue; } - - fup.lp += i; } - // Simple symbol - else - { - sy = *fup.sy++; - eattr = sy->sattr; - if (eattr & DEFINED) - eval = sy->svalue; - else - eval = 0; + *++locp = (uint8_t)eval; + break; - if ((eattr & (GLOBAL | DEFINED)) == GLOBAL) - esym = sy; - } + // Fixup one-byte value at locp + 1. + case FU_WBYTE: + locp++; + // FALLTHROUGH - tdb = (WORD)(eattr & TDB); + // Fixup one-byte forward references + case FU_BYTE: + if (!(eattr & DEFINED)) + { + error("external byte reference"); + continue; + } - // If the expression is undefined and no external symbol is - // involved, then it's an error. - if (!(eattr & DEFINED) && esym == NULL) + if (tdb) { - error(undef_error); + error("non-absolute byte reference"); 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 ((dw & FU_PCREL) && ((eval + 0x80) >= 0x100)) + goto rangeErr; + + if (dw & FU_SEXT) { - if (eattr & DEFINED) - { - if (tdb == sno) - eval -= (VALUE)loc; - else if (tdb) - { - error("PC-relative expr across sections"); - continue; - } + if ((eval + 0x100) >= 0x200) + goto rangeErr; + } + else if (eval >= 0x100) + goto rangeErr; - if (sbra_flag && (w & FU_LBRA) && (eval + 0x80 < 0x100)) - warn("unoptimized short branch"); - } - else if (obj_format == MWC) - eval -= (VALUE)loc; + *locp = (uint8_t)eval; + break; - tdb = 0; - eattr &= ~TDB; + // Fixup high/low byte off word for 6502 + case FU_BYTEH: + if (!(eattr & DEFINED)) + { + error("external byte reference"); + continue; } - // Do fixup classes - switch ((int)(w & FUMASK)) + *locp = (uint8_t)(eval >> 8); + break; + + case FU_BYTEL: + if (!(eattr & DEFINED)) { - // FU_BBRA fixes up a one-byte branch offset. - case FU_BBRA: - if (!(eattr & DEFINED)) - { - error("external short branch"); - continue; - } + error("external byte reference"); + continue; + } - eval -= 2; + *locp = (uint8_t)eval; + break; - if (eval + 0x80 >= 0x100) - goto range; + // Fixup WORD forward references; the word could be unaligned in the + // section buffer, so we have to be careful. (? careful about what?) + case FU_WORD: + if ((dw & FUMASKRISC) == FU_JR) + { +#if 0 + int reg; + + if (fup->orgaddr) + reg = (signed)((eval - (fup->orgaddr + 2)) / 2); + else + reg = (signed)((eval - (loc + 2)) / 2); +#else + int reg = (signed)((eval - ((fup->orgaddr ? fup->orgaddr : loc) + 2)) / 2); +#endif - if (eval == 0) + if ((reg < -16) || (reg > 15)) { - error("illegal bra.s with zero offset"); - continue; + error("relative jump out of range"); + break; } - *++locp = (char)eval; + *locp |= ((uint8_t)reg >> 3) & 0x03; + locp++; + *locp |= ((uint8_t)reg & 0x07) << 5; break; - // Fixup one-byte value at locp + 1. - case FU_WBYTE: + } + else if ((dw & FUMASKRISC) == FU_NUM15) + { + if (((int)eval < -16) || ((int)eval > 15)) + { + error("constant out of range (-16 - +15)"); + break; + } + + *locp |= ((uint8_t)eval >> 3) & 0x03; locp++; - // FALLTHROUGH - // Fixup one-byte forward references - case FU_BYTE: - if (!(eattr & DEFINED)) + *locp |= ((uint8_t)eval & 0x07) << 5; + break; + } + else if ((dw & FUMASKRISC) == FU_NUM31) + { + if (eval > 31) { - error("external byte reference"); - continue; + error("constant out of range (0-31)"); + break; } - if (tdb) + *locp |= ((uint8_t)eval >> 3) & 0x03; + locp++; + *locp |= ((uint8_t)eval & 0x07) << 5; + break; + } + else if ((dw & FUMASKRISC) == FU_NUM32) + { + if ((eval < 1) || (eval > 32)) { - error("non-absolute byte reference"); - continue; + error("constant out of range (1-32)"); + break; } - if ((w & FU_PCREL) && eval + 0x80 >= 0x100) - goto range; + if (dw & FU_SUB32) + eval = (32 - eval); - if (w & FU_SEXT) + eval = (eval == 32) ? 0 : eval; + *locp |= ((uint8_t)eval >> 3) & 0x03; + locp++; + *locp |= ((uint8_t)eval & 0x07) << 5; + break; + } + else if ((dw & FUMASKRISC) == FU_REGONE) + { + if (eval > 31) { - if (eval + 0x100 >= 0x200) - goto range; + error("register one value out of range"); + break; } - else if (eval >= 0x100) - goto range; - *locp = (char)eval; + *locp |= ((uint8_t)eval >> 3) & 0x03; + locp++; + *locp |= ((uint8_t)eval & 0x07) << 5; 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)) + } + else if ((dw & FUMASKRISC) == FU_REGTWO) + { + if (eval > 31) { - oaddr = *fup.lp++; + error("register two value out of range"); + break; + } - if (oaddr) - reg2 = (signed)((eval - (oaddr + 2)) / 2);// & 0x1F; - else - reg2 = (signed)((eval - (loc + 2)) / 2);// & 0x1F; + locp++; + *locp |= (uint8_t)eval & 0x1F; + break; + } -#if 0 - if ((w & 0x0F00) == FU_MJR) - { - // Main code destination alignment checking here for - // forward declared labels - address = (oaddr) ? oaddr : loc; + if (!(eattr & DEFINED)) + { + flags = MWORD; - 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 (dw & FU_PCREL) + flags |= MPCREL; - if ((reg2 < -16) || (reg2 > 15)) - { - error("relative jump out of range"); - break; - } + MarkRelocatable(sno, loc, 0, flags, esym); + } + else + { + if (tdb) + MarkRelocatable(sno, loc, tdb, MWORD, NULL); - *locp = (char)(*locp | ((reg2 >> 3) & 0x03)); - locp++; - *locp = (char)(*locp | ((reg2 & 0x07) << 5)); - break; + if (dw & FU_SEXT) + { + if (eval + 0x10000 >= 0x20000) + goto rangeErr; } - - if ((w & 0x0F00) == FU_NUM15) + else { - if (eval < -16 || eval > 15) + // Range-check BRA and DBRA + if (dw & FU_ISBRA) { - error("constant out of range"); - break; + if (eval + 0x8000 >= 0x10000) + goto rangeErr; } - - *locp = (char)(*locp | ((eval >> 3) & 0x03)); - locp++; - *locp = (char)(*locp | ((eval & 0x07) << 5)); - break; + else if (eval >= 0x10000) + goto rangeErr; } + } - if ((w & 0x0F00) == FU_NUM31) - { - if (eval < 0 || eval > 31) - { - error("constant out of range"); - break; - } + // 6502 words are little endian, so handle that here + if (sno == M6502) + SETLE16(locp, 0, eval) + else + SETBE16(locp, 0, eval) - *locp = (char)(*locp | ((eval >> 3) & 0x03)); - locp++; - *locp = (char)(*locp | ((eval & 0x07) << 5)); - break; - } + break; - if ((w & 0x0F00) == FU_NUM32) - { - if (eval < 1 || eval > 32) - { - error("constant out of range"); - break; - } + // Fixup LONG forward references; the long could be unaligned in the + // section buffer, so be careful (again). + case FU_LONG: + flags = MLONG; - if (w & FU_SUB32) - eval = (32 - eval); + if ((dw & FUMASKRISC) == FU_MOVEI) + { + // Long constant in MOVEI # is word-swapped, so fix it here + eval = WORDSWAP32(eval); + flags |= MMOVEI; + } - eval = (eval == 32) ? 0 : eval; - *locp = (char)(*locp | ((eval >> 3) & 0x03)); - locp++; - *locp = (char)(*locp | ((eval & 0x07) << 5)); - break; - } + // If the symbol is undefined, make sure to pass the symbol in + // to the MarkRelocatable() function. + if (!(eattr & DEFINED)) + MarkRelocatable(sno, loc, 0, flags, esym); + else if (tdb) + MarkRelocatable(sno, loc, tdb, flags, NULL); - if ((w & 0x0F00) == FU_REGONE) - { - if (eval < 0 || eval > 31) - { - error("register value out of range"); - break; - } + SETBE32(locp, 0, eval); + break; + + // Fixup QUAD forward references (mainly used by the OP assembler) + case FU_QUAD: + if (dw & FU_OBJLINK) + { + uint64_t quad = GETBE64(locp, 0); + uint64_t addr = eval; + +//Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR... :-/ + if (fup->orgaddr) + addr = fup->orgaddr; + + eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21); + } + else if (dw & FU_OBJDATA) + { + // If it's in a TEXT or DATA section, be sure to mark for a + // fixup later + if (tdb) + MarkRelocatable(sno, loc, tdb, MQUAD, NULL); + + uint64_t quad = GETBE64(locp, 0); + uint64_t addr = eval; - *locp = (char)(*locp | ((eval >> 3) & 0x03)); - locp++; - *locp = (char)(*locp | ((eval & 0x07) << 5)); +//Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR... :-/ + if (fup->orgaddr) + addr = fup->orgaddr; + + eval = (quad & 0x000007FFFFFFFFFFLL) | ((addr & 0xFFFFF8) << 40); + } + + SETBE64(locp, 0, 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 rangeErr; + + *locp |= (eval & 7) << 1; + break; + + // Fix up 6502 funny branch + case FU_6BRA: + eval -= (loc + 1); + + if (eval + 0x80 >= 0x100) + goto rangeErr; + + *locp = (uint8_t)eval; + break; + + // Fixup DSP56001 addresses + case FU_56001: + switch (dw & FUMASKDSP) + { + // DSPIMM5 actually is clamped from 0 to 23 for our purposes + // and does not use the full 5 bit range. + case FU_DSPIMM5: + if (eval > 23) + { + error("immediate value must be between 0 and 23"); break; } - if ((w & 0x0F00) == FU_REGTWO) - { - if (eval < 0 || eval > 31) - { - error("register value out of range"); - break; - } + locp[2] |= eval; + break; - locp++; - *locp = (char)(*locp | (eval & 0x1F)); + // This is a 12-bit address encoded into the lower 12 + // bits of a DSP word + case FU_DSPADR12: + if (eval >= 0x1000) + { + error("address out of range ($000-$FFF)"); break; } - if (!(eattr & DEFINED)) - { - if (w & FU_PCREL) - w = MPCREL | MWORD; - else - w = MWORD; + locp[1] |= eval >> 8; + locp[2] = eval & 0xFF; + break; - rmark(sno, loc, 0, w, esym); - } - else + // This is a full DSP word containing Effective Address Extension + case FU_DSPADR24: + case FU_DSPIMM24: + if (eval >= 0x100000) { - 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; - } + error("value out of range ($000-$FFFFFF)"); + break; } - *locp++ = (char)(eval >> 8); - *locp = (char)eval; + *locp++ = (uint32_t)eval >> 16; + *locp++ = ((uint32_t)eval >> 8) & 0xFF; + *locp++ = (uint32_t)eval & 0xFF; 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) + + // This is a 16bit absolute address into a 24bit field + case FU_DSPADR16: + if (eval >= 0x10000) { -#if 0 - address = loc + 4; + error("address out of range ($0000-$FFFF)"); + break; + } - if (eattr & DEFINED) - { - for(j=0; j 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 + locp[1] = (uint8_t)(eval >> 8); + locp[2] = (uint8_t)eval; + break; - eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000); - flags = (MLONG | MMOVEI); + // This is 12-bit immediate short data + // The upper nibble goes into the last byte's low nibble + // while the remainder 8 bits go into the 2nd byte. + case FU_DSPIMM12: + if (eval >= 0x1000) + { + error("immediate out of range ($000-$FFF)"); + break; } - else - flags = MLONG; - if (!(eattr & DEFINED)) + locp[1] = (uint8_t)eval; + locp[2] |= (uint8_t)(eval >> 8); + break; + + // This is 8-bit immediate short data + // which goes into the middle byte of a DSP word. + case FU_DSPIMM8: + if (eval >= 0x100) { -//printf("Fixup (long): Symbol undefined. loc = $%X, long = $%X, flags = $%x\n", loc, eval, flags); - rmark(sno, loc, 0, flags, esym); + error("immediate out of range ($00-$FF)"); + break; } - else if (tdb) + + locp[1] = (uint8_t)eval; + break; + + // This is a 6 bit absoulte short address. It occupies + // the low 6 bits of the middle byte of a DSP word. + case FU_DSPADR06: + if (eval > 63) { -//printf("Fixup (long): TDB = $%X. loc =$%X, long = $%X, flags = $%x\n", tdb, loc, eval, flags); - rmark(sno, loc, tdb, flags, NULL); + error("address must be between 0 and 63"); + break; } -//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; + locp[1] |= 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)) + // This is a 6 bit absoulte short address. It occupies + // the low 6 bits of the middle byte of a DSP word. + case FU_DSPPP06: + if (eval < 0xFFFFFFC0) { - error("External quick reference"); - continue; + error("address must be between $FFC0 and $FFFF"); + break; } - if (eval < 1 || eval > 8) - goto range; - - *locp |= (eval & 7) << 1; + locp[1] |= eval & 0x3F; break; - // Fix up 6502 funny branch - case FU_6BRA: - eval -= (loc + 1); + // Shamus: I'm pretty sure these don't make any sense... + case FU_DSPIMMFL8: + warn("FU_DSPIMMFL8 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\""); + break; - if (eval + 0x80 >= 0x100) - goto range; + case FU_DSPIMMFL16: + warn("FU_DSPIMMFL16 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\""); + break; - *locp = (char)eval; + case FU_DSPIMMFL24: + warn("FU_DSPIMMFL24 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\""); break; + // Bad fixup type--this should *never* happen! default: - interror(4); // Bad fixup type + interror(4); // NOTREACHED } - continue; -range: - error("expression out of range"); + break; + + // Fixup a 4-byte float + case FU_FLOATSING: + warn("FU_FLOATSING missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\""); + break; + + // Fixup a 8-byte float + case FU_FLOATDOUB: + warn("FU_FLOATDOUB missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\""); + break; + + // Fixup a 12-byte float + case FU_FLOATEXT: + warn("FU_FLOATEXT missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\""); + break; + + default: + // Bad fixup type--this should *never* happen! + // Once we call this function, it winds down immediately; it + // doesn't return. + interror(4); } - ch = ch->chnext; + continue; +rangeErr: + error("expression out of range"); } - while (ch != NULL); + + return 0; +} + + +// +// Resolve all fixups +// +int ResolveAllFixups(void) +{ + // Make undefined symbols GLOBL + if (glob_flag) + ForceUndefinedSymbolsGlobal(); + + DEBUG printf("Resolving TEXT sections...\n"); + ResolveFixups(TEXT); + DEBUG printf("Resolving DATA sections...\n"); + ResolveFixups(DATA); + DEBUG printf("Resolving 6502 sections...\n"); + ResolveFixups(M6502); // Fixup 6502 section (if any) return 0; }