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