]> Shamusworld >> Repos - rmac/blob - sect.c
Removed some dead code, as well as all gpu/dsp regbank check code (not only it was...
[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_KW
22 #include "kwtab.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                                         else
553                                         {
554                                                 error("PC-relative expr across sections");
555                                                 continue;
556                                         }
557                                 }
558
559                                 if (optim_warn_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
560                                         warn("unoptimized short branch");
561                         }
562
563                         // Be sure to clear any TDB flags, since we handled it just now
564                         tdb = 0;
565                         eattr &= ~TDB;
566                 }
567
568                 // Handle fixup classes
569                 switch (dw & FUMASK)
570                 {
571                 // FU_BBRA fixes up a one-byte branch offset.
572                 case FU_BBRA:
573                         if (!(eattr & DEFINED))
574                         {
575                                 error("external short branch");
576                                 continue;
577                         }
578
579                         eval -= 2;
580
581                         if (eval + 0x80 >= 0x100)
582                                 goto rangeErr;
583
584                         if (eval == 0)
585                         {
586                                 if (*locp) // optim_flags[OPT_NULL_BRA] is stored there, check the comment in mach.s under m_br
587                                 {
588                                         // Just output a NOP
589                                         *locp++ = 0x4E;
590                                         *locp = 0x71;
591
592                                         if (optim_warn_flag)
593                                                 warn("o6: bra.s with zero offset converted to NOP");
594
595                                         continue;
596                                 }
597                                 else
598                                 {
599                                         error("illegal bra.s with zero offset");
600                                         continue;
601                                 }
602                         }
603
604                         *++locp = (uint8_t)eval;
605                         break;
606
607                 // Fixup one-byte value at locp + 1.
608                 case FU_WBYTE:
609                         locp++;
610                         // FALLTHROUGH
611
612                 // Fixup one-byte forward references
613                 case FU_BYTE:
614                         if (!(eattr & DEFINED))
615                         {
616                                 error("external byte reference");
617                                 continue;
618                         }
619
620                         if (tdb)
621                         {
622                                 error("non-absolute byte reference");
623                                 continue;
624                         }
625
626                         if ((dw & FU_PCREL) && ((eval + 0x80) >= 0x100))
627                                 goto rangeErr;
628
629                         if (dw & FU_SEXT)
630                         {
631                                 if ((eval + 0x100) >= 0x200)
632                                         goto rangeErr;
633                         }
634                         else if (eval >= 0x100)
635                                 goto rangeErr;
636
637                         *locp = (uint8_t)eval;
638                         break;
639
640                 // Fixup high/low byte off word for 6502
641                 case FU_BYTEH:
642                         if (!(eattr & DEFINED))
643                         {
644                                 error("external byte reference");
645                                 continue;
646                         }
647
648                         *locp = (uint8_t)(eval >> 8);
649                         break;
650
651                 case FU_BYTEL:
652                         if (!(eattr & DEFINED))
653                         {
654                                 error("external byte reference");
655                                 continue;
656                         }
657
658                         *locp = (uint8_t)eval;
659                         break;
660
661                 // Fixup WORD forward references; the word could be unaligned in the
662                 // section buffer, so we have to be careful. (? careful about what?)
663                 case FU_WORD:
664                         if ((dw & FUMASKRISC) == FU_JR)
665                         {
666                                 int reg = (signed)((eval - ((fup->orgaddr ? fup->orgaddr : loc) + 2)) / 2);
667
668                                 if ((reg < -16) || (reg > 15))
669                                 {
670                                         error("relative jump out of range");
671                                         break;
672                                 }
673
674                                 *locp |= ((uint8_t)reg >> 3) & 0x03;
675                                 locp++;
676                                 *locp |= ((uint8_t)reg & 0x07) << 5;
677                                 break;
678                         }
679                         else if ((dw & FUMASKRISC) == FU_NUM15)
680                         {
681                                 if (((int)eval < -16) || ((int)eval > 15))
682                                 {
683                                         error("constant out of range (-16 - +15)");
684                                         break;
685                                 }
686
687                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
688                                 locp++;
689                                 *locp |= ((uint8_t)eval & 0x07) << 5;
690                                 break;
691                         }
692                         else if ((dw & FUMASKRISC) == FU_NUM31)
693                         {
694                                 if (eval > 31)
695                                 {
696                                         error("constant out of range (0-31)");
697                                         break;
698                                 }
699
700                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
701                                 locp++;
702                                 *locp |= ((uint8_t)eval & 0x07) << 5;
703                                 break;
704                         }
705                         else if ((dw & FUMASKRISC) == FU_NUM32)
706                         {
707                                 if ((eval < 1) || (eval > 32))
708                                 {
709                                         error("constant out of range (1-32)");
710                                         break;
711                                 }
712
713                                 if (dw & FU_SUB32)
714                                         eval = (32 - eval);
715
716                                 eval = (eval == 32) ? 0 : eval;
717                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
718                                 locp++;
719                                 *locp |= ((uint8_t)eval & 0x07) << 5;
720                                 break;
721                         }
722                         else if ((dw & FUMASKRISC) == FU_REGONE)
723                         {
724                                 eval -= KW_R0;
725                                 if (eval > 31)
726                                 {
727                                         error("register one value out of range");
728                                         break;
729                                 }
730
731                                 *locp |= ((uint8_t)eval >> 3) & 0x03;
732                                 locp++;
733                                 *locp |= ((uint8_t)eval & 0x07) << 5;
734                                 break;
735                         }
736                         else if ((dw & FUMASKRISC) == FU_REGTWO)
737                         {
738                                 eval -= KW_R0;
739                                 if (eval > 31)
740                                 {
741                                         error("register two value out of range");
742                                         break;
743                                 }
744
745                                 locp++;
746                                 *locp |= (uint8_t)eval & 0x1F;
747                                 break;
748                         }
749
750                         if (!(eattr & DEFINED))
751                         {
752                                 flags = MWORD;
753
754                                 if (dw & FU_PCREL)
755                                         flags |= MPCREL;
756
757                                 MarkRelocatable(sno, loc, 0, flags, esym);
758                         }
759                         else
760                         {
761                                 if (tdb)
762                                         MarkRelocatable(sno, loc, tdb, MWORD, NULL);
763
764                                 if (dw & FU_SEXT)
765                                 {
766                                         if (eval + 0x10000 >= 0x20000)
767                                                 goto rangeErr;
768                                 }
769                                 else
770                                 {
771                                         // Range-check BRA and DBRA
772                                         if (dw & FU_ISBRA)
773                                         {
774                                                 if (eval + 0x8000 >= 0x10000)
775                                                         goto rangeErr;
776                                         }
777                                         else if (eval >= 0x10000)
778                                                 goto rangeErr;
779                                 }
780                         }
781
782                         // 6502 words are little endian, so handle that here
783                         if (sno == M6502)
784                                 SETLE16(locp, 0, eval)
785                         else
786                                 SETBE16(locp, 0, eval)
787
788                         break;
789
790                 // Fixup LONG forward references; the long could be unaligned in the
791                 // section buffer, so be careful (again).
792                 case FU_LONG:
793                         flags = MLONG;
794
795                         if ((dw & FUMASKRISC) == FU_MOVEI)
796                         {
797                                 // Long constant in MOVEI # is word-swapped, so fix it here
798                                 eval = WORDSWAP32(eval);
799                                 flags |= MMOVEI;
800                         }
801
802                         // If the symbol is undefined, make sure to pass the symbol in
803                         // to the MarkRelocatable() function.
804                         if (!(eattr & DEFINED))
805                                 MarkRelocatable(sno, loc, 0, flags, esym);
806                         else if (tdb)
807                                 MarkRelocatable(sno, loc, tdb, flags, NULL);
808
809                         SETBE32(locp, 0, eval);
810                         break;
811
812                 // Fixup QUAD forward references (mainly used by the OP assembler)
813                 case FU_QUAD:
814                         if (dw & FU_OBJLINK)
815                         {
816                                 uint64_t quad = GETBE64(locp, 0);
817                                 uint64_t addr = eval;
818
819 //Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR...  :-/
820 //                              if (fup->orgaddr)
821 //                                      addr = fup->orgaddr;
822
823                                 eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21);
824                         }
825                         else if (dw & FU_OBJDATA)
826                         {
827                                 // If it's in a TEXT or DATA section, be sure to mark for a
828                                 // fixup later
829                                 if (tdb)
830                                         MarkRelocatable(sno, loc, tdb, MQUAD, NULL);
831
832                                 uint64_t quad = GETBE64(locp, 0);
833                                 uint64_t addr = eval;
834
835 //Hmm, not sure how this can be set, since it's only set if it's a DSP56001 fixup or a FU_JR...  :-/
836 //                              if (fup->orgaddr)
837 //                                      addr = fup->orgaddr;
838
839                                 eval = (quad & 0x000007FFFFFFFFFFLL) | ((addr & 0xFFFFF8) << 40);
840                         }
841
842                         SETBE64(locp, 0, eval);
843                         break;
844
845                 // Fixup a 3-bit "QUICK" reference in bits 9..1
846                 // (range of 1..8) in a word. [Really bits 1..3 in a byte.]
847                 case FU_QUICK:
848                         if (!(eattr & DEFINED))
849                         {
850                                 error("External quick reference");
851                                 continue;
852                         }
853
854                         if ((eval < 1) || (eval > 8))
855                                 goto rangeErr;
856
857                         *locp |= (eval & 7) << 1;
858                         break;
859
860                 // Fix up 6502 funny branch
861                 case FU_6BRA:
862                         eval -= (loc + 1);
863
864                         if (eval + 0x80 >= 0x100)
865                                 goto rangeErr;
866
867                         *locp = (uint8_t)eval;
868                         break;
869
870                 // Fixup DSP56001 addresses
871                 case FU_56001:
872                         switch (dw & FUMASKDSP)
873                         {
874                         // DSPIMM5 actually is clamped from 0 to 23 for our purposes
875                         // and does not use the full 5 bit range.
876                         case FU_DSPIMM5:
877                                 if (eval > 23)
878                                 {
879                                         error("immediate value must be between 0 and 23");
880                                         break;
881                                 }
882
883                                 locp[2] |= eval;
884                                 break;
885
886                         // This is a 12-bit address encoded into the lower 12
887                         // bits of a DSP word
888                         case FU_DSPADR12:
889                                 if (eval >= 0x1000)
890                                 {
891                                         error("address out of range ($0-$FFF)");
892                                         break;
893                                 }
894
895                                 locp[1] |= eval >> 8;
896                                 locp[2] = eval & 0xFF;
897                                 break;
898
899                         // This is a full DSP word containing Effective Address Extension
900                         case FU_DSPADR24:
901                         case FU_DSPIMM24:
902                                 if (eval >= 0x1000000)
903                                 {
904                                         error("value out of range ($0-$FFFFFF)");
905                                         break;
906                                 }
907
908                                 locp[0] = (uint8_t)((eval >> 16) & 0xFF);
909                                 locp[1] = (uint8_t)((eval >> 8) & 0xFF);
910                                 locp[2] = (uint8_t)(eval & 0xFF);
911                                 break;
912
913                         // This is a 16bit absolute address into a 24bit field
914                         case FU_DSPADR16:
915                                 if (eval >= 0x10000)
916                                 {
917                                         error("address out of range ($0-$FFFF)");
918                                         break;
919                                 }
920
921                                 locp[1] = (uint8_t)(eval >> 8);
922                                 locp[2] = (uint8_t)eval;
923                                 break;
924
925                         // This is 12-bit immediate short data
926                         // The upper nibble goes into the last byte's low nibble
927                         // while the remainder 8 bits go into the 2nd byte.
928                         case FU_DSPIMM12:
929                                 if (eval >= 0x1000)
930                                 {
931                                         error("immediate out of range ($0-$FFF)");
932                                         break;
933                                 }
934
935                                 locp[1] = (uint8_t)eval;
936                                 locp[2] |= (uint8_t)(eval >> 8);
937                                 break;
938
939                         // This is 8-bit immediate short data
940                         // which goes into the middle byte of a DSP word.
941                         case FU_DSPIMM8:
942                                 if (eval >= 0x100)
943                                 {
944                                         error("immediate out of range ($0-$FF)");
945                                         break;
946                                 }
947
948                                 locp[1] = (uint8_t)eval;
949                                 break;
950
951                         // This is a 6 bit absoulte short address. It occupies the low 6
952                         // bits of the middle byte of a DSP word.
953                         case FU_DSPADR06:
954                                 if (eval > 63)
955                                 {
956                                         error("address must be between 0 and 63");
957                                         break;
958                                 }
959
960                                 locp[1] |= eval;
961                                 break;
962
963                         // This is a 6 bit absoulte short address. It occupies the low 6
964                         // bits of the middle byte of a DSP word.
965                         case FU_DSPPP06:
966                                 if (eval < 0xFFFFFFC0)
967                                 {
968                                         error("address must be between $FFC0 and $FFFF");
969                                         break;
970                                 }
971
972                                 locp[1] |= eval & 0x3F;
973                                 break;
974
975                         // Shamus: I'm pretty sure these don't make any sense...
976                         case FU_DSPIMMFL8:
977                                 warn("FU_DSPIMMFL8 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
978                                 break;
979
980                         case FU_DSPIMMFL16:
981                                 warn("FU_DSPIMMFL16 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
982                                 break;
983
984                         case FU_DSPIMMFL24:
985                                 warn("FU_DSPIMMFL24 missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
986                                 break;
987
988                         // Bad fixup type--this should *never* happen!
989                         default:
990                                 interror(4);
991                                 // NOTREACHED
992                         }
993                         break;
994
995                 // Fixup a 4-byte float
996                 case FU_FLOATSING:
997                         warn("FU_FLOATSING missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
998                         break;
999
1000                 // Fixup a 8-byte float
1001                 case FU_FLOATDOUB:
1002                         warn("FU_FLOATDOUB missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
1003                         break;
1004
1005                 // Fixup a 12-byte float
1006                 case FU_FLOATEXT:
1007                         warn("FU_FLOATEXT missing implementation\n%s", "And you may ask yourself, \"Self, how did I get here?\"");
1008                         break;
1009
1010                 default:
1011                         // Bad fixup type--this should *never* happen!
1012                         // Once we call this function, it winds down immediately; it
1013                         // doesn't return.
1014                         interror(4);
1015                 }
1016
1017                 continue;
1018 rangeErr:
1019                 error("expression out of range");
1020         }
1021
1022         return 0;
1023 }
1024
1025
1026 //
1027 // Resolve all fixups
1028 //
1029 int ResolveAllFixups(void)
1030 {
1031         // Make undefined symbols GLOBL
1032         if (glob_flag)
1033                 ForceUndefinedSymbolsGlobal();
1034
1035         DEBUG printf("Resolving TEXT sections...\n");
1036         ResolveFixups(TEXT);
1037         DEBUG printf("Resolving DATA sections...\n");
1038         ResolveFixups(DATA);
1039         DEBUG printf("Resolving 6502 sections...\n");
1040         ResolveFixups(M6502);           // Fixup 6502 section (if any)
1041         DEBUG printf("Resolving DSP56001 P: sections...\n");
1042         ResolveFixups(M56001P);         // Fixup 56001 P: section (if any)
1043         DEBUG printf("Resolving DSP56001 X: sections...\n");
1044         ResolveFixups(M56001X);         // Fixup 56001 X: section (if any)
1045         DEBUG printf("Resolving DSP56001 Y: sections...\n");
1046         ResolveFixups(M56001Y);         // Fixup 56001 Y: section (if any)
1047
1048         return 0;
1049 }
1050