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