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