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