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