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