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