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