Slight revamp of the optimisation system, featuring: strengthened flag parser, slight...
[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-2020 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 (if any)
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         int first = 0;
222
223         if (scode == NULL)
224         {
225                 // First chunk in section
226                 cp->chprev = NULL;
227                 p->sfcode = cp;
228                 first = 1;
229         }
230         else
231         {
232                 // Add second and on to previous chunk
233                 cp->chprev = scode;
234                 scode->chnext = cp;
235                 scode->ch_size = ch_size;       // Save old chunk's globals
236         }
237
238         // Setup chunk and global vars
239 /*
240 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.
241 */
242         cp->chloc = sloc; // <-- HERE'S THE PROBLEM FOR 56K  :-/
243         cp->chnext = NULL;
244         challoc = cp->challoc = amt;
245         ch_size = cp->ch_size = 0;
246         chptr = cp->chptr = ((uint8_t *)cp) + sizeof(CHUNK);
247         scode = p->scode = cp;
248
249         // A quick kludge
250 /*
251 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
252
253 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.
254 */
255         if (((cursect == M56001P) || (cursect == M56001X) || (cursect == M56001Y)) && !first)
256                 cp->chloc = cp->chprev->chloc + cp->chprev->ch_size;
257
258         return;
259 }
260
261
262 //
263 // Arrange for a fixup on a location
264 //
265 int AddFixup(uint32_t attr, uint32_t loc, TOKEN * fexpr)
266 {
267         uint16_t exprlen = 0;
268         SYM * symbol = NULL;
269         uint32_t _orgaddr = 0;
270
271         // First, check to see if the expression is a bare label, otherwise, force
272         // the FU_EXPR flag into the attributes and count the tokens.
273         if ((fexpr[0] == SYMBOL) && (fexpr[2] == ENDEXPR))
274         {
275                 symbol = symbolPtr[fexpr[1]];
276
277                 // Save the org address for JR RISC instruction
278                 if ((attr & FUMASKRISC) == FU_JR)
279                         _orgaddr = orgaddr;
280         }
281         else
282         {
283                 attr |= FU_EXPR;
284                 exprlen = ExpressionLength(fexpr);
285         }
286
287         // Second, check to see if it's a DSP56001 fixup, and force the FU_56001
288         // flag into the attributes if so; also save the current org address.
289         if (attr & FUMASKDSP)
290         {
291                 attr |= FU_56001;
292                 // Save the exact spot in this chunk where the fixup should go
293                 _orgaddr = chptr - scode->chptr + scode->chloc;
294         }
295
296         // Allocate space for the fixup + any expression
297         FIXUP * fixup = malloc(sizeof(FIXUP) + (sizeof(TOKEN) * exprlen));
298
299         // Store the relevant fixup information in the FIXUP
300         fixup->next = NULL;
301         fixup->attr = attr;
302         fixup->loc = loc;
303         fixup->fileno = cfileno;
304         fixup->lineno = curlineno;
305         fixup->expr = NULL;
306         fixup->symbol = symbol;
307         fixup->orgaddr = _orgaddr;
308
309         // Copy the passed in expression to the FIXUP, if any
310         if (exprlen > 0)
311         {
312                 fixup->expr = (TOKEN *)((uint8_t *)fixup + sizeof(FIXUP));
313                 memcpy(fixup->expr, fexpr, sizeof(TOKEN) * exprlen);
314         }
315
316         // Finally, put the FIXUP in the current section's linked list
317         if (sect[cursect].sffix == NULL)
318         {
319                 sect[cursect].sffix = fixup;
320                 sect[cursect].sfix = fixup;
321         }
322         else
323         {
324                 sect[cursect].sfix->next = fixup;
325                 sect[cursect].sfix = fixup;
326         }
327
328         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);
329                 if (symbol != NULL)
330                         printf("          name: %s, value: $%lX\n", symbol->sname, symbol->svalue);
331         }
332
333         return 0;
334 }
335
336
337 //
338 // Resolve fixups in the passed in section
339 //
340 int ResolveFixups(int sno)
341 {
342         SECT * sc = &sect[sno];
343
344         // "Cache" first chunk
345         CHUNK * cch = sc->sfcode;
346
347         // Can't fixup a section with nothing in it
348         if (cch == NULL)
349                 return 0;
350
351         // Wire the 6502 segment's size to its allocated size (64K)
352         if (sno == M6502)
353                 cch->ch_size = cch->challoc;
354
355         // Get first fixup for the passed in section
356         FIXUP * fixup = sect[sno].sffix;
357
358         while (fixup != NULL)
359         {
360                 // We do it this way because we have continues everywhere... :-P
361                 FIXUP * fup = fixup;
362                 fixup = fixup->next;
363
364                 uint32_t dw = fup->attr;        // Fixup long (type + modes + flags)
365                 uint32_t loc = fup->loc;        // Location to fixup
366                 cfileno = fup->fileno;
367                 curlineno = fup->lineno;
368                 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); }
369
370                 // This is based on global vars cfileno, curfname :-P
371                 // This approach is kinda meh as well. I think we can do better
372                 // than this.
373                 SetFilenameForErrorReporting();
374
375                 if ((sno == M56001P) || (sno == M56001X) || (sno == M56001Y) || (sno == M56001L))
376                         loc = fup->orgaddr;
377
378                 // Search for chunk containing location to fix up; compute a
379                 // pointer to the location (in the chunk). Often we will find the
380                 // Fixup is in the "cached" chunk, so the linear-search is seldom
381                 // executed.
382                 if (loc < cch->chloc || loc >= (cch->chloc + cch->ch_size))
383                 {
384                         for(cch=sc->sfcode; cch!=NULL; cch=cch->chnext)
385                         {
386                                 if (loc >= cch->chloc && loc < (cch->chloc + cch->ch_size))
387                                         break;
388                         }
389
390                         if (cch == NULL)
391                         {
392                                 // Fixup (loc) is out of range--this should never happen!
393                                 // Once we call this function, it winds down immediately; it
394                                 // doesn't return.
395                                 interror(7);
396                         }
397                 }
398
399                 // Location to fix (in current chunk)
400                 // We use the address of the chunk that loc is actually in, then
401                 // subtract the chunk's starting location from loc to get the offset
402                 // into the current chunk.
403                 uint8_t * locp = cch->chptr + (loc - cch->chloc);
404
405                 uint16_t eattr = 0;                     // Expression attrib
406                 SYM * esym = NULL;                      // External symbol involved in expr
407                 uint64_t eval;                          // Expression value
408                 uint16_t flags;                         // Mark flags
409
410                 // Compute expression/symbol value and attributes
411
412                 // Complex expression
413                 if (dw & FU_EXPR)
414                 {
415                         // evexpr presumably issues the errors/warnings here
416                         if (evexpr(fup->expr, &eval, &eattr, &esym) != OK)
417                                 continue;
418
419                         if (CHECK_OPTS(OPT_PC_RELATIVE))
420                                 if (eattr & REFERENCED)
421                                         if (eattr & DEFINED)
422                                                 if (!(eattr & EQUATED))
423                                                 {
424                                                         error("relocation not allowed");
425                                                         continue;
426                                                 }
427                 }
428                 // Simple symbol
429                 else
430                 {
431                         SYM * sy = fup->symbol;
432                         eattr = sy->sattr;
433
434                         if (CHECK_OPTS(OPT_PC_RELATIVE))
435                                 if (eattr & REFERENCED)
436                                         if (eattr & DEFINED)
437                                                 if (!(eattr & EQUATED))
438                                                 {
439                                                         error("relocation not allowed");
440                                                         continue;
441                                                 }
442
443                         if (eattr & DEFINED)
444                                 eval = sy->svalue;
445                         else
446                                 eval = 0;
447
448                         // If the symbol is not defined, but global, set esym to sy
449                         if ((eattr & (GLOBAL | DEFINED)) == GLOBAL)
450                                 esym = sy;
451
452                         DEBUG { printf("               name: %s, value: $%" PRIX64 "\n", sy->sname, sy->svalue); }
453                 }
454
455                 uint16_t tdb = eattr & TDB;
456
457                 // If the expression/symbol is undefined and no external symbol is
458                 // involved, then that's an error.
459                 if (!(eattr & DEFINED) && (esym == NULL))
460                 {
461                         error(undef_error);
462                         continue;
463                 }
464
465                 // Do the fixup
466                 //
467                 // If a PC-relative fixup is undefined, its value is *not* subtracted
468                 // from the location (that will happen in the linker when the external
469                 // reference is resolved).
470                 //
471                 // PC-relative fixups must be DEFINED and either in the same section
472                 // (whereupon the subtraction takes place) or ABS (with no subtract).
473                 if ((dw & FU_PCREL) || (dw & FU_PCRELX))
474                 {
475                         if (eattr & DEFINED)
476                         {
477                                 if (tdb == sno)
478                                 {
479                                         eval -= loc;
480
481                                         // In this instruction the PC is located a DWORD away
482                                         if (dw & FU_PCRELX)
483                                                 eval += 2;
484                                 }
485                                 else if (tdb)
486                                 {
487                                         // Allow cross-section PCREL fixups in Alcyon mode
488                                         if (prg_flag || (obj_format == RAW))
489                                         {
490                                                 switch (tdb)
491                                                 {
492                                                 case TEXT:
493 // Shouldn't there be a break here, since otherwise, it will point to the DATA section?
494 //                                                      break;
495                                                 case DATA:
496                                                         eval += sect[TEXT].sloc;
497                                                         break;
498                                                 case BSS:
499                                                         eval += sect[TEXT].sloc + sect[DATA].sloc;
500                                                         break;
501                                                 default:
502                                                         error("invalid section");
503                                                 break;
504                                                 }
505
506                                                 eval -= loc;
507
508                                                 // In this instruction the PC is located a DWORD away
509                                                 if (dw & FU_PCRELX)
510                                                         eval += 2;
511                                         }
512                                         else
513                                         {
514                                                 error("PC-relative expr across sections");
515                                                 continue;
516                                         }
517                                 }
518
519                                 if (optim_warn_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
520                                         warn("unoptimized short branch");
521                         }
522
523                         // Be sure to clear any TDB flags, since we handled it just now
524                         tdb = 0;
525                         eattr &= ~TDB;
526                 }
527
528                 // Handle fixup classes
529                 switch (dw & FUMASK)
530                 {
531                 // FU_BBRA fixes up a one-byte branch offset.
532                 case FU_BBRA:
533                         if (!(eattr & DEFINED))
534                         {
535                                 error("external short branch");
536                                 continue;
537                         }
538
539                         eval -= 2;
540
541                         if (eval + 0x80 >= 0x100)
542                                 goto rangeErr;
543
544                         if (eval == 0)
545                         {
546                                 if (*locp) // optim_flags[OPT_NULL_BRA] is stored there, check the comment in mach.s under m_br
547                                 {
548                                         // Just output a NOP
549                                         *locp++ = 0x4E;
550                                         *locp = 0x71;
551                                         if (optim_warn_flag)
552                                                 warn("bra.s with zero offset converted to NOP");
553                                         continue;
554                                 }
555                                 else
556                                 {
557                                         error("illegal bra.s with zero offset");
558                                         continue;
559                                 }
560                         }
561
562                         *++locp = (uint8_t)eval;
563                         break;
564
565                 // Fixup one-byte value at locp + 1.
566                 case FU_WBYTE:
567                         locp++;
568                         // FALLTHROUGH
569
570                 // Fixup one-byte forward references
571                 case FU_BYTE:
572                         if (!(eattr & DEFINED))
573                         {
574                                 error("external byte reference");
575                                 continue;
576                         }
577
578                         if (tdb)
579                         {
580                                 error("non-absolute byte reference");
581                                 continue;
582                         }
583
584                         if ((dw & FU_PCREL) && ((eval + 0x80) >= 0x100))
585                                 goto rangeErr;
586
587                         if (dw & FU_SEXT)
588                         {
589                                 if ((eval + 0x100) >= 0x200)
590                                         goto rangeErr;
591                         }
592                         else if (eval >= 0x100)
593                                 goto rangeErr;
594
595                         *locp = (uint8_t)eval;
596                         break;
597
598                 // Fixup high/low byte off word for 6502
599                 case FU_BYTEH:
600                         if (!(eattr & DEFINED))
601                         {
602                                 error("external byte reference");
603                                 continue;
604                         }
605
606                         *locp = (uint8_t)(eval >> 8);
607                         break;
608
609                 case FU_BYTEL:
610                         if (!(eattr & DEFINED))
611                         {
612                                 error("external byte reference");
613                                 continue;
614                         }
615
616                         *locp = (uint8_t)eval;
617                         break;
618
619                 // Fixup WORD forward references; the word could be unaligned in the
620                 // section buffer, so we have to be careful. (? careful about what?)
621                 case FU_WORD:
622                         if ((dw & FUMASKRISC) == FU_JR)
623                         {
624                                 int reg = (signed)((eval - ((fup->orgaddr ? fup->orgaddr : loc) + 2)) / 2);
625
626                                 if ((reg < -16) || (reg > 15))
627                                 {
628                                         error("relative jump out of range");
629                                         break;
630                                 }
631
632                                 *locp |= ((uint8_t)reg >> 3) & 0x03;
633                                 locp++;
634                                 *locp |= ((uint8_t)reg & 0x07) << 5;
635                                 break;
636                         }
637                         else if ((dw & FUMASKRISC) == FU_NUM15)
638                         {
639                                 if (((int)eval < -16) || ((int)eval > 15))
640                                 {
641                                         error("constant out of range (-16 - +15)");
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_NUM31)
651                         {
652                                 if (eval > 31)
653                                 {
654                                         error("constant out of range (0-31)");
655                                         break;
656                                 }
657
658                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
659                                 locp++;
660                                 *locp |= ((uint8_t)eval & 0x07) << 5;
661                                 break;
662                         }
663                         else if ((dw & FUMASKRISC) == FU_NUM32)
664                         {
665                                 if ((eval < 1) || (eval > 32))
666                                 {
667                                         error("constant out of range (1-32)");
668                                         break;
669                                 }
670
671                                 if (dw & FU_SUB32)
672                                         eval = (32 - eval);
673
674                                 eval = (eval == 32) ? 0 : eval;
675                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
676                                 locp++;
677                                 *locp |= ((uint8_t)eval & 0x07) << 5;
678                                 break;
679                         }
680                         else if ((dw & FUMASKRISC) == FU_REGONE)
681                         {
682                                 if (eval > 31)
683                                 {
684                                         error("register one value out of range");
685                                         break;
686                                 }
687
688                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
689                                 locp++;
690                                 *locp |= ((uint8_t)eval & 0x07) << 5;
691                                 break;
692                         }
693                         else if ((dw & FUMASKRISC) == FU_REGTWO)
694                         {
695                                 if (eval > 31)
696                                 {
697                                         error("register two value out of range");
698                                         break;
699                                 }
700
701                                 locp++;
702                                 *locp |= (uint8_t)eval & 0x1F;
703                                 break;
704                         }
705
706                         if (!(eattr & DEFINED))
707                         {
708                                 flags = MWORD;
709
710                                 if (dw & FU_PCREL)
711                                         flags |= MPCREL;
712
713                                 MarkRelocatable(sno, loc, 0, flags, esym);
714                         }
715                         else
716                         {
717                                 if (tdb)
718                                         MarkRelocatable(sno, loc, tdb, MWORD, NULL);
719
720                                 if (dw & FU_SEXT)
721                                 {
722                                         if (eval + 0x10000 >= 0x20000)
723                                                 goto rangeErr;
724                                 }
725                                 else
726                                 {
727                                         // Range-check BRA and DBRA
728                                         if (dw & FU_ISBRA)
729                                         {
730                                                 if (eval + 0x8000 >= 0x10000)
731                                                         goto rangeErr;
732                                         }
733                                         else if (eval >= 0x10000)
734                                                 goto rangeErr;
735                                 }
736                         }
737
738                         // 6502 words are little endian, so handle that here
739                         if (sno == M6502)
740                                 SETLE16(locp, 0, eval)
741                         else
742                                 SETBE16(locp, 0, eval)
743
744                         break;
745
746                 // Fixup LONG forward references; the long could be unaligned in the
747                 // section buffer, so be careful (again).
748                 case FU_LONG:
749                         flags = MLONG;
750
751                         if ((dw & FUMASKRISC) == FU_MOVEI)
752                         {
753                                 // Long constant in MOVEI # is word-swapped, so fix it here
754                                 eval = WORDSWAP32(eval);
755                                 flags |= MMOVEI;
756                         }
757
758                         // If the symbol is undefined, make sure to pass the symbol in
759                         // to the MarkRelocatable() function.
760                         if (!(eattr & DEFINED))
761                                 MarkRelocatable(sno, loc, 0, flags, esym);
762                         else if (tdb)
763                                 MarkRelocatable(sno, loc, tdb, flags, NULL);
764
765                         SETBE32(locp, 0, eval);
766                         break;
767
768                 // Fixup QUAD forward references (mainly used by the OP assembler)
769                 case FU_QUAD:
770                         if (dw & FU_OBJLINK)
771                         {
772                                 uint64_t quad = GETBE64(locp, 0);
773                                 uint64_t addr = eval;
774
775 //Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR...  :-/
776 //                              if (fup->orgaddr)
777 //                                      addr = fup->orgaddr;
778
779                                 eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21);
780                         }
781                         else if (dw & FU_OBJDATA)
782                         {
783                                 // If it's in a TEXT or DATA section, be sure to mark for a
784                                 // fixup later
785                                 if (tdb)
786                                         MarkRelocatable(sno, loc, tdb, MQUAD, NULL);
787
788                                 uint64_t quad = GETBE64(locp, 0);
789                                 uint64_t addr = eval;
790
791 //Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR...  :-/
792 //                              if (fup->orgaddr)
793 //                                      addr = fup->orgaddr;
794
795                                 eval = (quad & 0x000007FFFFFFFFFFLL) | ((addr & 0xFFFFF8) << 40);
796                         }
797
798                         SETBE64(locp, 0, eval);
799                         break;
800
801                 // Fixup a 3-bit "QUICK" reference in bits 9..1
802                 // (range of 1..8) in a word. [Really bits 1..3 in a byte.]
803                 case FU_QUICK:
804                         if (!(eattr & DEFINED))
805                         {
806                                 error("External quick reference");
807                                 continue;
808                         }
809
810                         if ((eval < 1) || (eval > 8))
811                                 goto rangeErr;
812
813                         *locp |= (eval & 7) << 1;
814                         break;
815
816                 // Fix up 6502 funny branch
817                 case FU_6BRA:
818                         eval -= (loc + 1);
819
820                         if (eval + 0x80 >= 0x100)
821                                 goto rangeErr;
822
823                         *locp = (uint8_t)eval;
824                         break;
825
826                 // Fixup DSP56001 addresses
827                 case FU_56001:
828                         switch (dw & FUMASKDSP)
829                         {
830                         // DSPIMM5 actually is clamped from 0 to 23 for our purposes
831                         // and does not use the full 5 bit range.
832                         case FU_DSPIMM5:
833                                 if (eval > 23)
834                                 {
835                                         error("immediate value must be between 0 and 23");
836                                         break;
837                                 }
838
839                                 locp[2] |= eval;
840                                 break;
841
842                         // This is a 12-bit address encoded into the lower 12
843                         // bits of a DSP word
844                         case FU_DSPADR12:
845                                 if (eval >= 0x1000)
846                                 {
847                                         error("address out of range ($0-$FFF)");
848                                         break;
849                                 }
850
851                                 locp[1] |= eval >> 8;
852                                 locp[2] = eval & 0xFF;
853                                 break;
854
855                         // This is a full DSP word containing Effective Address Extension
856                         case FU_DSPADR24:
857                         case FU_DSPIMM24:
858                                 if (eval >= 0x1000000)
859                                 {
860                                         error("value out of range ($0-$FFFFFF)");
861                                         break;
862                                 }
863
864                                 locp[0] = (uint8_t)((eval >> 16) & 0xFF);
865                                 locp[1] = (uint8_t)((eval >> 8) & 0xFF);
866                                 locp[2] = (uint8_t)(eval & 0xFF);
867                                 break;
868
869                         // This is a 16bit absolute address into a 24bit field
870                         case FU_DSPADR16:
871                                 if (eval >= 0x10000)
872                                 {
873                                         error("address out of range ($0-$FFFF)");
874                                         break;
875                                 }
876
877                                 locp[1] = (uint8_t)(eval >> 8);
878                                 locp[2] = (uint8_t)eval;
879                                 break;
880
881                         // This is 12-bit immediate short data
882                         // The upper nibble goes into the last byte's low nibble
883                         // while the remainder 8 bits go into the 2nd byte.
884                         case FU_DSPIMM12:
885                                 if (eval >= 0x1000)
886                                 {
887                                         error("immediate out of range ($0-$FFF)");
888                                         break;
889                                 }
890
891                                 locp[1] = (uint8_t)eval;
892                                 locp[2] |= (uint8_t)(eval >> 8);
893                                 break;
894
895                         // This is 8-bit immediate short data
896                         // which goes into the middle byte of a DSP word.
897                         case FU_DSPIMM8:
898                                 if (eval >= 0x100)
899                                 {
900                                         error("immediate out of range ($0-$FF)");
901                                         break;
902                                 }
903
904                                 locp[1] = (uint8_t)eval;
905                                 break;
906
907                         // This is a 6 bit absoulte short address. It occupies
908                         // the low 6 bits of the middle byte of a DSP word.
909                         case FU_DSPADR06:
910                                 if (eval > 63)
911                                 {
912                                         error("address must be between 0 and 63");
913                                         break;
914                                 }
915
916                                 locp[1] |= eval;
917                                 break;
918
919                         // This is a 6 bit absoulte short address. It occupies
920                         // the low 6 bits of the middle byte of a DSP word.
921                         case FU_DSPPP06:
922                                 if (eval < 0xFFFFFFC0)
923                                 {
924                                         error("address must be between $FFC0 and $FFFF");
925                                         break;
926                                 }
927
928                                 locp[1] |= eval & 0x3F;
929                                 break;
930
931                         // Shamus: I'm pretty sure these don't make any sense...
932                         case FU_DSPIMMFL8:
933                                 warn("FU_DSPIMMFL8 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
934                                 break;
935
936                         case FU_DSPIMMFL16:
937                                 warn("FU_DSPIMMFL16 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
938                                 break;
939
940                         case FU_DSPIMMFL24:
941                                 warn("FU_DSPIMMFL24 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
942                                 break;
943
944                         // Bad fixup type--this should *never* happen!
945                         default:
946                                 interror(4);
947                                 // NOTREACHED
948                         }
949                         break;
950
951                 // Fixup a 4-byte float
952                 case FU_FLOATSING:
953                         warn("FU_FLOATSING missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
954                         break;
955
956                 // Fixup a 8-byte float
957                 case FU_FLOATDOUB:
958                         warn("FU_FLOATDOUB missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
959                         break;
960
961                 // Fixup a 12-byte float
962                 case FU_FLOATEXT:
963                         warn("FU_FLOATEXT missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
964                         break;
965
966                 default:
967                         // Bad fixup type--this should *never* happen!
968                         // Once we call this function, it winds down immediately; it
969                         // doesn't return.
970                         interror(4);
971                 }
972
973                 continue;
974 rangeErr:
975                 error("expression out of range");
976         }
977
978         return 0;
979 }
980
981
982 //
983 // Resolve all fixups
984 //
985 int ResolveAllFixups(void)
986 {
987         // Make undefined symbols GLOBL
988         if (glob_flag)
989                 ForceUndefinedSymbolsGlobal();
990
991         DEBUG printf("Resolving TEXT sections...\n");
992         ResolveFixups(TEXT);
993         DEBUG printf("Resolving DATA sections...\n");
994         ResolveFixups(DATA);
995         DEBUG printf("Resolving 6502 sections...\n");
996         ResolveFixups(M6502);           // Fixup 6502 section (if any)
997         DEBUG printf("Resolving DSP56001 P: sections...\n");
998         ResolveFixups(M56001P);         // Fixup 56001 P: section (if any)
999         DEBUG printf("Resolving DSP56001 X: sections...\n");
1000         ResolveFixups(M56001X);         // Fixup 56001 X: section (if any)
1001         DEBUG printf("Resolving DSP56001 Y: sections...\n");
1002         ResolveFixups(M56001Y);         // Fixup 56001 Y: section (if any)
1003
1004         return 0;
1005 }
1006