Version bump for last commit; now at v2.0.23.
[rmac] / direct.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // DIRECT.C - Directive Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "direct.h"
10 #include "6502.h"
11 #include "amode.h"
12 #include "dsp56k.h"
13 #include "error.h"
14 #include "expr.h"
15 #include "fltpoint.h"
16 #include "listing.h"
17 #include "mach.h"
18 #include "macro.h"
19 #include "mark.h"
20 #include "procln.h"
21 #include "riscasm.h"
22 #include "sect.h"
23 #include "symbol.h"
24 #include "token.h"
25
26 #define DEF_KW
27 #include "kwtab.h"
28
29
30 TOKEN exprbuf[128];                     // Expression buffer
31 SYM * symbolPtr[1000000];       // Symbol pointers table
32 static long unused;                     // For supressing 'write' warnings
33 char buffer[256];                       // Scratch buffer for messages
34 int largestAlign[3] = { 2, 2, 2 };      // Largest alignment value seen per section
35
36 // Function prototypes
37 int d_unimpl(void);
38 int d_68000(void);
39 int d_68020(void);
40 int d_68030(void);
41 int d_68040(void);
42 int d_68060(void);
43 int d_68881(void);
44 int d_68882(void);
45 int d_56001(void);
46 int d_nofpu(void);
47 int d_bss(void);
48 int d_data(void);
49 int d_text(void);
50 int d_abs(void);
51 int d_comm(void);
52 int d_dc(WORD);
53 int d_ds(WORD);
54 int d_dsm(WORD);
55 int d_dcb(WORD);
56 int d_globl(void);
57 int d_gpu(void);
58 int d_dsp(void);
59 int d_assert(void);
60 int d_include(void);
61 int d_list(void);
62 int d_nlist(void);
63 int d_error(char *);
64 int d_warn(char *);
65 int d_org(void);
66 int d_init(WORD);
67 int d_cargs(void);
68 int d_undmac(void);
69 int d_regbank0(void);
70 int d_regbank1(void);
71 int d_incbin(void);
72 int d_noclear(void);
73 int d_equrundef(void);
74 int d_ccundef(void);
75 int d_print(void);
76 int d_gpumain(void);
77 int d_jpad(void);
78 int d_nojpad(void);
79 int d_fail(void);
80 int d_cstruct(void);
81 int d_prgflags(void);
82 int d_opt(void);
83 int d_dsp(void);
84 int d_objproc(void);
85 void SetLargestAlignment(int);
86
87 // Directive handler table
88 int (*dirtab[])() = {
89         d_org,                          // 0 org
90         d_even,                         // 1 even
91         d_6502,                         // 2 .6502
92         d_68000,                        // 3 .68000
93         d_bss,                          // 4 bss
94         d_data,                         // 5 data
95         d_text,                         // 6 text
96         d_abs,                          // 7 abs
97         d_comm,                         // 8 comm
98         (void *)d_init,         // 9 init
99         d_cargs,                        // 10 cargs
100         (void *)d_goto,         // 11 goto
101         (void *)d_dc,           // 12 dc
102         (void *)d_ds,           // 13 ds
103         d_undmac,                       // 14 undefmac
104         d_gpu,                          // 15 .gpu
105         d_dsp,                          // 16 .dsp
106         (void *)d_dcb,          // 17 dcb
107         d_unimpl,                       // 18* set
108         d_unimpl,                       // 19* reg
109         d_unimpl,                       // 20 dump
110         d_incbin,                       // 21 .incbin //load
111         d_unimpl,                       // 22 disable
112         d_unimpl,                       // 23 enable
113         d_globl,                        // 24 globl
114         d_regbank0,                     // 25 .regbank0
115         d_regbank1,                     // 26 .regbank1
116         d_unimpl,                       // 27 xdef
117         d_assert,                       // 28 assert
118         d_unimpl,                       // 29* if
119         d_unimpl,                       // 30* endif
120         d_unimpl,                       // 31* endc
121         d_unimpl,                       // 32* iif
122         d_include,                      // 33 include
123         fpop,                           // 34 end
124         d_unimpl,                       // 35* macro
125         ExitMacro,                      // 36* exitm
126         d_unimpl,                       // 37* endm
127         d_list,                         // 38 list
128         d_nlist,                        // 39 nlist
129         d_long,                         // 40* rept
130         d_phrase,                       // 41* endr
131         d_dphrase,                      // 42 struct
132         d_qphrase,                      // 43 ends
133         d_title,                        // 44 title
134         d_subttl,                       // 45 subttl
135         eject,                          // 46 eject
136         d_error,                        // 47 error
137         d_warn,                         // 48 warn
138         d_noclear,                      // 49 .noclear
139         d_equrundef,            // 50 .equrundef/.regundef
140         d_ccundef,                      // 51 .ccundef
141         d_print,                        // 52 .print
142         d_cstruct,                      // 53 .cstruct
143         d_jpad,                         // 54 .jpad (deprecated)
144         d_nojpad,                       // 55 .nojpad (deprecated)
145         d_gpumain,                      // 56 .gpumain (deprecated)
146         d_prgflags,                     // 57 .prgflags
147         d_68020,                        // 58 .68020
148         d_68030,                        // 59 .68030
149         d_68040,                        // 60 .68040
150         d_68060,                        // 61 .68060
151         d_68881,                        // 62 .68881
152         d_68882,                        // 63 .68882
153         d_56001,                        // 64 .56001
154         d_nofpu,                        // 65 nofpu
155         d_opt,                          // 66 .opt
156         d_objproc,                      // 67 .objproc
157         (void *)d_dsm,                  // 68 .dsm
158 };
159
160
161 //
162 // Set the largest alignment seen in the current section
163 //
164 void SetLargestAlignment(int size)
165 {
166         if ((scattr & TEXT) && (largestAlign[0] < size))
167                 largestAlign[0] = size;
168         else if ((scattr & DATA) && (largestAlign[1] < size))
169                 largestAlign[1] = size;
170         else if ((scattr & BSS) && (largestAlign[2] < size))
171                 largestAlign[2] = size;
172 }
173
174
175 //
176 // .error - Abort compilation, printing an error message
177 //
178 int d_error(char *str)
179 {
180         if (*tok == EOL)
181                 return error("error directive encountered - aborting assembling");
182         else
183         {
184                 switch(*tok)
185                 {
186                 case STRING:
187                         return error(string[tok[1]]);
188                         break;
189                 default:
190                         return error("error directive encountered--aborting assembly");
191                 }
192         }
193 }
194
195
196 //
197 // .warn - Just display a warning on screen
198 //
199 int d_warn(char *str)
200 {
201         if (*tok == EOL)
202                 return warn("WARNING WARNING WARNING");
203         else
204         {
205                 switch(*tok)
206                 {
207                 case STRING:
208                         return warn(string[tok[1]]);
209                         break;
210                 default:
211                         return warn("WARNING WARNING WARNING");
212                 }
213         }
214 }
215
216
217 //
218 // .org - Set origin
219 //
220 int d_org(void)
221 {
222         uint64_t address;
223
224         if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001 && !(obj_format == RAW))
225                 return error(".org permitted only in GPU/DSP/OP, 56001, 6502 and 68k (with -fr switch) sections");
226
227         // M56K can leave the expression off the org for some reason :-/
228         // (It's because the expression is non-standard, and so we have to look at
229         // it in isolation)
230         if (!dsp56001 && (abs_expr(&address) == ERROR))
231         {
232                 error("cannot determine org'd address");
233                 return ERROR;
234         }
235
236         if (rgpu | rdsp | robjproc)
237         {
238                 orgaddr = address;
239                 orgactive = 1;
240         }
241         else if (m6502)
242         {
243                 // 6502.  We also kludge 'lsloc' so the listing generator doesn't try
244                 // to spew out megabytes.
245                 if (address > 0xFFFF)
246                         return error(range_error);
247
248                 if (sloc != currentorg[0])
249                 {
250                         currentorg[1] = sloc;
251                         currentorg += 2;
252                 }
253
254                 currentorg[0] = address;
255                 ch_size = 0;
256                 lsloc = sloc = address;
257                 chptr = scode->chptr + address;
258                 orgaddr = address;
259                 orgactive = 1;
260         }
261         else if (dsp56001)
262         {
263                 // Only mark segments we actually wrote something
264                 if (chptr != dsp_currentorg->start && dsp_written_data_in_current_org)
265                 {
266                         dsp_currentorg->end = chptr;
267                         dsp_currentorg++;
268                 }
269
270                 // Maybe we switched from a non-DSP section (TEXT, DATA, etc) and
271                 // scode isn't initialised yet. Not that it's going to be a valid
272                 // scenario, but if we try it anyhow it's going to lead to a crash. So
273                 // let's fudge a value of 0 and get on with it.
274                 orgaddr = (scode != NULL ? sloc : 0);
275                 SaveSection();
276
277                 if (tok[1] != ':')
278                         return error(syntax_error);
279
280                 int sectionToSwitch = 0;
281
282                 switch (tok[0])
283                 {
284                 case KW_X:
285                         dsp_currentorg->memtype = ORG_X;
286                         sectionToSwitch = M56001X;
287                         break;
288
289                 case KW_Y:
290                         dsp_currentorg->memtype = ORG_Y;
291                         sectionToSwitch = M56001Y;
292                         break;
293
294                 case KW_P:
295                         dsp_currentorg->memtype = ORG_P;
296                         sectionToSwitch = M56001P;
297                         break;
298
299                 case KW_L:
300                         dsp_currentorg->memtype = ORG_L;
301                         sectionToSwitch = M56001L;
302                         break;
303
304                 default:
305                         return error("unknown type in ORG");
306                 }
307
308                 if ((obj_format == LOD) || (obj_format == P56))
309                         SwitchSection(sectionToSwitch);
310
311                 tok += 2;
312                 chcheck(3); // Ensure we got a valid address to write
313                 dsp_currentorg->chunk = scode;  // Mark down which chunk this org starts from (will be needed when outputting)
314
315                 if (*tok == EOL)
316                 {
317                         // Well, the user didn't specify an address at all so we'll have to
318                         // use the last used address of that section (or 0 if there wasn't one)
319                         address = orgaddr;
320                         dsp_currentorg->start = chptr;
321                         dsp_currentorg->orgadr = orgaddr;
322                 }
323                 else
324                 {
325                         if (abs_expr(&address) == ERROR)
326                         {
327                                 error("cannot determine org'd address");
328                                 return ERROR;
329                         }
330
331                         dsp_currentorg->start = chptr;
332                         dsp_currentorg->orgadr = (uint32_t)address;
333                         sect[cursect].orgaddr = (uint32_t)address;
334                 }
335
336                 if (address > DSP_MAX_RAM)
337                 {
338                         return error(range_error);
339                 }
340
341                 dsp_written_data_in_current_org = 0;
342
343                 // Copied from 6502 above: kludge `lsloc' so the listing generator
344                 // doesn't try to spew out megabytes.
345                 lsloc = sloc = (int32_t)address;
346 // N.B.: It seems that by enabling this, even though it works elsewhere, will cause symbols to royally fuck up.  Will have to do some digging to figure out why.
347 //              orgactive = 1;
348         }
349         else
350         {
351                 // If we get here we assume it's 68k with RAW output, so this is allowed
352                 if (orgactive)
353                 {
354                         return error("In 68k mode only one .org statement is allowed");
355                 }
356
357                 org68k_address = address;
358                 org68k_active = 1;
359         }
360
361         ErrorIfNotAtEOL();
362         return 0;
363 }
364
365
366 //
367 // Print directive
368 //
369 int d_print(void)
370 {
371         char prntstr[LNSIZ];            // String for PRINT directive
372         char format[LNSIZ];                     // Format for PRINT directive
373         int formatting = 0;                     // Formatting on/off
374         int wordlong = 0;                       // WORD = 0, LONG = 1
375         int outtype = 0;                        // 0:hex, 1:decimal, 2:unsigned
376
377         uint64_t eval;                          // Expression value
378         WORD eattr;                                     // Expression attributes
379         SYM * esym;                                     // External symbol involved in expr.
380         TOKEN r_expr[EXPRSIZE];
381
382         while (*tok != EOL)
383         {
384                 switch (*tok)
385                 {
386                 case STRING:
387                         sprintf(prntstr, "%s", string[tok[1]]);
388                         printf("%s", prntstr);
389
390                         if (list_fd)
391                                 unused = write(list_fd, prntstr, (LONG)strlen(prntstr));
392
393                         tok += 2;
394                         break;
395                 case '/':
396                         formatting = 1;
397
398                         // "X" & "L" get tokenized now... :-/ Probably should look into preventing this kind of thing from happening (was added with DSP56K code)
399                         if ((tok[1] != SYMBOL) && (tok[1] != KW_L) && (tok[1] != KW_X))
400                                 goto token_err;
401
402                         if (tok[1] == KW_L)
403                         {
404                                 wordlong = 1;
405                                 tok += 2;
406                         }
407                         else if (tok[1] == KW_X)
408                         {
409                                 outtype = 0;
410                                 tok += 2;
411                         }
412                         else
413                         {
414                                 strcpy(prntstr, string[tok[2]]);
415
416                                 switch (prntstr[0])
417                                 {
418                                 case 'l': case 'L': wordlong = 1; break;
419                                 case 'w': case 'W': wordlong = 0; break;
420                                 case 'x': case 'X': outtype  = 0; break;
421                                 case 'd': case 'D': outtype  = 1; break;
422                                 case 'u': case 'U': outtype  = 2; break;
423                                 default:
424                                         error("unknown print format flag");
425                                         return ERROR;
426                                 }
427
428                                 tok += 3;
429                         }
430
431                         break;
432                 case ',':
433                         tok++;
434                         break;
435                 default:
436                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
437                                 goto token_err;
438                         else
439                         {
440                                 switch(outtype)
441                                 {
442                                 case 0: strcpy(format, "%X"); break;
443                                 case 1: strcpy(format, "%d" ); break;
444                                 case 2: strcpy(format, "%u" ); break;
445                                 }
446
447                                 if (wordlong)
448                                         sprintf(prntstr, format, eval);
449                                 else
450                                         sprintf(prntstr, format, eval & 0xFFFF);
451
452                                 printf("%s", prntstr);
453
454                                 if (list_fd)
455                                         unused = write(list_fd, prntstr, (LONG)strlen(prntstr));
456
457                                 formatting = 0;
458                                 wordlong = 0;
459                                 outtype = 0;
460                         }
461
462                         break;
463                 }
464         }
465
466         printf("\n");
467
468         return 0;
469
470 token_err:
471         error("illegal print token [@ '%s']", prntstr);
472         return ERROR;
473 }
474
475
476 //
477 // Undefine an equated condition code
478 //
479 int d_ccundef(void)
480 {
481         SYM * ccname;
482
483         // Check that we are in a RISC section
484         if (!rgpu && !rdsp)
485         {
486                 error(".ccundef must be defined in .gpu/.dsp section");
487                 return ERROR;
488         }
489
490         if (*tok != SYMBOL)
491         {
492                 error("syntax error; expected symbol");
493                 return ERROR;
494         }
495
496         ccname = lookup(string[tok[1]], LABEL, 0);
497
498         // Make sure symbol is a valid ccdef
499         if (!ccname || !(ccname->sattre & EQUATEDCC))
500         {
501                 error("invalid equated condition name specified");
502                 return ERROR;
503         }
504
505         ccname->sattre |= UNDEF_CC;
506
507         return 0;
508 }
509
510
511 //
512 // Undefine an equated register
513 //
514 int d_equrundef(void)
515 {
516         SYM * regname;
517
518         // Check that we are in a RISC section
519         if (!rgpu && !rdsp)
520                 return error(".equrundef/.regundef must be defined in .gpu/.dsp section");
521
522         while (*tok != EOL)
523         {
524                 // Skip preceeding or seperating commas (if any)
525                 if (*tok == ',')
526                         tok++;
527
528                 // Check we are dealing with a symbol
529                 if (*tok != SYMBOL)
530                         return error("syntax error; expected symbol");
531
532                 // Lookup and undef if equated register
533                 regname = lookup(string[tok[1]], LABEL, 0);
534
535                 if (regname && (regname->sattre & EQUATEDREG))
536                 {
537                         // Reset the attributes of this symbol...
538                         regname->sattr = 0;
539                         regname->sattre &= ~(EQUATEDREG | BANK_0 | BANK_1);
540                         regname->sattre |= UNDEF_EQUR;
541                 }
542
543                 // Skip over symbol token and address
544                 tok += 2;
545         }
546
547         return 0;
548 }
549
550
551 //
552 // Do not allow use of the CLR.L opcode
553 //
554 int d_noclear(void)
555 {
556         warn("CLR.L opcode ignored...");
557         return 0;
558 }
559
560
561 //
562 // Include binary file
563 //
564 int d_incbin(void)
565 {
566         int fd;
567         int bytes = 0;
568         long pos, size, bytesRead;
569         char buf1[256];
570         int i;
571
572         // Check to see if we're in BSS, and, if so, throw an error
573         if (scattr & SBSS)
574         {
575                 error("cannot include binary file \"%s\" in BSS section", string[tok[1]]);
576                 return ERROR;
577         }
578
579         if (*tok != STRING)
580         {
581                 error("syntax error; file to include missing");
582                 return ERROR;
583         }
584
585         // Attempt to open the include file in the current directory, then (if that
586         // failed) try list of include files passed in the enviroment string or by
587         // the "-d" option.
588         if ((fd = open(string[tok[1]], _OPEN_INC)) < 0)
589         {
590                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
591                 {
592                         fd = strlen(buf1);
593
594                         // Append path char if necessary
595                         if (fd > 0 && buf1[fd - 1] != SLASHCHAR)
596                                 strcat(buf1, SLASHSTRING);
597
598                         strcat(buf1, string[tok[1]]);
599
600                         if ((fd = open(buf1, _OPEN_INC)) >= 0)
601                                 goto allright;
602                 }
603
604                 return error("cannot open: \"%s\"", string[tok[1]]);
605         }
606
607 allright:
608
609         size = lseek(fd, 0L, SEEK_END);
610         pos = lseek(fd, 0L, SEEK_SET);
611         chcheck(size);
612
613         DEBUG { printf("INCBIN: File '%s' is %li bytes.\n", string[tok[1]], size); }
614
615         char * fileBuffer = (char *)malloc(size);
616         bytesRead = read(fd, fileBuffer, size);
617
618         if (bytesRead != size)
619         {
620                 error("was only able to read %li bytes from binary file (%s, %li bytes)", bytesRead, string[tok[1]], size);
621                 return ERROR;
622         }
623
624         memcpy(chptr, fileBuffer, size);
625         chptr += size;
626         sloc += size;
627         ch_size += size;
628
629         if (orgactive)
630                 orgaddr += size;
631
632         free(fileBuffer);
633         close(fd);
634         return 0;
635 }
636
637
638 //
639 // Set RISC register banks
640 //
641 int d_regbank0(void)
642 {
643         // Set active register bank zero
644         regbank = BANK_0;
645         return 0;
646 }
647
648
649 int d_regbank1(void)
650 {
651         // Set active register bank one
652         regbank = BANK_1;
653         return 0;
654 }
655
656
657 //
658 // Helper function, to cut down on mistakes & typing
659 //
660 static inline void SkipBytes(unsigned bytesToSkip)
661 {
662         if (!bytesToSkip)
663                 return;
664
665         if ((scattr & SBSS) == 0)
666         {
667                 chcheck(bytesToSkip);
668                 D_ZEROFILL(bytesToSkip);
669         }
670         else
671         {
672                 sloc += bytesToSkip;
673
674                 if (orgactive)
675                         orgaddr += bytesToSkip;
676         }
677 }
678
679
680 //
681 // Adjust location to an EVEN value
682 //
683 int d_even(void)
684 {
685         if (m6502)
686                 return error(in_6502mode);
687
688         unsigned skip = (rgpu || rdsp ? orgaddr : sloc) & 0x01;
689
690         if (skip)
691         {
692                 if ((scattr & SBSS) == 0)
693                 {
694                         chcheck(1);
695                         D_byte(0);
696                 }
697                 else
698                 {
699                         sloc++;
700
701                         if (orgactive)
702                                 orgaddr++;
703                 }
704         }
705
706         return 0;
707 }
708
709
710 //
711 // Adjust location to a LONG value
712 //
713 int d_long(void)
714 {
715         unsigned lower2Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x03;
716         unsigned bytesToSkip = (0x04 - lower2Bits) & 0x03;
717         SkipBytes(bytesToSkip);
718         SetLargestAlignment(4);
719
720         return 0;
721 }
722
723
724 //
725 // Adjust location to a PHRASE value
726 //
727 // N.B.: We have to handle the GPU/DSP cases separately because you can embed
728 //       RISC code in the middle of a regular 68K section. Also note that all
729 //       of the alignment pseudo-ops will have to be fixed this way.
730 //
731 // This *must* behave differently when in a RISC section, as following sloc
732 // (instead of orgaddr) will fuck things up royally. Note that we do it this
733 // way because you can embed RISC code in a 68K section, and have the origin
734 // pointing to a different alignment in the RISC section than the 68K section.
735 //
736 int d_phrase(void)
737 {
738         unsigned lower3Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x07;
739         unsigned bytesToSkip = (0x08 - lower3Bits) & 0x07;
740         SkipBytes(bytesToSkip);
741         SetLargestAlignment(8);
742
743         return 0;
744 }
745
746
747 //
748 // Adjust location to a DPHRASE value
749 //
750 int d_dphrase(void)
751 {
752         unsigned lower4Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x0F;
753         unsigned bytesToSkip = (0x10 - lower4Bits) & 0x0F;
754         SkipBytes(bytesToSkip);
755         SetLargestAlignment(16);
756
757         return 0;
758 }
759
760
761 //
762 // Adjust location to a QPHRASE value
763 //
764 int d_qphrase(void)
765 {
766         unsigned lower5Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x1F;
767         unsigned bytesToSkip = (0x20 - lower5Bits) & 0x1F;
768         SkipBytes(bytesToSkip);
769         SetLargestAlignment(32);
770
771         return 0;
772 }
773
774
775 //
776 // Do auto-even.  This must be called ONLY if 'sloc' is odd.
777 //
778 // This is made hairy because, if there was a label on the line, we also have
779 // to adjust its value. This won't work with more than one label on the line,
780 // which is OK since multiple labels are only allowed in AS68 kludge mode, and
781 // the C compiler is VERY paranoid and uses ".even" whenever it can
782 //
783 // N.B.: This probably needs the same fixes as above...
784 //
785 void auto_even(void)
786 {
787         if (cursect != M6502)
788         {
789                 if (scattr & SBSS)
790                         sloc++;                         // Bump BSS section
791                 else
792                         D_byte(0);                      // Deposit 0.b in non-BSS
793
794                 if (lab_sym != NULL)    // Bump label if we have to
795                         lab_sym->svalue++;
796         }
797 }
798
799
800 //
801 // Unimplemened directive error
802 //
803 int d_unimpl(void)
804 {
805         return error("unimplemented directive");
806 }
807
808
809 //
810 // Return absolute (not TDB) and defined expression or return an error
811 //
812 int abs_expr(uint64_t * a_eval)
813 {
814         WORD eattr;
815
816         if (expr(exprbuf, a_eval, &eattr, NULL) < 0)
817                 return ERROR;
818
819         if (!(eattr & DEFINED))
820                 return error(undef_error);
821
822         if (eattr & TDB)
823                 return error(rel_error);
824
825         return OK;
826 }
827
828
829 //
830 // Hand symbols in a symbol-list to a function (kind of like mapcar...)
831 //
832 int symlist(int(* func)())
833 {
834         const char * em = "symbol list syntax";
835
836         for(;;)
837         {
838                 if (*tok != SYMBOL)
839                         return error(em);
840
841                 if ((*func)(string[tok[1]]) != OK)
842                         break;
843
844                 tok += 2;
845
846                 if (*tok == EOL)
847                         break;
848
849                 if (*tok != ',')
850                         return error(em);
851
852                 tok++;
853         }
854
855         return 0;
856 }
857
858
859 //
860 // .include "filename"
861 //
862 int d_include(void)
863 {
864         int j;
865         int i;
866         char * fn;
867         char buf[128];
868         char buf1[128];
869
870         if (*tok == STRING)                     // Leave strings ALONE
871                 fn = string[*++tok];
872         else if (*tok == SYMBOL)        // Try to append ".s" to symbols
873         {
874                 strcpy(buf, string[*++tok]);
875                 fext(buf, ".s", 0);
876                 fn = &buf[0];
877         }
878         else                                            // Punt if no STRING or SYMBOL
879                 return error("missing filename");
880
881         // Make sure the user didn't try anything like:
882         // .include equates.s
883         if (*++tok != EOL)
884                 return error("extra stuff after filename--enclose it in quotes");
885
886         // Attempt to open the include file in the current directory, then (if that
887         // failed) try list of include files passed in the enviroment string or by
888         // the "-i" option.
889         if ((j = open(fn, 0)) < 0)
890         {
891                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
892                 {
893                         j = strlen(buf1);
894
895                         // Append path char if necessary
896                         if (j > 0 && buf1[j - 1] != SLASHCHAR)
897                                 strcat(buf1, SLASHSTRING);
898
899                         strcat(buf1, fn);
900
901                         if ((j = open(buf1, 0)) >= 0)
902                                 goto allright;
903                 }
904
905                 return error("cannot open: \"%s\"", fn);
906         }
907
908 allright:
909         include(j, fn);
910         return 0;
911 }
912
913
914 //
915 // .assert expression [, expression...]
916 //
917 int d_assert(void)
918 {
919         WORD eattr;
920         uint64_t eval;
921
922         for(; expr(exprbuf, &eval, &eattr, NULL)==OK; ++tok)
923         {
924                 if (!(eattr & DEFINED))
925                         return error("forward or undefined .assert");
926
927                 if (!eval)
928                         return error("assert failure");
929
930                 if (*tok != ',')
931                         break;
932         }
933
934         ErrorIfNotAtEOL();
935         return 0;
936 }
937
938
939 //
940 // .globl symbol [, symbol] <<<cannot make local symbols global>>>
941 //
942 int globl1(char * p)
943 {
944         SYM * sy;
945
946         if (*p == '.')
947                 return error("cannot .globl local symbol");
948
949         if ((sy = lookup(p, LABEL, 0)) == NULL)
950         {
951                 sy = NewSymbol(p, LABEL, 0);
952                 sy->svalue = 0;
953                 sy->sattr = GLOBAL;
954 //printf("glob1: Making global symbol: attr=%04X, eattr=%08X, %s\n", sy->sattr, sy->sattre, sy->sname);
955         }
956         else
957                 sy->sattr |= GLOBAL;
958
959         return OK;
960 }
961
962
963 int d_globl(void)
964 {
965         if (m6502)
966                 return error(in_6502mode);
967
968         symlist(globl1);
969         return 0;
970 }
971
972
973 //
974 // .prgflags expression
975 //
976 int d_prgflags(void)
977 {
978         uint64_t eval;
979
980         if (*tok == EOL)
981                 return error("PRGFLAGS requires value");
982         else if (abs_expr(&eval) == OK)
983         {
984                 PRGFLAGS = (uint32_t)eval;
985                 return 0;
986         }
987         else
988         {
989                 return error("PRGFLAGS requires value");
990         }
991 }
992
993
994 //
995 // .abs [expression]
996 //
997 int d_abs(void)
998 {
999         uint64_t eval;
1000
1001         if (m6502)
1002                 return error(in_6502mode);
1003
1004         SaveSection();
1005
1006         if (*tok == EOL)
1007                 eval = 0;
1008         else if (abs_expr(&eval) != OK)
1009                 return 0;
1010
1011         SwitchSection(ABS);
1012         sloc = (uint32_t)eval;
1013         return 0;
1014 }
1015
1016
1017 //
1018 // Switch segments
1019 //
1020 int d_text(void)
1021 {
1022         if (rgpu || rdsp)
1023                 return error("directive forbidden in gpu/dsp mode");
1024         else if (m6502)
1025                 return error(in_6502mode);
1026
1027         if (cursect != TEXT)
1028         {
1029                 SaveSection();
1030                 SwitchSection(TEXT);
1031         }
1032
1033         return 0;
1034 }
1035
1036
1037 int d_data(void)
1038 {
1039         if (rgpu || rdsp)
1040                 return error("directive forbidden in gpu/dsp mode");
1041         else if (m6502)
1042                 return error(in_6502mode);
1043
1044         if (cursect != DATA)
1045         {
1046                 SaveSection();
1047                 SwitchSection(DATA);
1048         }
1049
1050         return 0;
1051 }
1052
1053
1054 int d_bss(void)
1055 {
1056         if (rgpu || rdsp)
1057                 return error("directive forbidden in gpu/dsp mode");
1058         else if (m6502)
1059                 return error(in_6502mode);
1060
1061         if (cursect != BSS)
1062         {
1063                 SaveSection();
1064                 SwitchSection(BSS);
1065         }
1066
1067         return 0;
1068 }
1069
1070
1071 //
1072 // .ds[.size] expression
1073 //
1074 int d_ds(WORD siz)
1075 {
1076         DEBUG { printf("Directive: .ds.[size] = %u, sloc = $%X\n", siz, sloc); }
1077
1078         uint64_t eval;
1079
1080         if ((cursect & (M6502 | M56KPXYL)) == 0)
1081         {
1082                 if ((siz != SIZB) && (sloc & 1))        // Automatic .even
1083                         auto_even();
1084         }
1085
1086         if (abs_expr(&eval) != OK)
1087                 return 0;
1088
1089         // Check to see if the value being passed in is negative (who the hell does
1090         // that?--nobody does; it's the code gremlins, or rum, what does it)
1091         // N.B.: Since 'eval' is of type uint64_t, if it goes negative, it will
1092         //       have its high bit set.
1093         if (eval & 0x8000000000000000)
1094                 return error("negative sizes not allowed in DS");
1095
1096         // In non-TDB section (BSS, ABS and M6502) just advance the location
1097         // counter appropriately. In TDB sections, deposit (possibly large) chunks
1098         // of zeroed memory....
1099         if ((scattr & SBSS) || cursect == M6502)
1100         {
1101                 listvalue((uint32_t)eval);
1102                 eval *= siz;
1103                 sloc += (uint32_t)eval;
1104
1105                 if (cursect == M6502)
1106                         chptr += eval;
1107
1108                 just_bss = 1;                                   // No data deposited (8-bit CPU mode)
1109         }
1110         else if (cursect & M56KPXYL)
1111         {
1112                 // Change segment instead of marking blanks.
1113                 // Only mark segments we actually wrote something
1114                 if (chptr != dsp_currentorg->start && dsp_written_data_in_current_org)
1115                 {
1116                         dsp_currentorg->end = chptr;
1117                         dsp_currentorg++;
1118                         dsp_currentorg->memtype = dsp_currentorg[-1].memtype;
1119                 }
1120
1121                 listvalue((uint32_t)eval);
1122                 sloc += (uint32_t)eval;
1123
1124                 // And now let's create a new segment
1125                 dsp_currentorg->start = chptr;
1126                 dsp_currentorg->chunk = scode;  // Mark down which chunk this org starts from (will be needed when outputting)
1127                 sect[cursect].orgaddr = sloc;
1128                 dsp_currentorg->orgadr = sloc;
1129                 dsp_written_data_in_current_org = 0;
1130
1131                 just_bss = 1;                                   // No data deposited
1132         }
1133         else
1134         {
1135                 dep_block(eval, siz, 0, (DEFINED | ABS), NULL);
1136         }
1137
1138         ErrorIfNotAtEOL();
1139         return OK;
1140 }
1141
1142
1143 //
1144 // dsm[.siz] expression
1145 // Define modulo storage
1146 // Quoting the Motorola assembler manual:
1147 // "The DSM directive reserves a block of memory the length of which in words is equal to
1148 // the value of <expression>.If the runtime location counter is not zero, this directive first
1149 // advances the runtime location counter to a base address that is a multiple of 2k, where
1150 // 2k >= <expression>."
1151 // The kicker of course is written a few sentences after:
1152 // "<label>, if present, will be assigned the value of the runtime location counter after a valid
1153 // base address has been established."
1154 //
1155 int d_dsm(WORD siz)
1156 {
1157         TOKEN * tok_current = tok;  // Keep track of where tok was when we entered this procedure
1158         uint64_t eval;
1159
1160         if (abs_expr(&eval) != OK)
1161                 return 0;
1162
1163         // Round up to the next highest power of 2
1164         // Nicked from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
1165         eval--;
1166         eval |= eval >> 1;
1167         eval |= eval >> 2;
1168         eval |= eval >> 4;
1169         eval |= eval >> 8;
1170         eval |= eval >> 16;
1171
1172         int units_to_skip;
1173         units_to_skip = eval + 1 - sloc;
1174         sloc += units_to_skip;          // Bump up sloc - TODO: check if this goes over the RAM limits?
1175
1176         // If a label has been defined in the same line as dsm, its value also needs to be adjusted
1177         if (label_defined)
1178         {
1179                 SYM * label = lookup(label_defined, LABEL, 0);
1180                 label->svalue += units_to_skip;
1181         }
1182
1183         tok = tok_current;              // Rewind tok back to where it was
1184         return d_ds(siz);               // And let d_ds take over from here
1185 }
1186
1187
1188 //
1189 // dc.b, dc.w / dc, dc.l, dc.i, dc.q, dc.d, dc.s, dc.x
1190 //
1191 int d_dc(WORD siz)
1192 {
1193         WORD eattr;
1194         uint64_t eval;
1195         uint8_t * p;
1196
1197         if ((scattr & SBSS) != 0)
1198                 return error("illegal initialization of section");
1199
1200         // Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
1201         if ((cursect != M6502) && (cursect != M56001P) && (cursect != M56001X)
1202                 && (cursect != M56001Y) && (cursect != M56001L)
1203                 && (siz != SIZB) && (sloc & 1))
1204                 auto_even();
1205
1206         // Check to see if we're trying to set LONGS on a non 32-bit aligned
1207         // address in a GPU or DSP section, in their local RAM
1208         if ((siz == SIZL) && (orgaddr & 0x03)
1209                 && ((rgpu && (orgaddr >= 0xF03000) && (orgaddr <= 0xF03FFFF))
1210                 || (rdsp && (orgaddr >= 0xF1B000) && (orgaddr <= 0xF1CFFFF))))
1211                 warn("depositing LONGs on a non-long address in local RAM");
1212
1213         for(;; tok++)
1214         {
1215                 // dc.b 'string' [,] ...
1216                 if (siz == SIZB && (*tok == STRING || *tok == STRINGA8) && (tok[2] == ',' || tok[2] == EOL))
1217                 {
1218                         uint32_t i = strlen(string[tok[1]]);
1219
1220                         if ((challoc - ch_size) < i)
1221                                 chcheck(i);
1222
1223                         if (*tok == STRING)
1224                         {
1225                                 for(p=string[tok[1]]; *p!=EOS; p++)
1226                                         D_byte(*p);
1227                         }
1228                         else if (*tok == STRINGA8)
1229                         {
1230                                 for(p=string[tok[1]]; *p!=EOS; p++)
1231                                         D_byte(strtoa8[*p]);
1232                         }
1233                         else
1234                         {
1235                                 error("String format not supported... yet");
1236                         }
1237
1238                         tok += 2;
1239                         goto comma;
1240                 }
1241
1242                 int movei = 0; // MOVEI flag for dc.i
1243
1244                 if (*tok == DOTI)
1245                 {
1246                         movei = 1;
1247                         tok++;
1248                         siz = SIZL;
1249                 }
1250
1251                 // dc.x <expression>
1252                 SYM * esym = 0;
1253
1254                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
1255                         return 0;
1256
1257                 uint16_t tdb = eattr & TDB;
1258                 uint16_t defined = eattr & DEFINED;
1259
1260 // N.B.: This is awful.  This needs better handling, rather than just bodging something in that, while works, is basically an ugly wart on the assembler.  !!! FIX !!!
1261                 if (dsp56001)
1262                 {
1263                         if (cursect != M56001L)
1264                         {
1265                                 if (!defined)
1266                                 {
1267                                         AddFixup(FU_DSPIMM24 | FU_SEXT, sloc, exprbuf);
1268                                         D_dsp(0);
1269                                 }
1270                                 else
1271                                 {
1272                                         if (eattr & FLOAT)
1273                                         {
1274                                                 double fval = *(double *)&eval;
1275                                                 eval = DoubleToDSPFloat(fval);
1276                                         }
1277                                         else
1278                                         {
1279                                                 if ((uint32_t)eval + 0x1000000 >= 0x2000000)
1280                                                         return error(range_error);
1281                                         }
1282
1283                                         // Deposit DSP word (24-bit)
1284                                         D_dsp(eval);
1285                                 }
1286                         }
1287                         else
1288                         {
1289                                 // In L: we deposit stuff to both X: and Y: instead
1290                                 // We will be a bit lazy and require that there is a 2nd value
1291                                 // in the same source line. (Motorola's assembler can parse
1292                                 // 12-digit hex values, which we can't do at the moment) This
1293                                 // of course requires to parse 2 values in one pass. If there
1294                                 // isn't another value in this line, assume X: value is 0.
1295                                 int secondword = 0;
1296                                 uint32_t evaly;
1297 l_parse_loop:
1298
1299                                 if (!defined)
1300                                 {
1301                                         AddFixup(FU_DSPIMM24 | FU_SEXT, sloc, exprbuf);
1302                                         D_dsp(0);
1303                                 }
1304                                 else
1305                                 {
1306                                         if (eattr & FLOAT)
1307                                         {
1308                                                 float fval = *(float *)&eval;
1309                                                 eval = DoubleToDSPFloat(fval);
1310                                         }
1311                                         else
1312                                         {
1313                                                 if (eval + 0x1000000 >= 0x2000000)
1314                                                         return error(range_error);
1315                                         }
1316
1317                                         // Parse 2nd value if we didn't do this yet
1318                                         if (secondword == 0)
1319                                         {
1320                                                 evaly = (uint32_t)eval;
1321                                                 secondword = 1;
1322
1323                                                 if (*tok != ':')
1324                                                 {
1325                                                         // If we don't have a : then we're probably at EOL,
1326                                                         // which means the X: value will be 0
1327                                                         eval = 0;
1328                                                         ErrorIfNotAtEOL();
1329                                                 }
1330                                                 else
1331                                                 {
1332                                                         tok++; // Eat the comma;
1333
1334                                                         if (expr(exprbuf, &eval, &eattr, NULL) != OK)
1335                                                                 return 0;
1336
1337                                                         defined = (WORD)(eattr & DEFINED);
1338                                                         goto l_parse_loop;
1339                                                 }
1340                                         }
1341
1342                                         // Deposit DSP words (24-bit)
1343                                         D_dsp(eval);
1344                                         D_dsp(evaly);
1345                                         sloc--; // We do write 2 DSP words but as far as L: space is concerned we actually advance our counter by one
1346                                 }
1347
1348                         }
1349
1350                         goto comma;
1351                 }
1352
1353                 switch (siz)
1354                 {
1355                 case SIZB:
1356                         if (!defined)
1357                         {
1358                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1359                                 D_byte(0);
1360                         }
1361                         else
1362                         {
1363                                 if (tdb)
1364                                         return error("non-absolute byte value");
1365
1366                                 if (eval + 0x100 >= 0x200)
1367                                         return error("%s (value = $%X)", range_error, eval);
1368
1369                                 D_byte(eval);
1370                         }
1371
1372                         break;
1373
1374                 case SIZW:
1375                 case SIZN:
1376                         if (!defined)
1377                         {
1378                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1379                                 D_word(0);
1380                         }
1381                         else
1382                         {
1383                                 if (eval + 0x10000 >= 0x20000)
1384                                         return error(range_error);
1385
1386                                 if (tdb)
1387                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1388
1389                                 // Deposit 68000 or 6502 (byte-reversed) word
1390                                 if (cursect != M6502)
1391                                         D_word(eval)
1392                                 else
1393                                         D_rword(eval)
1394                         }
1395
1396                         break;
1397
1398                 case SIZL:
1399                         // Shamus: Why can't we do longs in 6502 mode?
1400                         if (m6502)
1401                                 return error(in_6502mode);
1402
1403                         if (!defined)
1404                         {
1405                                 AddFixup(FU_LONG | (movei ? FU_MOVEI : 0), sloc, exprbuf);
1406                                 D_long(0);
1407                         }
1408                         else
1409                         {
1410                                 if (tdb)
1411                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1412
1413                                 if (movei)
1414                                         eval = WORDSWAP32(eval);
1415
1416                                 D_long(eval);
1417                         }
1418
1419                         break;
1420
1421                 case SIZQ:
1422                         // 64-bit size
1423                         if (m6502)
1424                                 return error(in_6502mode);
1425
1426                         // DEFINITELY NEED FIXUPS HERE!
1427                         if (!defined)
1428                         {
1429                                 AddFixup(FU_QUAD, sloc, exprbuf);
1430                                 eval = 0;
1431                         }
1432
1433                         D_quad(eval);
1434                         break;
1435
1436                 case SIZS:
1437                         // 32-bit float size
1438                         if (m6502)
1439                                 return error(in_6502mode);
1440
1441 /* Seems to me that if something is undefined here, then that should be an error.  Likewise for the D & X variants. */
1442                         if (!defined)
1443                         {
1444 //                              AddFixup(FU_FLOATSING, sloc, exprbuf);
1445 //                              D_long(0);
1446                                 return error("labels not allowed in floating point expressions");
1447                         }
1448                         else
1449                         {
1450 //Would this *ever* happen?
1451 //                              if (tdb)
1452 //                                      MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
1453
1454                                 PTR ptr;
1455                                 ptr.u64 = &eval;
1456                                 uint32_t ieee754 = FloatToIEEE754((float)*ptr.dp);
1457                                 D_long(ieee754);
1458                         }
1459
1460                         break;
1461
1462                 case SIZD:
1463                         // 64-bit double size
1464                         if (m6502)
1465                                 return error(in_6502mode);
1466
1467                         if (!defined)
1468                         {
1469 //                              AddFixup(FU_FLOATDOUB, sloc, exprbuf);
1470 //                              D_quad(0LL);
1471                                 return error("labels not allowed in floating point expressions");
1472                         }
1473                         else
1474                         {
1475 //Would this *ever* happen?
1476 //                              if (tdb)
1477 //                                      MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
1478
1479                                 PTR ptr;
1480                                 ptr.u64 = &eval;
1481                                 uint64_t ieee754 = DoubleToIEEE754(*ptr.dp);
1482                                 D_quad(ieee754);
1483                         }
1484
1485                         break;
1486
1487                 case SIZX:
1488                         if (m6502)
1489                                 return error(in_6502mode);
1490
1491                         uint8_t extDbl[12];
1492                         memset(extDbl, 0, 12);
1493
1494                         if (!defined)
1495                         {
1496 //                              AddFixup(FU_FLOATEXT, sloc, exprbuf);
1497 //                              D_extend(extDbl);
1498                                 return error("labels not allowed in floating point expressions");
1499                         }
1500                         else
1501                         {
1502 //Would this *ever* happen?
1503 //                              if (tdb)
1504 //                                      MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
1505
1506                                 PTR ptr;
1507                                 ptr.u64 = &eval;
1508                                 DoubleToExtended(*ptr.dp, extDbl);
1509                                 D_extend(extDbl);
1510                         }
1511
1512                         break;
1513                 }
1514
1515 comma:
1516                 if (*tok != ',')
1517                         break;
1518         }
1519
1520         ErrorIfNotAtEOL();
1521         return 0;
1522 }
1523
1524
1525 //
1526 // dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2'
1527 //
1528 int d_dcb(WORD siz)
1529 {
1530         uint64_t evalc, eval;
1531         WORD eattr;
1532
1533         DEBUG { printf("dcb: section is %s%s%s (scattr=$%X)\n", (cursect & TEXT ? "TEXT" : ""), (cursect & DATA ? " DATA" : ""), (cursect & BSS ? "BSS" : ""), scattr); }
1534
1535         if ((scattr & SBSS) != 0)
1536                 return error("illegal initialization of section");
1537
1538         if (abs_expr(&evalc) != OK)
1539                 return 0;
1540
1541         if (*tok++ != ',')
1542                 return error("missing comma");
1543
1544         if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1545                 return 0;
1546
1547         if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
1548                 auto_even();
1549
1550         dep_block((uint32_t)evalc, siz, (uint32_t)eval, eattr, exprbuf);
1551         return 0;
1552 }
1553
1554
1555 //
1556 // Generalized initialization directive
1557 //
1558 // .init[.siz] [#count,] expression [.size] , ...
1559 //
1560 // The size suffix on the ".init" directive becomes the default size of the
1561 // objects to deposit. If an item is preceeded with a sharp (immediate) sign
1562 // and an expression, it specifies a repeat count. The value to be deposited
1563 // may be followed by a size suffix, which overrides the default size.
1564 //
1565 int d_init(WORD def_siz)
1566 {
1567         uint64_t count;
1568         uint64_t eval;
1569         WORD eattr;
1570         WORD siz;
1571
1572         if ((scattr & SBSS) != 0)
1573                 return error(".init not permitted in BSS or ABS");
1574
1575         if (rgpu || rdsp)
1576                 return error("directive forbidden in gpu/dsp mode");
1577
1578         for(;;)
1579         {
1580                 // Get repeat count (defaults to 1)
1581                 if (*tok == '#')
1582                 {
1583                         tok++;
1584
1585                         if (abs_expr(&count) != OK)
1586                                 return 0;
1587
1588                         if (*tok++ != ',')
1589                                 return error(comma_error);
1590                 }
1591                 else
1592                         count = 1;
1593
1594                 // Evaluate expression to deposit
1595                 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1596                         return 0;
1597
1598                 switch (*tok++)
1599                 {                                 // Determine size of object to deposit
1600                 case DOTB: siz = SIZB; break;
1601                 case DOTW: siz = SIZB; break;
1602                 case DOTL: siz = SIZL; break;
1603                 default:
1604                         siz = def_siz;
1605                         tok--;
1606                         break;
1607                 }
1608
1609                 dep_block((uint32_t)count, siz, (uint32_t)eval, eattr, exprbuf);
1610
1611                 switch (*tok)
1612                 {
1613                 case EOL:
1614                         return 0;
1615                 case ',':
1616                         tok++;
1617                         continue;
1618                 default:
1619                         return error(comma_error);
1620                 }
1621         }
1622 }
1623
1624
1625 //
1626 // Deposit 'count' values of size 'siz' in the current (non-BSS) segment
1627 //
1628 int dep_block(uint32_t count, WORD siz, uint32_t eval, WORD eattr, TOKEN * exprbuf)
1629 {
1630         WORD tdb = eattr & TDB;
1631         WORD defined = eattr & DEFINED;
1632
1633         while (count--)
1634         {
1635                 if ((challoc - ch_size) < 4)
1636                         chcheck(4L);
1637
1638                 switch(siz)
1639                 {
1640                 case SIZB:
1641                         if (!defined)
1642                         {
1643                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1644                                 D_byte(0);
1645                         }
1646                         else
1647                         {
1648                                 if (tdb)
1649                                         return error("non-absolute byte value");
1650
1651                                 if (eval + 0x100 >= 0x200)
1652                                         return error(range_error);
1653
1654                                 D_byte(eval);
1655                         }
1656
1657                         break;
1658                 case SIZW:
1659                 case SIZN:
1660                         if (!defined)
1661                         {
1662                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1663                                 D_word(0);
1664                         }
1665                         else
1666                         {
1667                                 if (tdb)
1668                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1669
1670                                 if (eval + 0x10000 >= 0x20000)
1671                                         return error(range_error);
1672
1673                                 // Deposit 68000 or 6502 (byte-reversed) word
1674                                 if (cursect != M6502)
1675                                         D_word(eval)
1676                                 else
1677                                         D_rword(eval)
1678
1679                         }
1680
1681                         break;
1682                 case SIZL:
1683                         if (m6502)
1684                                 return error(in_6502mode);
1685
1686                         if (!defined)
1687                         {
1688                                 AddFixup(FU_LONG, sloc, exprbuf);
1689                                 D_long(0);
1690                         }
1691                         else
1692                         {
1693                                 if (tdb)
1694                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1695
1696                                 D_long(eval);
1697                         }
1698
1699                         break;
1700                 }
1701         }
1702
1703         return 0;
1704 }
1705
1706
1707 //
1708 // .comm symbol, size
1709 //
1710 int d_comm(void)
1711 {
1712         SYM * sym;
1713         char * p;
1714         uint64_t eval;
1715
1716         if (m6502)
1717                 return error(in_6502mode);
1718
1719         if (*tok != SYMBOL)
1720                 return error("missing symbol");
1721
1722         p = string[tok[1]];
1723         tok += 2;
1724
1725         if (*p == '.')                                          // Cannot .comm a local symbol
1726                 return error(locgl_error);
1727
1728         if ((sym = lookup(p, LABEL, 0)) == NULL)
1729                 sym = NewSymbol(p, LABEL, 0);
1730         else
1731         {
1732                 if (sym->sattr & DEFINED)
1733                         return error(".comm symbol already defined");
1734         }
1735
1736         sym->sattr = GLOBAL | COMMON | BSS;
1737
1738         if (*tok++ != ',')
1739                 return error(comma_error);
1740
1741         if (abs_expr(&eval) != OK)                      // Parse size of common region
1742                 return 0;
1743
1744         sym->svalue = eval;                                     // Install common symbol's size
1745         ErrorIfNotAtEOL();
1746         return 0;
1747 }
1748
1749
1750 //
1751 // .list - Turn listing on
1752 //
1753 int d_list(void)
1754 {
1755         if (list_flag)
1756                 listing++;
1757
1758         return 0;
1759 }
1760
1761
1762 //
1763 // .nlist - Turn listing off
1764 //
1765 int d_nlist(void)
1766 {
1767         if (list_flag)
1768                 listing--;
1769
1770         return 0;
1771 }
1772
1773
1774 //
1775 // .68000 - Back to 68000 TEXT segment
1776 //
1777 int d_68000(void)
1778 {
1779         rgpu = rdsp = robjproc = dsp56001 = 0;
1780         // Switching from gpu/dsp sections should reset any ORG'd Address
1781         orgactive = 0;
1782         orgwarning = 0;
1783         SaveSection();
1784         SwitchSection(TEXT);
1785         activecpu = CPU_68000;
1786         return 0;
1787 }
1788
1789
1790 //
1791 // .68020 - Back to 68000 TEXT segment and select 68020
1792 //
1793 int d_68020(void)
1794 {
1795         d_68000();
1796         activecpu = CPU_68020;
1797         return 0;
1798 }
1799
1800
1801 //
1802 // .68030 - Back to 68000 TEXT segment and select 68030
1803 //
1804 int d_68030(void)
1805 {
1806         d_68000();
1807         activecpu = CPU_68030;
1808         return 0;
1809 }
1810
1811
1812 //
1813 // .68040 - Back to 68000 TEXT segment and select 68040
1814 //
1815 int d_68040(void)
1816 {
1817         d_68000();
1818         activecpu = CPU_68040;
1819         activefpu = FPU_68040;
1820         return 0;
1821 }
1822
1823
1824 //
1825 // .68060 - Back to 68000 TEXT segment and select 68060
1826 //
1827 int d_68060(void)
1828 {
1829         d_68000();
1830         activecpu = CPU_68060;
1831         activefpu = FPU_68060;
1832         return 0;
1833 }
1834
1835
1836 //
1837 // .68881 - Back to 680x0 TEXT segment and select 68881 FPU
1838 //
1839 int d_68881(void)
1840 {
1841         //d_68000();
1842         activefpu = FPU_68881;
1843         return 0;
1844 }
1845
1846
1847 //
1848 // .68882 - Back to 680x0 TEXT segment and select 68882 FPU
1849 //
1850 int d_68882(void)
1851 {
1852         //d_68000();
1853         activefpu = FPU_68882;
1854         return 0;
1855 }
1856
1857
1858 //
1859 // nofpu - Deselect FPUs.
1860 //
1861 int d_nofpu(void)
1862 {
1863         activefpu = FPU_NONE;
1864         return 0;
1865 }
1866
1867
1868 //
1869 // .56001 - Switch to DSP56001 assembler
1870 //
1871 int d_56001(void)
1872 {
1873         dsp56001 = 1;
1874         rgpu = rdsp = robjproc = 0;
1875         SaveSection();
1876
1877         if ((obj_format == LOD) || (obj_format == P56))
1878                 SwitchSection(M56001P);
1879
1880         return 0;
1881 }
1882
1883
1884 //
1885 // .gpu - Switch to GPU assembler
1886 //
1887 int d_gpu(void)
1888 {
1889         if ((cursect != TEXT) && (cursect != DATA))
1890         {
1891                 error(".gpu can only be used in the TEXT or DATA segments");
1892                 return ERROR;
1893         }
1894
1895         // If previous section was DSP or 68000 then we need to reset ORG'd Addresses
1896         if (!rgpu)
1897         {
1898                 orgactive = 0;
1899                 orgwarning = 0;
1900         }
1901
1902         rgpu = 1;                       // Set GPU assembly
1903         rdsp = 0;                       // Unset DSP assembly
1904         robjproc = 0;           // Unset OP assembly
1905         dsp56001 = 0;           // Unset 56001 assembly
1906         regbank = BANK_N;       // Set no default register bank
1907         return 0;
1908 }
1909
1910
1911 //
1912 // .dsp - Switch to DSP assembler
1913 //
1914 int d_dsp(void)
1915 {
1916         if ((cursect != TEXT) && (cursect != DATA))
1917         {
1918                 error(".dsp can only be used in the TEXT or DATA segments");
1919                 return ERROR;
1920         }
1921
1922         // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
1923         if (!rdsp)
1924         {
1925                 orgactive = 0;
1926                 orgwarning = 0;
1927         }
1928
1929         rdsp = 1;                       // Set DSP assembly
1930         rgpu = 0;                       // Unset GPU assembly
1931         robjproc = 0;           // Unset OP assembly
1932         dsp56001 = 0;           // Unset 56001 assembly
1933         regbank = BANK_N;       // Set no default register bank
1934         return 0;
1935 }
1936
1937
1938 //
1939 // .cargs [#offset], symbol[.size], ...
1940 //
1941 // Lists of registers may also be mentioned; they just take up space. Good for
1942 // "documentation" purposes:
1943 //
1944 // .cargs a6, .arg1, .arg2, .arg3...
1945 //
1946 // Symbols thus created are ABS and EQUATED.
1947 //
1948 int d_cargs(void)
1949 {
1950         uint64_t eval = 4;      // Default to 4 if no offset specified (to account for
1951                                                 // return address)
1952         WORD rlist;
1953         SYM * symbol;
1954         char * p;
1955         int env;
1956         int i;
1957
1958         if (rgpu || rdsp)
1959                 return error("directive forbidden in gpu/dsp mode");
1960
1961         if (*tok == '#')
1962         {
1963                 tok++;
1964
1965                 if (abs_expr(&eval) != OK)
1966                         return 0;
1967
1968                 // Eat the comma, if it's there
1969                 if (*tok == ',')
1970                         tok++;
1971         }
1972
1973         for(;;)
1974         {
1975                 if (*tok == SYMBOL)
1976                 {
1977                         p = string[tok[1]];
1978
1979                         // Set env to either local (dot prefixed) or global scope
1980                         env = (*p == '.' ? curenv : 0);
1981                         symbol = lookup(p, LABEL, env);
1982
1983                         if (symbol == NULL)
1984                         {
1985                                 symbol = NewSymbol(p, LABEL, env);
1986                                 symbol->sattr = 0;
1987                         }
1988                         else if (symbol->sattr & DEFINED)
1989                                 return error("multiply-defined label '%s'", p);
1990
1991                         // Put symbol in "order of definition" list
1992                         AddToSymbolDeclarationList(symbol);
1993
1994                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1995                         symbol->svalue = eval;
1996                         tok += 2;
1997
1998                         // What this does is eat any dot suffixes attached to a symbol. If
1999                         // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
2000                         // there is no dot suffix, it assumes a size of 2.
2001                         switch ((int)*tok)
2002                         {
2003                         case DOTL:
2004                                 eval += 2;
2005                         case DOTB:
2006                         case DOTW:
2007                                 tok++;
2008                         }
2009
2010                         eval += 2;
2011                 }
2012                 else if (*tok >= KW_D0 && *tok <= KW_A7)
2013                 {
2014                         if (reglist(&rlist) < 0)
2015                                 return 0;
2016
2017                         for(i=0; i<16; i++, rlist>>=1)
2018                         {
2019                                 if (rlist & 1)
2020                                         eval += 4;
2021                         }
2022                 }
2023                 else
2024                 {
2025                         switch ((int)*tok)
2026                         {
2027                         case KW_USP:
2028                         case KW_SSP:
2029                         case KW_PC:
2030                                 eval += 2;
2031                                 // FALLTHROUGH
2032                         case KW_SR:
2033                         case KW_CCR:
2034                                 eval += 2;
2035                                 tok++;
2036                                 break;
2037                         case EOL:
2038                                 return 0;
2039                         default:
2040                                 return error(".cargs syntax");
2041                         }
2042                 }
2043
2044                 // Eat commas in between each argument, if they exist
2045                 if (*tok == ',')
2046                         tok++;
2047         }
2048 }
2049
2050
2051 //
2052 // .cstruct [#offset], symbol[.size], ...
2053 //
2054 // Lists of registers may also be mentioned; they just take up space. Good for
2055 // "documentation" purposes:
2056 //
2057 // .cstruct a6, .arg1, .arg2, .arg3...
2058 //
2059 // Symbols thus created are ABS and EQUATED. Note that this is for
2060 // compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
2061 // the suggestion.
2062 //
2063 int d_cstruct(void)
2064 {
2065         uint64_t eval = 0;      // Default, if no offset specified, is zero
2066         WORD rlist;
2067         SYM * symbol;
2068         char * symbolName;
2069         int env;
2070         int i;
2071
2072         if (rgpu || rdsp)
2073                 return error("directive forbidden in gpu/dsp mode");
2074
2075         if (*tok == '#')
2076         {
2077                 tok++;
2078
2079                 if (abs_expr(&eval) != OK)
2080                         return 0;
2081
2082                 // Eat the comma, if it's there
2083                 if (*tok == ',')
2084                         tok++;
2085         }
2086
2087         for(;;)
2088         {
2089                 if (*tok == SYMBOL)
2090                 {
2091                         symbolName = string[tok[1]];
2092
2093                         // Set env to either local (dot prefixed) or global scope
2094                         env = (symbolName[0] == '.' ? curenv : 0);
2095                         symbol = lookup(symbolName, LABEL, env);
2096
2097                         // If the symbol wasn't found, then define it. Otherwise, throw an
2098                         // error.
2099                         if (symbol == NULL)
2100                         {
2101                                 symbol = NewSymbol(symbolName, LABEL, env);
2102                                 symbol->sattr = 0;
2103                         }
2104                         else if (symbol->sattr & DEFINED)
2105                                 return error("multiply-defined label '%s'", symbolName);
2106
2107                         // Put symbol in "order of definition" list
2108                         AddToSymbolDeclarationList(symbol);
2109
2110                         tok += 2;
2111
2112                         // Adjust label start address if it's a word or a long, as a byte
2113                         // label might have left us on an odd address.
2114                         switch ((int)*tok)
2115                         {
2116                         case DOTW:
2117                         case DOTL:
2118                                 eval += eval & 0x01;
2119                         }
2120
2121                         symbol->sattr |= (ABS | DEFINED | EQUATED);
2122                         symbol->svalue = eval;
2123
2124                         // Check for dot suffixes and adjust space accordingly (longs and
2125                         // words on an odd boundary get bumped to the next word aligned
2126                         // address). If no suffix, then throw an error.
2127                         switch ((int)*tok)
2128                         {
2129                         case DOTL:
2130                                 eval += 4;
2131                                 break;
2132                         case DOTW:
2133                                 eval += 2;
2134                                 break;
2135                         case DOTB:
2136                                 eval += 1;
2137                                 break;
2138                         default:
2139                                 return error("Symbol missing dot suffix in .cstruct construct");
2140                         }
2141
2142                         tok++;
2143                 }
2144                 else if (*tok >= KW_D0 && *tok <= KW_A7)
2145                 {
2146                         if (reglist(&rlist) < 0)
2147                                 return 0;
2148
2149                         for(i=0; i<16; i++, rlist>>=1)
2150                         {
2151                                 if (rlist & 1)
2152                                         eval += 4;
2153                         }
2154                 }
2155                 else
2156                 {
2157                         switch ((int)*tok)
2158                         {
2159                         case KW_USP:
2160                         case KW_SSP:
2161                         case KW_PC:
2162                                 eval += 2;
2163                                 // FALLTHROUGH
2164                         case KW_SR:
2165                         case KW_CCR:
2166                                 eval += 2;
2167                                 tok++;
2168                                 break;
2169                         case EOL:
2170                                 return 0;
2171                         default:
2172                                 return error(".cstruct syntax");
2173                         }
2174                 }
2175
2176                 // Eat commas in between each argument, if they exist
2177                 if (*tok == ',')
2178                         tok++;
2179         }
2180 }
2181
2182
2183 //
2184 // Define start of OP object list (allows the use of ORG)
2185 //
2186 int d_objproc(void)
2187 {
2188         if ((cursect != TEXT) && (cursect != DATA))
2189         {
2190                 error(".objproc can only be used in the TEXT or DATA segments");
2191                 return ERROR;
2192         }
2193
2194         // If previous section was DSP or 68000 then we need to reset ORG'd
2195         // Addresses
2196         if (!robjproc)
2197         {
2198                 orgactive = 0;
2199                 orgwarning = 0;
2200         }
2201
2202         robjproc = 1;           // Set OP assembly
2203         rgpu = 0;                       // Unset GPU assembly
2204         rdsp = 0;                       // Unset DSP assembly
2205         dsp56001 = 0;           // Unset 56001 assembly
2206         return OK;
2207 }
2208
2209
2210 //
2211 // Undefine a macro - .undefmac macname [, macname...]
2212 //
2213 int undmac1(char * p)
2214 {
2215         SYM * symbol = lookup(p, MACRO, 0);
2216
2217         // If the macro symbol exists, cause it to disappear
2218         if (symbol != NULL)
2219                 symbol->stype = (BYTE)SY_UNDEF;
2220
2221         return OK;
2222 }
2223
2224
2225 int d_undmac(void)
2226 {
2227         symlist(undmac1);
2228         return 0;
2229 }
2230
2231
2232 int d_jpad(void)
2233 {
2234         warn("JPAD directive is deprecated/non-functional");
2235         return OK;
2236 }
2237
2238
2239 int d_nojpad(void)
2240 {
2241         warn("NOJPAD directive is deprecated/non-functional");
2242         return OK;
2243 }
2244
2245
2246 int d_gpumain(void)
2247 {
2248         return error("What the hell? Do you think we adhere to the Goof standard?");
2249 }
2250
2251
2252 //
2253 // .opt - turn a specific (or all) optimisation on or off
2254 //
2255 int d_opt(void)
2256 {
2257         while (*tok != EOL)
2258         {
2259                 if (*tok == STRING)
2260                 {
2261                         tok++;
2262                         char * tmpstr = string[*tok++];
2263
2264                         if (ParseOptimization(tmpstr) != OK)
2265                                 return error("unknown optimization flag '%s'", tmpstr);
2266                 }
2267                 else
2268                         return error(".opt directive needs every switch enclosed inside quotation marks");
2269         }
2270
2271         return OK;
2272 }
2273
2274
2275 //
2276 // .if, Start conditional assembly
2277 //
2278 int d_if(void)
2279 {
2280         WORD eattr;
2281         uint64_t eval;
2282         SYM * esym;
2283         IFENT * rif = f_ifent;
2284
2285         // Alloc an IFENTRY
2286         if (rif == NULL)
2287                 rif = (IFENT *)malloc(sizeof(IFENT));
2288         else
2289                 f_ifent = rif->if_prev;
2290
2291         rif->if_prev = ifent;
2292         ifent = rif;
2293
2294         if (!disabled)
2295         {
2296                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
2297                         return 0;
2298
2299                 if ((eattr & DEFINED) == 0)
2300                         return error(undef_error);
2301
2302                 disabled = !eval;
2303         }
2304
2305         rif->if_state = (WORD)disabled;
2306         return 0;
2307 }
2308
2309
2310 //
2311 // .else, Do alternate case for .if
2312 //
2313 int d_else(void)
2314 {
2315         IFENT * rif = ifent;
2316
2317         if (rif->if_prev == NULL)
2318                 return error("mismatched .else");
2319
2320         if (disabled)
2321                 disabled = rif->if_prev->if_state;
2322         else
2323                 disabled = 1;
2324
2325         rif->if_state = (WORD)disabled;
2326         return 0;
2327 }
2328
2329
2330 //
2331 // .endif, End of conditional assembly block
2332 // This is also called by fpop() to pop levels of IFENTs in case a macro or
2333 // include file exits early with `exitm' or `end'.
2334 //
2335 int d_endif(void)
2336 {
2337         IFENT * rif = ifent;
2338
2339         if (rif->if_prev == NULL)
2340                 return error("mismatched .endif");
2341
2342         ifent = rif->if_prev;
2343         disabled = rif->if_prev->if_state;
2344         rif->if_prev = f_ifent;
2345         f_ifent = rif;
2346         return 0;
2347 }
2348