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