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