]> Shamusworld >> Repos - rmac/blob - sect.c
12f9c89eae2f7eda973f63765816c21bb87f3c57
[rmac] / sect.c
1 //
2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // SECT.C - Code Generation, Fixups and Section Management
4 // Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "sect.h"
10 #include "6502.h"
11 #include "direct.h"
12 #include "dsp56k.h"
13 #include "error.h"
14 #include "expr.h"
15 #include "listing.h"
16 #include "mach.h"
17 #include "mark.h"
18 #include "riscasm.h"
19 #include "symbol.h"
20 #include "token.h"
21 #define DEF_REGRISC
22 #include "riscregs.h"
23
24 // Function prototypes
25 void MakeSection(int, uint16_t);
26 void SwitchSection(int);
27
28 // Section descriptors
29 SECT sect[NSECTS];              // All sections...
30 int cursect;                    // Current section number
31
32 // These are copied from the section descriptor, the current code chunk
33 // descriptor and the current fixup chunk descriptor when a switch is made into
34 // a section. They are copied back to the descriptors when the section is left.
35 uint16_t scattr;                // Section attributes
36 uint32_t sloc;                  // Current loc in section
37
38 CHUNK * scode;                  // Current (last) code chunk
39 uint32_t challoc;               // # bytes alloc'd to code chunk
40 uint32_t ch_size;               // # bytes used in code chunk
41 uint8_t * chptr;                // Deposit point in code chunk buffer
42 uint8_t * chptr_opcode; // Backup of chptr, updated before entering code generators
43
44 // Return a size (SIZB, SIZW, SIZL) or 0, depending on what kind of fixup is
45 // associated with a location.
46 static uint8_t fusiztab[] = {
47         0,      // FU_QUICK
48         1,      // FU_BYTE
49         2,      // FU_WORD
50         2,      // FU_WBYTE
51         4,      // FU_LONG
52         1,      // FU_BBRA
53         0,      // (unused)
54         1,      // FU_6BRA
55 };
56
57 // Offset to REAL fixup location
58 static uint8_t fusizoffs[] = {
59         0,      // FU_QUICK
60         0,      // FU_BYTE
61         0,      // FU_WORD
62         1,      // FU_WBYTE
63         0,      // FU_LONG
64         1,      // FU_BBRA
65         0,      // (unused)
66         0,      // FU_6BRA
67 };
68
69
70 //
71 // Initialize sections; setup initial ABS, TEXT, DATA and BSS sections
72 //
73 void InitSection(void)
74 {
75         // Initialize all sections
76         for(int i=0; i<NSECTS; i++)
77                 MakeSection(i, 0);
78
79         // Construct default sections, make TEXT the current section
80         MakeSection(ABS,     SUSED | SABS | SBSS);      // ABS
81         MakeSection(TEXT,    SUSED | TEXT       );      // TEXT
82         MakeSection(DATA,    SUSED | DATA       );      // DATA
83         MakeSection(BSS,     SUSED | BSS  | SBSS);      // BSS
84         MakeSection(M6502,   SUSED | TEXT       );      // 6502 code section
85         MakeSection(M56001P, SUSED | SABS       );      // DSP 56001 Program RAM
86         MakeSection(M56001X, SUSED | SABS       );      // DSP 56001 X RAM
87         MakeSection(M56001Y, SUSED | SABS       );      // DSP 56001 Y RAM
88
89         // Switch to TEXT for starters
90         SwitchSection(TEXT);
91 }
92
93
94 //
95 // Make a new (clean) section
96 //
97 void MakeSection(int sno, uint16_t attr)
98 {
99         SECT * sp = &sect[sno];
100         sp->scattr = attr;
101         sp->sloc = 0;
102         sp->orgaddr = 0;
103         sp->scode = sp->sfcode = NULL;
104         sp->sfix = sp->sffix = NULL;
105 }
106
107
108 //
109 // Switch to another section (copy section & chunk descriptors to global vars
110 // for fast access)
111 //
112 void SwitchSection(int sno)
113 {
114         CHUNK * cp;
115         cursect = sno;
116         SECT * sp = &sect[sno];
117
118         m6502 = (sno == M6502); // Set 6502-mode flag
119
120         // Copy section vars
121         scattr = sp->scattr;
122         sloc = sp->sloc;
123         scode = sp->scode;
124         orgaddr = sp->orgaddr;
125
126         // Copy code chunk vars
127         if ((cp = scode) != NULL)
128         {
129                 challoc = cp->challoc;
130                 ch_size = cp->ch_size;
131                 chptr = cp->chptr + ch_size;
132
133                 // For 6502 mode, add the last org'd address
134 // Why?
135 /*
136 Because the way this is set up it treats the 6502 assembly space as a single 64K space (+ 16 bytes, for some unknown reason) and just bobbles around inside that space and uses a stack of org "pointers" to show where the data ended up.
137
138 This is a shitty way to handle things, and we can do better than this!  :-P
139
140 Really, there's no reason to have the 6502 (or DSP56001 for that matter) have their own private sections for this kind of thing, as there's literally *no* chance that it would be mingled with 68K+ code.  It should be able to use the TEXT, DATA & BSS sections just like the 68K.
141
142 Or should it?  After looking at the code, maybe it's better to keep the 56001 sections segregated from the rest.  But we can still make the 6502 stuff better.
143 */
144                 if (m6502)
145                         chptr = cp->chptr + orgaddr;
146         }
147         else
148                 challoc = ch_size = 0;
149 }
150
151
152 //
153 // Save current section
154 //
155 void SaveSection(void)
156 {
157         SECT * sp = &sect[cursect];
158
159         sp->scattr = scattr;                    // Bailout section vars
160         sp->sloc = sloc;
161         sp->orgaddr = orgaddr;
162
163         if (scode != NULL)                              // Bailout code chunk (if any)
164                 scode->ch_size = ch_size;
165 }
166
167
168 //
169 // Test to see if a location has a fixup set on it. This is used by the
170 // listing generator to print 'xx's instead of '00's for forward references
171 //
172 int fixtest(int sno, uint32_t loc)
173 {
174         // Force update to sect[] variables
175         StopMark();
176
177         // Ugly linear search for a mark on our location. The speed doesn't
178         // matter, since this is only done when generating a listing, which is
179         // SLOW anyway.
180         for(FIXUP * fp=sect[sno].sffix; fp!=NULL; fp=fp->next)
181         {
182                 uint32_t w = fp->attr;
183                 uint32_t xloc = fp->loc + (int)fusizoffs[w & FUMASK];
184
185                 if (xloc == loc)
186                         return (int)fusiztab[w & FUMASK];
187         }
188
189         return 0;
190 }
191
192
193 //
194 // Check that there are at least 'amt' bytes left in the current chunk. If
195 // there are not, allocate another chunk of at least CH_CODE_SIZE bytes or
196 // 'amt', whichever is larger.
197 //
198 // If 'amt' is zero, ensure there are at least CH_THRESHOLD bytes, likewise.
199 //
200 void chcheck(uint32_t amt)
201 {
202         DEBUG { printf("chcheck(%u)\n", amt); }
203
204         // If in BSS section, no allocation required
205         if (scattr & SBSS)
206                 return;
207
208         if (amt == 0)
209                 amt = CH_THRESHOLD;
210
211         DEBUG { printf("    challoc=%i, ch_size=%i, diff=%i\n", challoc, ch_size, challoc - ch_size); }
212
213         if ((int)(challoc - ch_size) >= (int)amt)
214                 return;
215
216         if (amt < CH_CODE_SIZE)
217                 amt = CH_CODE_SIZE;
218
219         DEBUG { printf("    amt (adjusted)=%u\n", amt); }
220         SECT * p = &sect[cursect];
221         CHUNK * cp = malloc(sizeof(CHUNK) + amt);
222         int first = 0;
223
224         if (scode == NULL)
225         {
226                 // First chunk in section
227                 cp->chprev = NULL;
228                 p->sfcode = cp;
229                 first = 1;
230         }
231         else
232         {
233                 // Add second and on to previous chunk
234                 cp->chprev = scode;
235                 scode->chnext = cp;
236                 scode->ch_size = ch_size;       // Save old chunk's globals
237         }
238
239         // Setup chunk and global vars
240 /*
241 So, whenever there's an ORG in a 56K section, it sets sloc TO THE ADDRESS IN THE ORG.  Also, the loc/sloc are incremented by 1s, which means to alias correctly to the byte-oriented memory model we have here, we have to fix that kind of crap.
242 */
243         cp->chloc = sloc; // <-- HERE'S THE PROBLEM FOR 56K  :-/
244         cp->chnext = NULL;
245         challoc = cp->challoc = amt;
246         ch_size = cp->ch_size = 0;
247         chptr = cp->chptr = ((uint8_t *)cp) + sizeof(CHUNK);
248         scode = p->scode = cp;
249
250         // A quick kludge
251 /*
252 OK, so this is a bit shite, but at least it gets things working the way they should.  The right way to do this is not rely on sloc & friends for the right fixup address but to have an accurate model of the thing.  That will probably come with v2.0.1  :-P
253
254 So the problem is, d_org sets sloc to the address of the ORG statement, and that gives an incorrect base for the fixup.  And so when a second (or later) chunk is allocated, it gets set wrong.  Further complicating things is that the orgaddress *does not* get used in a typical way with the DSP56001 code, and, as such, causes incorrect addresses to be generated.  All that has to be dealt with in order to get this right and do away with this kludge.
255 */
256         if (((cursect == M56001P) || (cursect == M56001X) || (cursect == M56001Y)) && !first)
257                 cp->chloc = cp->chprev->chloc + cp->chprev->ch_size;
258
259         return;
260 }
261
262
263 //
264 // Arrange for a fixup on a location
265 //
266 int AddFixup(uint32_t attr, uint32_t loc, TOKEN * fexpr)
267 {
268         uint16_t exprlen = 0;
269         SYM * symbol = NULL;
270         uint32_t _orgaddr = 0;
271
272         // First, check to see if the expression is a bare label, otherwise, force
273         // the FU_EXPR flag into the attributes and count the tokens.
274         if ((fexpr[0] == SYMBOL) && (fexpr[2] == ENDEXPR))
275         {
276                 symbol = symbolPtr[fexpr[1]];
277
278                 // Save the org address for JR RISC instruction
279                 if ((attr & FUMASKRISC) == FU_JR)
280                         _orgaddr = orgaddr;
281         }
282         else
283         {
284                 attr |= FU_EXPR;
285                 exprlen = ExpressionLength(fexpr);
286         }
287
288         // Second, check to see if it's a DSP56001 fixup, and force the FU_56001
289         // flag into the attributes if so; also save the current org address.
290         if (attr & FUMASKDSP)
291         {
292                 attr |= FU_56001;
293                 // Save the exact spot in this chunk where the fixup should go
294                 _orgaddr = chptr - scode->chptr + scode->chloc;
295         }
296
297         // Allocate space for the fixup + any expression
298         FIXUP * fixup = malloc(sizeof(FIXUP) + (sizeof(TOKEN) * exprlen)*2);
299
300         // Store the relevant fixup information in the FIXUP
301         fixup->next = NULL;
302         fixup->attr = attr;
303         fixup->loc = loc;
304         fixup->fileno = cfileno;
305         fixup->lineno = curlineno;
306         fixup->expr = NULL;
307         fixup->symbol = symbol;
308         fixup->orgaddr = _orgaddr;
309
310         // Copy the passed in expression to the FIXUP, if any
311         if (exprlen > 0)
312         {
313                 // Here we used to to a plain memcpy and punt on trying to evaluate the expression by then.
314                 // As discussed in bug #176, this can lead to robustness issues because some symbols might
315                 // have changed by the time we perform the relocations (think of a symbol that's SET multiple
316                 // times). So instead we perform a symbol-by-symbol copy and check to see if there are any
317                 // resolved symbols that can be evaluated immediately. Those, we replace with constants.
318                 // Also of note: because "fixup" can be larger than what ExpressionLength() returns
319                 // (due to constants taking up more space than symbols), we allocate twice as RAM as we should
320                 // without expansions just to be on the safe side. The "correct" thing to do would be to
321                 // modify ExpressionLength() to cater for defined symbols and return the exact amount of items.
322
323                 fixup->expr = (TOKEN *)((uint8_t *)fixup + sizeof(FIXUP));
324                 int i;
325                 PTR dstexpr;
326                 dstexpr.u32 = fixup->expr;
327                 SYM *sy;
328                 for (i = 0; i < exprlen; i++)
329                 {
330                         if (*fexpr == SYMBOL)
331                         {
332                                 sy = symbolPtr[fexpr[1]];
333                                 if (sy->sattr & DEFINED && !(sy->sattr & (TDB| M56KPXYL|M6502)))
334                                 {
335                                         // Only convert symbols that are defined and are absolute
336                                         *dstexpr.u32++ = CONST;
337                                         *dstexpr.u64++ = sy->svalue;
338                                         fexpr += 2;
339                                         i++;
340                                 }
341                                 else
342                                 {
343                                         // Just copy the symbol
344                                         *dstexpr.u32++ = *fexpr++;
345                                         *dstexpr.u32++ = *fexpr++;
346                                         i++;
347                                 }
348                         }
349                         else if (*fexpr == CONST || *fexpr == FCONST)
350                         {
351                                 // Copy constants
352                                 *dstexpr.u32++ = *fexpr++;
353                                 *dstexpr.u32++ = *fexpr++;
354                                 *dstexpr.u32++ = *fexpr++;
355                                 i += 2;
356                         }
357                         else
358                                 *dstexpr.u32++ = *fexpr++;
359                 }
360         }
361
362         // Finally, put the FIXUP in the current section's linked list
363         if (sect[cursect].sffix == NULL)
364         {
365                 sect[cursect].sffix = fixup;
366                 sect[cursect].sfix = fixup;
367         }
368         else
369         {
370                 sect[cursect].sfix->next = fixup;
371                 sect[cursect].sfix = fixup;
372         }
373
374         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);
375                 if (symbol != NULL)
376                         printf("          name: %s, value: $%lX\n", symbol->sname, symbol->svalue);
377         }
378
379         return 0;
380 }
381
382
383 //
384 // Resolve fixups in the passed in section
385 //
386 int ResolveFixups(int sno)
387 {
388         SECT * sc = &sect[sno];
389
390         // "Cache" first chunk
391         CHUNK * cch = sc->sfcode;
392
393         // Can't fixup a section with nothing in it
394         if (cch == NULL)
395                 return 0;
396
397         // Wire the 6502 segment's size to its allocated size (64K)
398         if (sno == M6502)
399                 cch->ch_size = cch->challoc;
400
401         // Get first fixup for the passed in section
402         FIXUP * fixup = sect[sno].sffix;
403
404         while (fixup != NULL)
405         {
406                 // We do it this way because we have continues everywhere... :-P
407                 FIXUP * fup = fixup;
408                 fixup = fixup->next;
409
410                 uint32_t dw = fup->attr;        // Fixup long (type + modes + flags)
411                 uint32_t loc = fup->loc;        // Location to fixup
412                 cfileno = fup->fileno;
413                 curlineno = fup->lineno;
414                 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); }
415
416                 // This is based on global vars cfileno, curfname :-P
417                 // This approach is kinda meh as well. I think we can do better
418                 // than this.
419                 SetFilenameForErrorReporting();
420
421                 if ((sno == M56001P) || (sno == M56001X) || (sno == M56001Y) || (sno == M56001L))
422                         loc = fup->orgaddr;
423
424                 // Search for chunk containing location to fix up; compute a
425                 // pointer to the location (in the chunk). Often we will find the
426                 // Fixup is in the "cached" chunk, so the linear-search is seldom
427                 // executed.
428                 if (loc < cch->chloc || loc >= (cch->chloc + cch->ch_size))
429                 {
430                         for(cch=sc->sfcode; cch!=NULL; cch=cch->chnext)
431                         {
432                                 if (loc >= cch->chloc && loc < (cch->chloc + cch->ch_size))
433                                         break;
434                         }
435
436                         if (cch == NULL)
437                         {
438                                 // Fixup (loc) is out of range--this should never happen!
439                                 // Once we call this function, it winds down immediately; it
440                                 // doesn't return.
441                                 interror(7);
442                         }
443                 }
444
445                 // Location to fix (in current chunk)
446                 // We use the address of the chunk that loc is actually in, then
447                 // subtract the chunk's starting location from loc to get the offset
448                 // into the current chunk.
449                 uint8_t * locp = cch->chptr + (loc - cch->chloc);
450
451                 uint16_t eattr = 0;                     // Expression attrib
452                 SYM * esym = NULL;                      // External symbol involved in expr
453                 uint64_t eval;                          // Expression value
454                 uint16_t flags;                         // Mark flags
455
456                 // Compute expression/symbol value and attributes
457
458                 // Complex expression
459                 if (dw & FU_EXPR)
460                 {
461                         // evexpr presumably issues the errors/warnings here
462                         if (evexpr(fup->expr, &eval, &eattr, &esym) != OK)
463                                 continue;
464
465                         if (esym)
466                                 if (!(esym->sattr & DEFINED) && eval==0)
467                                 {
468                                         // If our expression still has an undefined symbol at this stage, it's bad news.
469                                         // The linker is never going to resolve the expression, so that's an error.
470                                         error("cannot export complex expression with unresloved symbol '%s'", esym->sname);
471                                         continue;
472                                 }
473
474                         if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & (DEFINED | REFERENCED | EQUATED)) == (DEFINED | REFERENCED))
475                         {
476                                 error("relocation not allowed when o30 is enabled");
477                                 continue;
478                         }
479                 }
480                 // Simple symbol
481                 else
482                 {
483                         SYM * sy = fup->symbol;
484                         eattr = sy->sattr;
485
486                         if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & (DEFINED | REFERENCED | EQUATED)) == (DEFINED | REFERENCED))
487                         {
488                                 error("relocation not allowed when o30 is enabled");
489                                 continue;
490                         }
491
492                         if (eattr & DEFINED)
493                                 eval = sy->svalue;
494                         else
495                                 eval = 0;
496
497                         // If the symbol is not defined, but global, set esym to sy
498                         if ((eattr & (GLOBAL | DEFINED)) == GLOBAL)
499                                 esym = sy;
500
501                         DEBUG { printf("               name: %s, value: $%" PRIX64 "\n", sy->sname, sy->svalue); }
502                 }
503
504                 uint16_t tdb = eattr & TDB;
505
506                 // If the expression/symbol is undefined and no external symbol is
507                 // involved, then that's an error.
508                 if (!(eattr & DEFINED) && (esym == NULL))
509                 {
510                         error(undef_error);
511                         continue;
512                 }
513
514                 // Do the fixup
515                 //
516                 // If a PC-relative fixup is undefined, its value is *not* subtracted
517                 // from the location (that will happen in the linker when the external
518                 // reference is resolved).
519                 //
520                 // PC-relative fixups must be DEFINED and either in the same section
521                 // (whereupon the subtraction takes place) or ABS (with no subtract).
522                 if ((dw & FU_PCREL) || (dw & FU_PCRELX))
523                 {
524                         if (eattr & DEFINED)
525                         {
526                                 if (tdb == sno)
527                                 {
528                                         eval -= loc;
529
530                                         // In this instruction the PC is located a DWORD away
531                                         if (dw & FU_PCRELX)
532                                                 eval += 2;
533                                 }
534                                 else if (tdb)
535                                 {
536                                         // Allow cross-section PCREL fixups in Alcyon mode
537                                         if (prg_flag || (obj_format == RAW))
538                                         {
539                                                 switch (tdb)
540                                                 {
541                                                 case TEXT:
542 // Shouldn't there be a break here, since otherwise, it will point to the DATA section?
543 //                                                      break;
544                                                 case DATA:
545                                                         eval += sect[TEXT].sloc;
546                                                         break;
547                                                 case BSS:
548                                                         eval += sect[TEXT].sloc + sect[DATA].sloc;
549                                                         break;
550                                                 default:
551                                                         error("invalid section");
552                                                 break;
553                                                 }
554
555                                                 eval -= loc;
556
557                                                 // In this instruction the PC is located a DWORD away
558                                                 if (dw & FU_PCRELX)
559                                                         eval += 2;
560                                                 
561                                                 if ((int64_t)eval > 0x7fff || (int64_t)eval < -32768)
562                                                         error(range_error);
563                                         }
564                                         else
565                                         {
566                                                 error("PC-relative expr across sections");
567                                                 continue;
568                                         }
569                                 }
570
571                                 if (optim_warn_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
572                                         warn("unoptimized short branch");
573                         }
574
575                         // Be sure to clear any TDB flags, since we handled it just now
576                         tdb = 0;
577                         eattr &= ~TDB;
578                 }
579
580                 // Handle fixup classes
581                 switch (dw & FUMASK)
582                 {
583                 // FU_BBRA fixes up a one-byte branch offset.
584                 case FU_BBRA:
585                         if (!(eattr & DEFINED))
586                         {
587                                 error("external short branch");
588                                 continue;
589                         }
590
591                         eval -= 2;
592
593                         if (eval + 0x80 >= 0x100)
594                                 goto rangeErr;
595
596                         if (eval == 0)
597                         {
598                                 if (*locp) // optim_flags[OPT_NULL_BRA] is stored there, check the comment in mach.s under m_br
599                                 {
600                                         // Just output a NOP
601                                         *locp++ = 0x4E;
602                                         *locp = 0x71;
603
604                                         if (optim_warn_flag)
605                                                 warn("o6: bra.s with zero offset converted to NOP");
606
607                                         continue;
608                                 }
609                                 else
610                                 {
611                                         error("illegal bra.s with zero offset");
612                                         continue;
613                                 }
614                         }
615
616                         *++locp = (uint8_t)eval;
617                         break;
618
619                 // Fixup one-byte value at locp + 1.
620                 case FU_WBYTE:
621                         locp++;
622                         // FALLTHROUGH
623
624                 // Fixup one-byte forward references
625                 case FU_BYTE:
626                         if (!(eattr & DEFINED))
627                         {
628                                 error("external byte reference");
629                                 continue;
630                         }
631
632                         if (tdb)
633                         {
634                                 error("non-absolute byte reference");
635                                 continue;
636                         }
637
638                         if ((dw & FU_PCREL) && ((eval + 0x80) >= 0x100))
639                                 goto rangeErr;
640
641                         if (dw & FU_SEXT)
642                         {
643                                 if ((eval + 0x100) >= 0x200)
644                                         goto rangeErr;
645                         }
646                         else if (eval >= 0x100)
647                                 goto rangeErr;
648
649                         *locp = (uint8_t)eval;
650                         break;
651
652                 // Fixup high/low byte off word for 6502
653                 case FU_BYTEH:
654                         if (!(eattr & DEFINED))
655                         {
656                                 error("external byte reference");
657                                 continue;
658                         }
659
660                         *locp = (uint8_t)(eval >> 8);
661                         break;
662
663                 case FU_BYTEL:
664                         if (!(eattr & DEFINED))
665                         {
666                                 error("external byte reference");
667                                 continue;
668                         }
669
670                         *locp = (uint8_t)eval;
671                         break;
672
673                 // Fixup WORD forward references; the word could be unaligned in the
674                 // section buffer, so we have to be careful. (? careful about what?)
675                 case FU_WORD:
676                         if ((dw & FUMASKRISC) == FU_JR)
677                         {
678                                 int reg = (signed)((eval - ((fup->orgaddr ? fup->orgaddr : loc) + 2)) / 2);
679
680                                 if ((reg < -16) || (reg > 15))
681                                 {
682                                         error("relative jump out of range");
683                                         break;
684                                 }
685
686                                 *locp |= ((uint8_t)reg >> 3) & 0x03;
687                                 locp++;
688                                 *locp |= ((uint8_t)reg & 0x07) << 5;
689                                 break;
690                         }
691                         else if ((dw & FUMASKRISC) == FU_NUM15)
692                         {
693                                 if (((int)eval < -16) || ((int)eval > 15))
694                                 {
695                                         error("constant out of range (-16 - +15)");
696                                         break;
697                                 }
698
699                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
700                                 locp++;
701                                 *locp |= ((uint8_t)eval & 0x07) << 5;
702                                 break;
703                         }
704                         else if ((dw & FUMASKRISC) == FU_NUM31)
705                         {
706                                 if (eval > 31)
707                                 {
708                                         error("constant out of range (0-31)");
709                                         break;
710                                 }
711
712                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
713                                 locp++;
714                                 *locp |= ((uint8_t)eval & 0x07) << 5;
715                                 break;
716                         }
717                         else if ((dw & FUMASKRISC) == FU_NUM32)
718                         {
719                                 if ((eval < 1) || (eval > 32))
720                                 {
721                                         error("constant out of range (1-32)");
722                                         break;
723                                 }
724
725                                 if (dw & FU_SUB32)
726                                         eval = (32 - eval);
727
728                                 eval = (eval == 32) ? 0 : eval;
729                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
730                                 locp++;
731                                 *locp |= ((uint8_t)eval & 0x07) << 5;
732                                 break;
733                         }
734                         else if ((dw & FUMASKRISC) == FU_REGONE)
735                         {
736                                 eval -= REGRISC_R0;
737                                 if (eval > 31)
738                                 {
739                                         error("register one value out of range");
740                                         break;
741                                 }
742
743                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
744                                 locp++;
745                                 *locp |= ((uint8_t)eval & 0x07) << 5;
746                                 break;
747                         }
748                         else if ((dw & FUMASKRISC) == FU_REGTWO)
749                         {
750                                 eval -= REGRISC_R0;
751                                 if (eval > 31)
752                                 {
753                                         error("register two value out of range");
754                                         break;
755                                 }
756
757                                 locp++;
758                                 *locp |= (uint8_t)eval & 0x1F;
759                                 break;
760                         }
761
762                         if (!(eattr & DEFINED))
763                         {
764                                 flags = MWORD;
765
766                                 if (dw & FU_PCREL)
767                                         flags |= MPCREL;
768
769                                 MarkRelocatable(sno, loc, 0, flags, esym);
770                         }
771                         else
772                         {
773                                 if (tdb)
774                                         MarkRelocatable(sno, loc, tdb, MWORD, NULL);
775
776                                 if (dw & FU_SEXT)
777                                 {
778                                         if (eval + 0x10000 >= 0x20000)
779                                                 goto rangeErr;
780                                 }
781                                 else
782                                 {
783                                         // Range-check BRA and DBRA
784                                         if (dw & FU_ISBRA)
785                                         {
786                                                 if (eval + 0x8000 >= 0x10000)
787                                                         goto rangeErr;
788                                         }
789                                         else if (eval >= 0x10000)
790                                                 goto rangeErr;
791                                 }
792                         }
793
794                         // 6502 words are little endian, so handle that here
795                         if (sno == M6502)
796                                 SETLE16(locp, 0, eval)
797                         else
798                                 SETBE16(locp, 0, eval)
799
800                         break;
801
802                 // Fixup LONG forward references; the long could be unaligned in the
803                 // section buffer, so be careful (again).
804                 case FU_LONG:
805                         flags = MLONG;
806
807                         if ((dw & FUMASKRISC) == FU_MOVEI)
808                         {
809                                 // Long constant in MOVEI # is word-swapped, so fix it here
810                                 eval = WORDSWAP32(eval);
811                                 flags |= MMOVEI;
812                         }
813
814                         // If the symbol is undefined, make sure to pass the symbol in
815                         // to the MarkRelocatable() function.
816                         if (!(eattr & DEFINED))
817                                 MarkRelocatable(sno, loc, 0, flags, esym);
818                         else if (tdb)
819                                 MarkRelocatable(sno, loc, tdb, flags, NULL);
820
821                         SETBE32(locp, 0, eval);
822                         break;
823
824                 // Fixup QUAD forward references (mainly used by the OP assembler)
825                 case FU_QUAD:
826                         if (dw & FU_OBJLINK)
827                         {
828                                 uint64_t quad = GETBE64(locp, 0);
829                                 uint64_t addr = eval;
830
831 //Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR...  :-/
832 //                              if (fup->orgaddr)
833 //                                      addr = fup->orgaddr;
834
835                                 eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21);
836                         }
837                         else if (dw & FU_OBJDATA)
838                         {
839                                 // If it's in a TEXT or DATA section, be sure to mark for a
840                                 // fixup later
841                                 if (tdb)
842                                         MarkRelocatable(sno, loc, tdb, MQUAD, NULL);
843
844                                 uint64_t quad = GETBE64(locp, 0);
845                                 uint64_t addr = eval;
846
847 //Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR...  :-/
848 //                              if (fup->orgaddr)
849 //                                      addr = fup->orgaddr;
850
851                                 eval = (quad & 0x000007FFFFFFFFFFLL) | ((addr & 0xFFFFF8) << 40);
852                         }
853
854                         SETBE64(locp, 0, eval);
855                         break;
856
857                 // Fixup a 3-bit "QUICK" reference in bits 9..1
858                 // (range of 1..8) in a word. [Really bits 1..3 in a byte.]
859                 case FU_QUICK:
860                         if (!(eattr & DEFINED))
861                         {
862                                 error("External quick reference");
863                                 continue;
864                         }
865
866                         if ((eval < 1) || (eval > 8))
867                                 goto rangeErr;
868
869                         *locp |= (eval & 7) << 1;
870                         break;
871
872                 // Fix up 6502 funny branch
873                 case FU_6BRA:
874                         eval -= (loc + 1);
875
876                         if (eval + 0x80 >= 0x100)
877                                 goto rangeErr;
878
879                         *locp = (uint8_t)eval;
880                         break;
881
882                 // Fixup DSP56001 addresses
883                 case FU_56001:
884                         switch (dw & FUMASKDSP)
885                         {
886                         // DSPIMM5 actually is clamped from 0 to 23 for our purposes
887                         // and does not use the full 5 bit range.
888                         case FU_DSPIMM5:
889                                 if (eval > 23)
890                                 {
891                                         error("immediate value must be between 0 and 23");
892                                         break;
893                                 }
894
895                                 locp[2] |= eval;
896                                 break;
897
898                         // This is a 12-bit address encoded into the lower 12
899                         // bits of a DSP word
900                         case FU_DSPADR12:
901                                 if (eval >= 0x1000)
902                                 {
903                                         error("address out of range ($0-$FFF)");
904                                         break;
905                                 }
906
907                                 locp[1] |= eval >> 8;
908                                 locp[2] = eval & 0xFF;
909                                 break;
910
911                         // This is a full DSP word containing Effective Address Extension
912                         case FU_DSPADR24:
913                         case FU_DSPIMM24:
914                                 if (eval >= 0x1000000)
915                                 {
916                                         error("value out of range ($0-$FFFFFF)");
917                                         break;
918                                 }
919
920                                 locp[0] = (uint8_t)((eval >> 16) & 0xFF);
921                                 locp[1] = (uint8_t)((eval >> 8) & 0xFF);
922                                 locp[2] = (uint8_t)(eval & 0xFF);
923                                 break;
924
925                         // This is a 16bit absolute address into a 24bit field
926                         case FU_DSPADR16:
927                                 if (eval >= 0x10000)
928                                 {
929                                         error("address out of range ($0-$FFFF)");
930                                         break;
931                                 }
932
933                                 locp[1] = (uint8_t)(eval >> 8);
934                                 locp[2] = (uint8_t)eval;
935                                 break;
936
937                         // This is 12-bit immediate short data
938                         // The upper nibble goes into the last byte's low nibble
939                         // while the remainder 8 bits go into the 2nd byte.
940                         case FU_DSPIMM12:
941                                 if (eval >= 0x1000)
942                                 {
943                                         error("immediate out of range ($0-$FFF)");
944                                         break;
945                                 }
946
947                                 locp[1] = (uint8_t)eval;
948                                 locp[2] |= (uint8_t)(eval >> 8);
949                                 break;
950
951                         // This is 8-bit immediate short data
952                         // which goes into the middle byte of a DSP word.
953                         case FU_DSPIMM8:
954                                 if (eval >= 0x100)
955                                 {
956                                         error("immediate out of range ($0-$FF)");
957                                         break;
958                                 }
959
960                                 locp[1] = (uint8_t)eval;
961                                 break;
962
963                         // This is a 6 bit absoulte short address. It occupies the low 6
964                         // bits of the middle byte of a DSP word.
965                         case FU_DSPADR06:
966                                 if (eval > 63)
967                                 {
968                                         error("address must be between 0 and 63");
969                                         break;
970                                 }
971
972                                 locp[1] |= eval;
973                                 break;
974
975                         // This is a 6 bit absoulte short address. It occupies the low 6
976                         // bits of the middle byte of a DSP word.
977                         case FU_DSPPP06:
978                                 if (eval < 0xFFFFFFC0)
979                                 {
980                                         error("address must be between $FFC0 and $FFFF");
981                                         break;
982                                 }
983
984                                 locp[1] |= eval & 0x3F;
985                                 break;
986
987                         // Shamus: I'm pretty sure these don't make any sense...
988                         case FU_DSPIMMFL8:
989                                 warn("FU_DSPIMMFL8 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
990                                 break;
991
992                         case FU_DSPIMMFL16:
993                                 warn("FU_DSPIMMFL16 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
994                                 break;
995
996                         case FU_DSPIMMFL24:
997                                 warn("FU_DSPIMMFL24 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
998                                 break;
999
1000                         // Bad fixup type--this should *never* happen!
1001                         default:
1002                                 interror(4);
1003                                 // NOTREACHED
1004                         }
1005                         break;
1006
1007                 // Fixup a 4-byte float
1008                 case FU_FLOATSING:
1009                         warn("FU_FLOATSING missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
1010                         break;
1011
1012                 // Fixup a 8-byte float
1013                 case FU_FLOATDOUB:
1014                         warn("FU_FLOATDOUB missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
1015                         break;
1016
1017                 // Fixup a 12-byte float
1018                 case FU_FLOATEXT:
1019                         warn("FU_FLOATEXT missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
1020                         break;
1021
1022                 default:
1023                         // Bad fixup type--this should *never* happen!
1024                         // Once we call this function, it winds down immediately; it
1025                         // doesn't return.
1026                         interror(4);
1027                 }
1028
1029                 continue;
1030 rangeErr:
1031                 error("expression out of range");
1032         }
1033
1034         return 0;
1035 }
1036
1037
1038 //
1039 // Resolve all fixups
1040 //
1041 int ResolveAllFixups(void)
1042 {
1043         // Make undefined symbols GLOBL
1044         if (glob_flag)
1045                 ForceUndefinedSymbolsGlobal();
1046
1047         DEBUG printf("Resolving TEXT sections...\n");
1048         ResolveFixups(TEXT);
1049         DEBUG printf("Resolving DATA sections...\n");
1050         ResolveFixups(DATA);
1051         DEBUG printf("Resolving 6502 sections...\n");
1052         ResolveFixups(M6502);           // Fixup 6502 section (if any)
1053         DEBUG printf("Resolving DSP56001 P: sections...\n");
1054         ResolveFixups(M56001P);         // Fixup 56001 P: section (if any)
1055         DEBUG printf("Resolving DSP56001 X: sections...\n");
1056         ResolveFixups(M56001X);         // Fixup 56001 X: section (if any)
1057         DEBUG printf("Resolving DSP56001 Y: sections...\n");
1058         ResolveFixups(M56001Y);         // Fixup 56001 Y: section (if any)
1059
1060         return 0;
1061 }
1062