7c480357c4e801b9420dd1ea1ad4b873a211a454
[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 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
1002 //
1003 int d_dc(WORD siz)
1004 {
1005         WORD eattr;
1006         uint64_t eval;
1007         WORD tdb;
1008         WORD defined;
1009         uint64_t val64;
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++)
1027         {
1028                 // dc.b 'string' [,] ...
1029                 if (siz == SIZB && (*tok == STRING || *tok == STRINGA8) && (tok[2] == ',' || tok[2] == EOL))
1030                 {
1031                         uint32_t i = strlen(string[tok[1]]);
1032
1033                         if ((challoc - ch_size) < i)
1034                                 chcheck(i);
1035
1036                         if (*tok == STRING)
1037                         {
1038                                 for(p=string[tok[1]]; *p!=EOS; p++)
1039                                         D_byte(*p);
1040                         }
1041                         else if(*tok == STRINGA8)
1042                         {
1043                                 for(p=string[tok[1]]; *p!=EOS; p++)
1044                                         D_byte(strtoa8[*p]);
1045                         }
1046                         else
1047                         {
1048                                 error("String format not supported... yet");
1049                         }
1050
1051                         tok += 2;
1052                         goto comma;
1053                 }
1054
1055                 int movei = 0; // MOVEI flag for dc.i
1056
1057                 if (*tok == DOTI)
1058                 {
1059                         movei = 1;
1060                         tok++;
1061                         siz = SIZL;
1062                 }
1063
1064                 if (siz != SIZQ)
1065                 {
1066                 // dc.x <expression>
1067                 SYM * esym = 0;
1068
1069                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
1070                         return 0;
1071                 }
1072                 else
1073                 {
1074                         val64 = *(uint64_t *)(tok);
1075                         tok = tok + 2;
1076                         D_long((uint32_t)(val64 >> 32));
1077                         D_long((uint32_t)val64);
1078
1079             goto comma;
1080         }
1081
1082                 tdb = (WORD)(eattr & TDB);
1083                 defined = (WORD)(eattr & DEFINED);
1084
1085                 if ((challoc - ch_size) < 4)
1086                         chcheck(4);
1087
1088                 switch (siz)
1089                 {
1090                 case SIZB:
1091                         if (!defined)
1092                         {
1093                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1094                                 D_byte(0);
1095                         }
1096                         else
1097                         {
1098                                 if (tdb)
1099                                         return error("non-absolute byte value");
1100
1101                                 if (eval + 0x100 >= 0x200)
1102                                         return error("%s (value = $%X)", range_error, eval);
1103
1104                                 D_byte(eval);
1105                         }
1106
1107                         break;
1108                 case SIZW:
1109                 case SIZN:
1110                         if (!defined)
1111                         {
1112                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1113                                 D_word(0);
1114                         }
1115                         else
1116                         {
1117                                 if (eval + 0x10000 >= 0x20000)
1118                                         return error(range_error);
1119
1120                                 if (tdb)
1121                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1122
1123                                 // Deposit 68000 or 6502 (byte-reversed) word
1124                                 if (cursect != M6502)
1125                                         D_word(eval)
1126                                 else
1127                                         D_rword(eval)
1128                         }
1129
1130                         break;
1131                 case SIZL:
1132                         // Shamus: Why can't we do longs in 6502 mode?
1133                         if (m6502)
1134                                 return error(in_6502mode);
1135
1136                         if (!defined)
1137                         {
1138                                 if (movei)
1139                                         AddFixup(FU_LONG | FU_MOVEI, sloc, exprbuf);
1140                                 else
1141                                         AddFixup(FU_LONG, sloc, exprbuf);
1142
1143                                 D_long(0);
1144                         }
1145                         else
1146                         {
1147                                 if (tdb)
1148                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1149
1150                                 if (movei)
1151                                         eval = WORDSWAP32(eval);
1152
1153                                 D_long(eval);
1154                         }
1155                         break;
1156                 case SIZS:
1157                         if (m6502)
1158                                 return error(in_6502mode);
1159
1160                         if (!defined)
1161                         {
1162                                 float vv = 0;
1163                                 AddFixup(FU_FLOATSING, sloc, exprbuf);
1164
1165                                 D_single(vv);
1166                         }
1167                         else
1168                         {
1169                                 if (tdb)
1170                                         MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
1171
1172                                 D_single(eval);
1173                         }
1174                         break;
1175                 case SIZD:
1176                         if (m6502)
1177                                 return error(in_6502mode);
1178
1179                         if (!defined)
1180                         {
1181                                 double vv = 0;
1182                                 AddFixup(FU_FLOATDOUB, sloc, exprbuf);
1183
1184                                 D_double(vv);
1185                         }
1186                         else
1187                         {
1188                                 double vv;
1189                                 if (tdb)
1190                                         MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
1191
1192                                 vv = *(double *)&eval;
1193                                 D_double(vv);
1194                         }
1195                         break;
1196                 case SIZX:
1197                         if (m6502)
1198                                 return error(in_6502mode);
1199
1200                         if (!defined)
1201                         {
1202                                 double vv = 0;
1203                                 AddFixup(FU_FLOATEXT, sloc, exprbuf);
1204
1205                                 D_extend(vv);
1206                         }
1207                         else
1208                         {
1209                                 float vv;
1210                                 if (tdb)
1211                                         MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
1212
1213                                 vv = *(double *)&eval;
1214                                 D_extend(vv);
1215                         }
1216                         break;
1217                 }
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 ((int)*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 ((int)*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 //printf("Resetting ORG...\n");
1600                 orgactive = 0;
1601                 orgwarning = 0;
1602         }
1603 //else printf("NOT resetting ORG!\n");
1604
1605         rgpu = 1;                       // Set GPU assembly
1606         rdsp = 0;                       // Unset DSP assembly
1607         regbank = BANK_N;       // Set no default register bank
1608         return 0;
1609 }
1610
1611
1612 //
1613 // .dsp - Switch to DSP assembler
1614 //
1615 int d_dsp(void)
1616 {
1617         if ((cursect != TEXT) && (cursect != DATA))
1618         {
1619                 error(".dsp can only be used in the TEXT or DATA segments");
1620                 return ERROR;
1621         }
1622
1623         // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
1624         if (!rdsp)
1625         {
1626                 orgactive = 0;
1627                 orgwarning = 0;
1628         }
1629
1630         rdsp = 1;                       // Set DSP assembly
1631         rgpu = 0;                       // Unset GPU assembly
1632         regbank = BANK_N;       // Set no default register bank
1633         return 0;
1634 }
1635
1636
1637 //
1638 // .cargs [#offset], symbol[.size], ...
1639 //
1640 // Lists of registers may also be mentioned; they just take up space. Good for
1641 // "documentation" purposes:
1642 //
1643 // .cargs a6, .arg1, .arg2, .arg3...
1644 //
1645 // Symbols thus created are ABS and EQUATED.
1646 //
1647 int d_cargs(void)
1648 {
1649         uint64_t eval = 4;      // Default to 4 if no offset specified (to account for
1650                                                 // return address)
1651         WORD rlist;
1652         SYM * symbol;
1653         char * p;
1654         int env;
1655         int i;
1656
1657         if (rgpu || rdsp)
1658                 return error("directive forbidden in gpu/dsp mode");
1659
1660         if (*tok == '#')
1661         {
1662                 tok++;
1663
1664                 if (abs_expr(&eval) != OK)
1665                         return 0;
1666
1667                 // Eat the comma, if it's there
1668                 if (*tok == ',')
1669                         tok++;
1670         }
1671
1672         for(;;)
1673         {
1674                 if (*tok == SYMBOL)
1675                 {
1676                         p = string[tok[1]];
1677
1678                         // Set env to either local (dot prefixed) or global scope
1679                         env = (*p == '.' ? curenv : 0);
1680                         symbol = lookup(p, LABEL, env);
1681
1682                         if (symbol == NULL)
1683                         {
1684                                 symbol = NewSymbol(p, LABEL, env);
1685                                 symbol->sattr = 0;
1686                         }
1687                         else if (symbol->sattr & DEFINED)
1688                                 return error("multiply-defined label '%s'", p);
1689
1690                         // Put symbol in "order of definition" list
1691                         AddToSymbolDeclarationList(symbol);
1692
1693                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1694                         symbol->svalue = (uint32_t)eval;
1695                         tok += 2;
1696
1697                         // What this does is eat any dot suffixes attached to a symbol. If
1698                         // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
1699                         // there is no dot suffix, it assumes a size of 2.
1700                         switch ((int)*tok)
1701                         {
1702                         case DOTL:
1703                                 eval += 2;
1704                         case DOTB:
1705                         case DOTW:
1706                                 tok++;
1707                         }
1708
1709                         eval += 2;
1710                 }
1711                 else if (*tok >= KW_D0 && *tok <= KW_A7)
1712                 {
1713                         if (reglist(&rlist) < 0)
1714                                 return 0;
1715
1716                         for(i=0; i<16; i++, rlist>>=1)
1717                         {
1718                                 if (rlist & 1)
1719                                         eval += 4;
1720                         }
1721                 }
1722                 else
1723                 {
1724                         switch ((int)*tok)
1725                         {
1726                         case KW_USP:
1727                         case KW_SSP:
1728                         case KW_PC:
1729                                 eval += 2;
1730                                 // FALLTHROUGH
1731                         case KW_SR:
1732                         case KW_CCR:
1733                                 eval += 2;
1734                                 tok++;
1735                                 break;
1736                         case EOL:
1737                                 return 0;
1738                         default:
1739                                 return error(".cargs syntax");
1740                         }
1741                 }
1742
1743                 // Eat commas in between each argument, if they exist
1744                 if (*tok == ',')
1745                         tok++;
1746         }
1747 }
1748
1749
1750 //
1751 // .cstruct [#offset], symbol[.size], ...
1752 //
1753 // Lists of registers may also be mentioned; they just take up space. Good for
1754 // "documentation" purposes:
1755 //
1756 // .cstruct a6, .arg1, .arg2, .arg3...
1757 //
1758 // Symbols thus created are ABS and EQUATED. Note that this is for
1759 // compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
1760 // the suggestion.
1761 //
1762 int d_cstruct(void)
1763 {
1764         uint64_t eval = 0;      // Default, if no offset specified, is zero
1765         WORD rlist;
1766         SYM * symbol;
1767         char * symbolName;
1768         int env;
1769         int i;
1770
1771         if (rgpu || rdsp)
1772                 return error("directive forbidden in gpu/dsp mode");
1773
1774         if (*tok == '#')
1775         {
1776                 tok++;
1777
1778                 if (abs_expr(&eval) != OK)
1779                         return 0;
1780
1781                 // Eat the comma, if it's there
1782                 if (*tok == ',')
1783                         tok++;
1784         }
1785
1786         for(;;)
1787         {
1788                 if (*tok == SYMBOL)
1789                 {
1790                         symbolName = string[tok[1]];
1791
1792                         // Set env to either local (dot prefixed) or global scope
1793                         env = (symbolName[0] == '.' ? curenv : 0);
1794                         symbol = lookup(symbolName, LABEL, env);
1795
1796                         // If the symbol wasn't found, then define it. Otherwise, throw an
1797                         // error.
1798                         if (symbol == NULL)
1799                         {
1800                                 symbol = NewSymbol(symbolName, LABEL, env);
1801                                 symbol->sattr = 0;
1802                         }
1803                         else if (symbol->sattr & DEFINED)
1804                                 return error("multiply-defined label '%s'", symbolName);
1805
1806                         // Put symbol in "order of definition" list
1807                         AddToSymbolDeclarationList(symbol);
1808
1809                         tok += 2;
1810
1811                         // Adjust label start address if it's a word or a long, as a byte
1812                         // label might have left us on an odd address.
1813                         switch ((int)*tok)
1814                         {
1815                         case DOTW:
1816                         case DOTL:
1817                                 eval += eval & 0x01;
1818                         }
1819
1820                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1821                         symbol->svalue = (uint32_t)eval;
1822
1823                         // Check for dot suffixes and adjust space accordingly (longs and
1824                         // words on an odd boundary get bumped to the next word aligned
1825                         // address). If no suffix, then throw an error.
1826                         switch ((int)*tok)
1827                         {
1828                         case DOTL:
1829                                 eval += 4;
1830                                 break;
1831                         case DOTW:
1832                                 eval += 2;
1833                                 break;
1834                         case DOTB:
1835                                 eval += 1;
1836                                 break;
1837                         default:
1838                                 return error("Symbol missing dot suffix in .cstruct construct");
1839                         }
1840
1841                         tok++;
1842                 }
1843                 else if (*tok >= KW_D0 && *tok <= KW_A7)
1844                 {
1845                         if (reglist(&rlist) < 0)
1846                                 return 0;
1847
1848                         for(i=0; i<16; i++, rlist>>=1)
1849                         {
1850                                 if (rlist & 1)
1851                                         eval += 4;
1852                         }
1853                 }
1854                 else
1855                 {
1856                         switch ((int)*tok)
1857                         {
1858                         case KW_USP:
1859                         case KW_SSP:
1860                         case KW_PC:
1861                                 eval += 2;
1862                                 // FALLTHROUGH
1863                         case KW_SR:
1864                         case KW_CCR:
1865                                 eval += 2;
1866                                 tok++;
1867                                 break;
1868                         case EOL:
1869                                 return 0;
1870                         default:
1871                                 return error(".cstruct syntax");
1872                         }
1873                 }
1874
1875                 // Eat commas in between each argument, if they exist
1876                 if (*tok == ',')
1877                         tok++;
1878         }
1879 }
1880
1881
1882 //
1883 // Undefine a macro - .undefmac macname [, macname...]
1884 //
1885 int undmac1(char * p)
1886 {
1887         SYM * symbol = lookup(p, MACRO, 0);
1888
1889         // If the macro symbol exists, cause it to disappear
1890         if (symbol != NULL)
1891                 symbol->stype = (BYTE)SY_UNDEF;
1892
1893         return OK;
1894 }
1895
1896
1897 int d_undmac(void)
1898 {
1899         symlist(undmac1);
1900         return 0;
1901 }
1902
1903
1904 int d_jpad(void)
1905 {
1906         warn("JPAD directive is deprecated/non-functional");
1907         return OK;
1908 }
1909
1910
1911 int d_nojpad(void)
1912 {
1913         warn("NOJPAD directive is deprecated/non-functional");
1914         return OK;
1915 }
1916
1917
1918 int d_gpumain(void)
1919 {
1920         return error("What the hell? Do you think we adhere to the Goof standard?");
1921 }
1922
1923
1924 //
1925 // .opt - turn a specific (or all) optimisation on or off
1926 //
1927 int d_opt(void)
1928 {
1929         while (*tok != EOL)
1930         {
1931                 if (*tok == STRING)
1932                 {
1933                         tok++;
1934                         char * tmpstr = string[*tok++];
1935
1936                         if (ParseOptimization(tmpstr) != OK)
1937                                 return error("unknown optimization flag '%s'", tmpstr);
1938                 }
1939                 else
1940                         return error(".opt directive needs every switch enclosed inside quotation marks");
1941         }
1942
1943         return OK;
1944 }
1945
1946
1947 //
1948 // .if, Start conditional assembly
1949 //
1950 int d_if(void)
1951 {
1952         WORD eattr;
1953         uint64_t eval;
1954         SYM * esym;
1955         IFENT * rif = f_ifent;
1956
1957         // Alloc an IFENTRY
1958         if (rif == NULL)
1959                 rif = (IFENT *)malloc(sizeof(IFENT));
1960         else
1961                 f_ifent = rif->if_prev;
1962
1963         rif->if_prev = ifent;
1964         ifent = rif;
1965
1966         if (!disabled)
1967         {
1968                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
1969                         return 0;
1970
1971                 if ((eattr & DEFINED) == 0)
1972                         return error(undef_error);
1973
1974                 disabled = !eval;
1975         }
1976
1977         rif->if_state = (WORD)disabled;
1978         return 0;
1979 }
1980
1981
1982 //
1983 // .else, Do alternate case for .if
1984 //
1985 int d_else(void)
1986 {
1987         IFENT * rif = ifent;
1988
1989         if (rif->if_prev == NULL)
1990                 return error("mismatched .else");
1991
1992         if (disabled)
1993                 disabled = rif->if_prev->if_state;
1994         else
1995                 disabled = 1;
1996
1997         rif->if_state = (WORD)disabled;
1998         return 0;
1999 }
2000
2001
2002 //
2003 // .endif, End of conditional assembly block
2004 // This is also called by fpop() to pop levels of IFENTs in case a macro or
2005 // include file exits early with `exitm' or `end'.
2006 //
2007 int d_endif(void)
2008 {
2009         IFENT * rif = ifent;
2010
2011         if (rif->if_prev == NULL)
2012                 return error("mismatched .endif");
2013
2014         ifent = rif->if_prev;
2015         disabled = rif->if_prev->if_state;
2016         rif->if_prev = f_ifent;
2017         f_ifent = rif;
2018         return 0;
2019 }
2020