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