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