]> Shamusworld >> Repos - rmac/blob - direct.c
Version bump for last commit; now a v2.0.20.;35M;35m
[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-2020 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 | BANK_0 | BANK_1);
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                         }
626                         else
627                                 size = lseek(fd, 0L, SEEK_END);
628                 }
629
630                 // Check offset parameter (can be omitted)
631                 if (*tok != EOL)
632                 {
633                         if (*tok++ == ',')
634                         {
635                                 if (*tok != EOL)
636                                 {
637                                         if (abs_expr(&pos) != OK)
638                                         {
639                                                 close(fd);
640                                                 return ERROR;
641                                         }
642
643                                         lseek(fd, pos, SEEK_SET);
644                                         size -= pos;
645                                 }
646                                 else
647                                 {
648                                         // offset parameter omitted, so it's 0
649                                         pos = lseek(fd, 0L, SEEK_SET);
650                                 }
651                         }
652                         else
653                                 return error(comma_error);
654                 }
655                 else
656                         pos = lseek(fd, 0L, SEEK_SET);
657         }
658         else
659         {
660                 // size & pos not given, so assume offset of 0 and all of the binary
661                 size = lseek(fd, 0L, SEEK_END);
662                 pos = lseek(fd, 0L, SEEK_SET);
663         }
664
665         chcheck(size);
666
667         DEBUG { printf("INCBIN: File '%s' is %li bytes.\n", string[filename], size); }
668
669         char * fileBuffer = (char *)malloc(size);
670         bytesRead = read(fd, fileBuffer, size);
671
672         if (bytesRead != size)
673         {
674                 error("was only able to read %li bytes from binary file (%s, %li bytes)", bytesRead, string[filename], size);
675                 return ERROR;
676         }
677
678         memcpy(chptr, fileBuffer, size);
679         chptr += size;
680         sloc += size;
681         ch_size += size;
682
683         if (orgactive)
684                 orgaddr += size;
685
686         free(fileBuffer);
687         close(fd);
688         return 0;
689 }
690
691
692 //
693 // Set RISC register banks
694 //
695 int d_regbank0(void)
696 {
697         // Set active register bank zero
698         regbank = BANK_0;
699         return 0;
700 }
701
702
703 int d_regbank1(void)
704 {
705         // Set active register bank one
706         regbank = BANK_1;
707         return 0;
708 }
709
710
711 //
712 // Helper function, to cut down on mistakes & typing
713 //
714 static inline void SkipBytes(unsigned bytesToSkip)
715 {
716         if (!bytesToSkip)
717                 return;
718
719         if ((scattr & SBSS) == 0)
720         {
721                 chcheck(bytesToSkip);
722                 D_ZEROFILL(bytesToSkip);
723         }
724         else
725         {
726                 sloc += bytesToSkip;
727
728                 if (orgactive)
729                         orgaddr += bytesToSkip;
730         }
731 }
732
733
734 //
735 // Adjust location to an EVEN value
736 //
737 int d_even(void)
738 {
739         if (m6502)
740                 return error(in_6502mode);
741
742         unsigned skip = (rgpu || rdsp ? orgaddr : sloc) & 0x01;
743
744         if (skip)
745         {
746                 if ((scattr & SBSS) == 0)
747                 {
748                         chcheck(1);
749                         D_byte(0);
750                 }
751                 else
752                 {
753                         sloc++;
754
755                         if (orgactive)
756                                 orgaddr++;
757                 }
758         }
759
760         return 0;
761 }
762
763
764 //
765 // Adjust location to a LONG value
766 //
767 int d_long(void)
768 {
769         unsigned lower2Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x03;
770         unsigned bytesToSkip = (0x04 - lower2Bits) & 0x03;
771         SkipBytes(bytesToSkip);
772         SetLargestAlignment(4);
773
774         return 0;
775 }
776
777
778 //
779 // Adjust location to a PHRASE value
780 //
781 // N.B.: We have to handle the GPU/DSP cases separately because you can embed
782 //       RISC code in the middle of a regular 68K section. Also note that all
783 //       of the alignment pseudo-ops will have to be fixed this way.
784 //
785 // This *must* behave differently when in a RISC section, as following sloc
786 // (instead of orgaddr) will fuck things up royally. Note that we do it this
787 // way because you can embed RISC code in a 68K section, and have the origin
788 // pointing to a different alignment in the RISC section than the 68K section.
789 //
790 int d_phrase(void)
791 {
792         unsigned lower3Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x07;
793         unsigned bytesToSkip = (0x08 - lower3Bits) & 0x07;
794         SkipBytes(bytesToSkip);
795         SetLargestAlignment(8);
796
797         return 0;
798 }
799
800
801 //
802 // Adjust location to a DPHRASE value
803 //
804 int d_dphrase(void)
805 {
806         unsigned lower4Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x0F;
807         unsigned bytesToSkip = (0x10 - lower4Bits) & 0x0F;
808         SkipBytes(bytesToSkip);
809         SetLargestAlignment(16);
810
811         return 0;
812 }
813
814
815 //
816 // Adjust location to a QPHRASE value
817 //
818 int d_qphrase(void)
819 {
820         unsigned lower5Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x1F;
821         unsigned bytesToSkip = (0x20 - lower5Bits) & 0x1F;
822         SkipBytes(bytesToSkip);
823         SetLargestAlignment(32);
824
825         return 0;
826 }
827
828
829 //
830 // Do auto-even.  This must be called ONLY if 'sloc' is odd.
831 //
832 // This is made hairy because, if there was a label on the line, we also have
833 // to adjust its value. This won't work with more than one label on the line,
834 // which is OK since multiple labels are only allowed in AS68 kludge mode, and
835 // the C compiler is VERY paranoid and uses ".even" whenever it can
836 //
837 // N.B.: This probably needs the same fixes as above...
838 //
839 void auto_even(void)
840 {
841         if (cursect != M6502)
842         {
843                 if (scattr & SBSS)
844                         sloc++;                         // Bump BSS section
845                 else
846                         D_byte(0);                      // Deposit 0.b in non-BSS
847
848                 if (lab_sym != NULL)    // Bump label if we have to
849                         lab_sym->svalue++;
850         }
851 }
852
853
854 //
855 // Unimplemened directive error
856 //
857 int d_unimpl(void)
858 {
859         return error("unimplemented directive");
860 }
861
862
863 //
864 // Return absolute (not TDB) and defined expression or return an error
865 //
866 int abs_expr(uint64_t * a_eval)
867 {
868         WORD eattr;
869
870         if (expr(exprbuf, a_eval, &eattr, NULL) < 0)
871                 return ERROR;
872
873         if (!(eattr & DEFINED))
874                 return error(undef_error);
875
876         if (eattr & TDB)
877                 return error(rel_error);
878
879         return OK;
880 }
881
882
883 //
884 // Hand symbols in a symbol-list to a function (kind of like mapcar...)
885 //
886 int symlist(int(* func)())
887 {
888         const char * em = "symbol list syntax";
889
890         for(;;)
891         {
892                 if (*tok != SYMBOL)
893                         return error(em);
894
895                 if ((*func)(string[tok[1]]) != OK)
896                         break;
897
898                 tok += 2;
899
900                 if (*tok == EOL)
901                         break;
902
903                 if (*tok != ',')
904                         return error(em);
905
906                 tok++;
907         }
908
909         return 0;
910 }
911
912
913 //
914 // .include "filename"
915 //
916 int d_include(void)
917 {
918         int j;
919         int i;
920         char * fn;
921         char buf[128];
922         char buf1[128];
923
924         if (*tok == STRING)                     // Leave strings ALONE
925                 fn = string[*++tok];
926         else if (*tok == SYMBOL)        // Try to append ".s" to symbols
927         {
928                 strcpy(buf, string[*++tok]);
929                 fext(buf, ".s", 0);
930                 fn = &buf[0];
931         }
932         else                                            // Punt if no STRING or SYMBOL
933                 return error("missing filename");
934
935         // Make sure the user didn't try anything like:
936         // .include equates.s
937         if (*++tok != EOL)
938                 return error("extra stuff after filename--enclose it in quotes");
939
940         // Attempt to open the include file in the current directory, then (if that
941         // failed) try list of include files passed in the enviroment string or by
942         // the "-i" option.
943         if ((j = open(fn, 0)) < 0)
944         {
945                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
946                 {
947                         j = strlen(buf1);
948
949                         // Append path char if necessary
950                         if (j > 0 && buf1[j - 1] != SLASHCHAR)
951                                 strcat(buf1, SLASHSTRING);
952
953                         strcat(buf1, fn);
954
955                         if ((j = open(buf1, 0)) >= 0)
956                                 goto allright;
957                 }
958
959                 return error("cannot open: \"%s\"", fn);
960         }
961
962 allright:
963         include(j, fn);
964         return 0;
965 }
966
967
968 //
969 // .assert expression [, expression...]
970 //
971 int d_assert(void)
972 {
973         WORD eattr;
974         uint64_t eval;
975
976         for(; expr(exprbuf, &eval, &eattr, NULL)==OK; ++tok)
977         {
978                 if (!(eattr & DEFINED))
979                         return error("forward or undefined .assert");
980
981                 if (!eval)
982                         return error("assert failure");
983
984                 if (*tok != ',')
985                         break;
986         }
987
988         ErrorIfNotAtEOL();
989         return 0;
990 }
991
992
993 //
994 // .globl symbol [, symbol] <<<cannot make local symbols global>>>
995 //
996 int globl1(char * p)
997 {
998         SYM * sy;
999
1000         if (*p == '.')
1001                 return error("cannot .globl local symbol");
1002
1003         if ((sy = lookup(p, LABEL, 0)) == NULL)
1004         {
1005                 sy = NewSymbol(p, LABEL, 0);
1006                 sy->svalue = 0;
1007                 sy->sattr = GLOBAL;
1008 //printf("glob1: Making global symbol: attr=%04X, eattr=%08X, %s\n", sy->sattr, sy->sattre, sy->sname);
1009         }
1010         else
1011                 sy->sattr |= GLOBAL;
1012
1013         return OK;
1014 }
1015
1016
1017 int d_globl(void)
1018 {
1019         if (m6502)
1020                 return error(in_6502mode);
1021
1022         symlist(globl1);
1023         return 0;
1024 }
1025
1026
1027 //
1028 // .prgflags expression
1029 //
1030 int d_prgflags(void)
1031 {
1032         uint64_t eval;
1033
1034         if (*tok == EOL)
1035                 return error("PRGFLAGS requires value");
1036         else if (abs_expr(&eval) == OK)
1037         {
1038                 PRGFLAGS = (uint32_t)eval;
1039                 return 0;
1040         }
1041         else
1042         {
1043                 return error("PRGFLAGS requires value");
1044         }
1045 }
1046
1047
1048 //
1049 // .abs [expression]
1050 //
1051 int d_abs(void)
1052 {
1053         uint64_t eval;
1054
1055         if (m6502)
1056                 return error(in_6502mode);
1057
1058         SaveSection();
1059
1060         if (*tok == EOL)
1061                 eval = 0;
1062         else if (abs_expr(&eval) != OK)
1063                 return 0;
1064
1065         SwitchSection(ABS);
1066         sloc = (uint32_t)eval;
1067         return 0;
1068 }
1069
1070
1071 //
1072 // Switch segments
1073 //
1074 int d_text(void)
1075 {
1076         if (rgpu || rdsp)
1077                 return error("directive forbidden in gpu/dsp mode");
1078         else if (m6502)
1079                 return error(in_6502mode);
1080
1081         if (cursect != TEXT)
1082         {
1083                 SaveSection();
1084                 SwitchSection(TEXT);
1085         }
1086
1087         return 0;
1088 }
1089
1090
1091 int d_data(void)
1092 {
1093         if (rgpu || rdsp)
1094                 return error("directive forbidden in gpu/dsp mode");
1095         else if (m6502)
1096                 return error(in_6502mode);
1097
1098         if (cursect != DATA)
1099         {
1100                 SaveSection();
1101                 SwitchSection(DATA);
1102         }
1103
1104         return 0;
1105 }
1106
1107
1108 int d_bss(void)
1109 {
1110         if (rgpu || rdsp)
1111                 return error("directive forbidden in gpu/dsp mode");
1112         else if (m6502)
1113                 return error(in_6502mode);
1114
1115         if (cursect != BSS)
1116         {
1117                 SaveSection();
1118                 SwitchSection(BSS);
1119         }
1120
1121         return 0;
1122 }
1123
1124
1125 //
1126 // .ds[.size] expression
1127 //
1128 int d_ds(WORD siz)
1129 {
1130         DEBUG { printf("Directive: .ds.[size] = %u, sloc = $%X\n", siz, sloc); }
1131
1132         uint64_t eval;
1133
1134         if ((cursect & (M6502 | M56KPXYL)) == 0)
1135         {
1136                 if ((siz != SIZB) && (sloc & 1))        // Automatic .even
1137                         auto_even();
1138         }
1139
1140         if (abs_expr(&eval) != OK)
1141                 return 0;
1142
1143         // Check to see if the value being passed in is negative (who the hell does
1144         // that?--nobody does; it's the code gremlins, or rum, what does it)
1145         // N.B.: Since 'eval' is of type uint64_t, if it goes negative, it will
1146         //       have its high bit set.
1147         if (eval & 0x8000000000000000)
1148                 return error("negative sizes not allowed in DS");
1149
1150         // In non-TDB section (BSS, ABS and M6502) just advance the location
1151         // counter appropriately. In TDB sections, deposit (possibly large) chunks
1152         // of zeroed memory....
1153         if ((scattr & SBSS) || cursect == M6502)
1154         {
1155                 listvalue((uint32_t)eval);
1156                 eval *= siz;
1157                 sloc += (uint32_t)eval;
1158
1159                 if (cursect == M6502)
1160                         chptr += eval;
1161
1162                 just_bss = 1;                                   // No data deposited (8-bit CPU mode)
1163         }
1164         else if (cursect & M56KPXYL)
1165         {
1166                 // Change segment instead of marking blanks.
1167                 // Only mark segments we actually wrote something
1168                 if (chptr != dsp_currentorg->start && dsp_written_data_in_current_org)
1169                 {
1170                         dsp_currentorg->end = chptr;
1171                         dsp_currentorg++;
1172                         dsp_currentorg->memtype = dsp_currentorg[-1].memtype;
1173                 }
1174
1175                 listvalue((uint32_t)eval);
1176                 sloc += (uint32_t)eval;
1177
1178                 // And now let's create a new segment
1179                 dsp_currentorg->start = chptr;
1180                 dsp_currentorg->chunk = scode;  // Mark down which chunk this org starts from (will be needed when outputting)
1181                 sect[cursect].orgaddr = sloc;
1182                 dsp_currentorg->orgadr = sloc;
1183                 dsp_written_data_in_current_org = 0;
1184
1185                 just_bss = 1;                                   // No data deposited
1186         }
1187         else
1188         {
1189                 dep_block(eval, siz, 0, (DEFINED | ABS), NULL);
1190         }
1191
1192         ErrorIfNotAtEOL();
1193         return OK;
1194 }
1195
1196
1197 //
1198 // dsm[.siz] expression
1199 // Define modulo storage
1200 // Quoting the Motorola assembler manual:
1201 // "The DSM directive reserves a block of memory the length of which in words is equal to
1202 // the value of <expression>.If the runtime location counter is not zero, this directive first
1203 // advances the runtime location counter to a base address that is a multiple of 2k, where
1204 // 2k >= <expression>."
1205 // The kicker of course is written a few sentences after:
1206 // "<label>, if present, will be assigned the value of the runtime location counter after a valid
1207 // base address has been established."
1208 //
1209 int d_dsm(WORD siz)
1210 {
1211         TOKEN * tok_current = tok;  // Keep track of where tok was when we entered this procedure
1212         uint64_t eval;
1213
1214         if (abs_expr(&eval) != OK)
1215                 return 0;
1216
1217         // Round up to the next highest power of 2
1218         // Nicked from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
1219         eval--;
1220         eval |= eval >> 1;
1221         eval |= eval >> 2;
1222         eval |= eval >> 4;
1223         eval |= eval >> 8;
1224         eval |= eval >> 16;
1225
1226         int units_to_skip;
1227         units_to_skip = eval + 1 - sloc;
1228         sloc += units_to_skip;          // Bump up sloc - TODO: check if this goes over the RAM limits?
1229
1230         // If a label has been defined in the same line as dsm, its value also needs to be adjusted
1231         if (label_defined)
1232         {
1233                 SYM * label = lookup(label_defined, LABEL, 0);
1234                 label->svalue += units_to_skip;
1235         }
1236
1237         tok = tok_current;              // Rewind tok back to where it was
1238         return d_ds(siz);               // And let d_ds take over from here
1239 }
1240
1241
1242 //
1243 // dc.b, dc.w / dc, dc.l, dc.i, dc.q, dc.d, dc.s, dc.x
1244 //
1245 int d_dc(WORD siz)
1246 {
1247         WORD eattr;
1248         uint64_t eval;
1249         uint8_t * p;
1250
1251         if ((scattr & SBSS) != 0)
1252                 return error("illegal initialization of section");
1253
1254         // Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
1255         if ((cursect != M6502) && (cursect != M56001P) && (cursect != M56001X)
1256                 && (cursect != M56001Y) && (cursect != M56001L)
1257                 && (siz != SIZB) && (sloc & 1))
1258                 auto_even();
1259
1260         // Check to see if we're trying to set LONGS on a non 32-bit aligned
1261         // address in a GPU or DSP section, in their local RAM
1262         if ((siz == SIZL) && (orgaddr & 0x03)
1263                 && ((rgpu && (orgaddr >= 0xF03000) && (orgaddr <= 0xF03FFFF))
1264                 || (rdsp && (orgaddr >= 0xF1B000) && (orgaddr <= 0xF1CFFFF))))
1265                 warn("depositing LONGs on a non-long address in local RAM");
1266
1267         for(;; tok++)
1268         {
1269                 // dc.b 'string' [,] ...
1270                 if (siz == SIZB && (*tok == STRING || *tok == STRINGA8) && (tok[2] == ',' || tok[2] == EOL))
1271                 {
1272                         uint32_t i = strlen(string[tok[1]]);
1273
1274                         if ((challoc - ch_size) < i)
1275                                 chcheck(i);
1276
1277                         if (*tok == STRING)
1278                         {
1279                                 for(p=string[tok[1]]; *p!=EOS; p++)
1280                                         D_byte(*p);
1281                         }
1282                         else if (*tok == STRINGA8)
1283                         {
1284                                 for(p=string[tok[1]]; *p!=EOS; p++)
1285                                         D_byte(strtoa8[*p]);
1286                         }
1287                         else
1288                         {
1289                                 error("String format not supported... yet");
1290                         }
1291
1292                         tok += 2;
1293                         goto comma;
1294                 }
1295
1296                 int movei = 0; // MOVEI flag for dc.i
1297
1298                 if (*tok == DOTI)
1299                 {
1300                         movei = 1;
1301                         tok++;
1302                         siz = SIZL;
1303                 }
1304
1305                 // dc.x <expression>
1306                 SYM * esym = 0;
1307
1308                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
1309                         return 0;
1310
1311                 uint16_t tdb = eattr & TDB;
1312                 uint16_t defined = eattr & DEFINED;
1313
1314 // 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 !!!
1315                 if (dsp56001)
1316                 {
1317                         if (cursect != M56001L)
1318                         {
1319                                 if (!defined)
1320                                 {
1321                                         AddFixup(FU_DSPIMM24 | FU_SEXT, sloc, exprbuf);
1322                                         D_dsp(0);
1323                                 }
1324                                 else
1325                                 {
1326                                         if (eattr & FLOAT)
1327                                         {
1328                                                 double fval = *(double *)&eval;
1329                                                 eval = DoubleToDSPFloat(fval);
1330                                         }
1331                                         else
1332                                         {
1333                                                 if ((uint32_t)eval + 0x1000000 >= 0x2000000)
1334                                                         return error(range_error);
1335                                         }
1336
1337                                         // Deposit DSP word (24-bit)
1338                                         D_dsp(eval);
1339                                 }
1340                         }
1341                         else
1342                         {
1343                                 // In L: we deposit stuff to both X: and Y: instead
1344                                 // We will be a bit lazy and require that there is a 2nd value
1345                                 // in the same source line. (Motorola's assembler can parse
1346                                 // 12-digit hex values, which we can't do at the moment) This
1347                                 // of course requires to parse 2 values in one pass. If there
1348                                 // isn't another value in this line, assume X: value is 0.
1349                                 int secondword = 0;
1350                                 uint32_t evaly;
1351 l_parse_loop:
1352
1353                                 if (!defined)
1354                                 {
1355                                         AddFixup(FU_DSPIMM24 | FU_SEXT, sloc, exprbuf);
1356                                         D_dsp(0);
1357                                 }
1358                                 else
1359                                 {
1360                                         if (eattr & FLOAT)
1361                                         {
1362                                                 float fval = *(float *)&eval;
1363                                                 eval = DoubleToDSPFloat(fval);
1364                                         }
1365                                         else
1366                                         {
1367                                                 if (eval + 0x1000000 >= 0x2000000)
1368                                                         return error(range_error);
1369                                         }
1370
1371                                         // Parse 2nd value if we didn't do this yet
1372                                         if (secondword == 0)
1373                                         {
1374                                                 evaly = (uint32_t)eval;
1375                                                 secondword = 1;
1376
1377                                                 if (*tok != ':')
1378                                                 {
1379                                                         // If we don't have a : then we're probably at EOL,
1380                                                         // which means the X: value will be 0
1381                                                         eval = 0;
1382                                                         ErrorIfNotAtEOL();
1383                                                 }
1384                                                 else
1385                                                 {
1386                                                         tok++; // Eat the comma;
1387
1388                                                         if (expr(exprbuf, &eval, &eattr, NULL) != OK)
1389                                                                 return 0;
1390
1391                                                         defined = (WORD)(eattr & DEFINED);
1392                                                         goto l_parse_loop;
1393                                                 }
1394                                         }
1395
1396                                         // Deposit DSP words (24-bit)
1397                                         D_dsp(eval);
1398                                         D_dsp(evaly);
1399                                         sloc--; // We do write 2 DSP words but as far as L: space is concerned we actually advance our counter by one
1400                                 }
1401
1402                         }
1403
1404                         goto comma;
1405                 }
1406
1407                 switch (siz)
1408                 {
1409                 case SIZB:
1410                         if (!defined)
1411                         {
1412                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1413                                 D_byte(0);
1414                         }
1415                         else
1416                         {
1417                                 if (tdb)
1418                                         return error("non-absolute byte value");
1419
1420                                 if (eval + 0x100 >= 0x200)
1421                                         return error("%s (value = $%X)", range_error, eval);
1422
1423                                 D_byte(eval);
1424                         }
1425
1426                         break;
1427
1428                 case SIZW:
1429                 case SIZN:
1430                         if (!defined)
1431                         {
1432                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1433                                 D_word(0);
1434                         }
1435                         else
1436                         {
1437                                 if (eval + 0x10000 >= 0x20000)
1438                                         return error(range_error);
1439
1440                                 if (tdb)
1441                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1442
1443                                 // Deposit 68000 or 6502 (byte-reversed) word
1444                                 if (cursect != M6502)
1445                                         D_word(eval)
1446                                 else
1447                                         D_rword(eval)
1448                         }
1449
1450                         break;
1451
1452                 case SIZL:
1453                         // Shamus: Why can't we do longs in 6502 mode?
1454                         if (m6502)
1455                                 return error(in_6502mode);
1456
1457                         if (!defined)
1458                         {
1459                                 AddFixup(FU_LONG | (movei ? FU_MOVEI : 0), sloc, exprbuf);
1460                                 D_long(0);
1461                         }
1462                         else
1463                         {
1464                                 if (tdb)
1465                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1466
1467                                 if (movei)
1468                                         eval = WORDSWAP32(eval);
1469
1470                                 D_long(eval);
1471                         }
1472
1473                         break;
1474
1475                 case SIZQ:
1476                         // 64-bit size
1477                         if (m6502)
1478                                 return error(in_6502mode);
1479
1480                         // DEFINITELY NEED FIXUPS HERE!
1481                         if (!defined)
1482                         {
1483                                 AddFixup(FU_QUAD, sloc, exprbuf);
1484                                 eval = 0;
1485                         }
1486
1487                         D_quad(eval);
1488                         break;
1489
1490                 case SIZS:
1491                         // 32-bit float size
1492                         if (m6502)
1493                                 return error(in_6502mode);
1494
1495 /* Seems to me that if something is undefined here, then that should be an error.  Likewise for the D & X variants. */
1496                         if (!defined)
1497                         {
1498 //                              AddFixup(FU_FLOATSING, sloc, exprbuf);
1499 //                              D_long(0);
1500                                 return error("labels not allowed in floating point expressions");
1501                         }
1502                         else
1503                         {
1504 //Would this *ever* happen?
1505 //                              if (tdb)
1506 //                                      MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
1507
1508                                 PTR ptr;
1509                                 ptr.u64 = &eval;
1510                                 uint32_t ieee754 = FloatToIEEE754((float)*ptr.dp);
1511                                 D_long(ieee754);
1512                         }
1513
1514                         break;
1515
1516                 case SIZD:
1517                         // 64-bit double size
1518                         if (m6502)
1519                                 return error(in_6502mode);
1520
1521                         if (!defined)
1522                         {
1523 //                              AddFixup(FU_FLOATDOUB, sloc, exprbuf);
1524 //                              D_quad(0LL);
1525                                 return error("labels not allowed in floating point expressions");
1526                         }
1527                         else
1528                         {
1529 //Would this *ever* happen?
1530 //                              if (tdb)
1531 //                                      MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
1532
1533                                 PTR ptr;
1534                                 ptr.u64 = &eval;
1535                                 uint64_t ieee754 = DoubleToIEEE754(*ptr.dp);
1536                                 D_quad(ieee754);
1537                         }
1538
1539                         break;
1540
1541                 case SIZX:
1542                         if (m6502)
1543                                 return error(in_6502mode);
1544
1545                         uint8_t extDbl[12];
1546                         memset(extDbl, 0, 12);
1547
1548                         if (!defined)
1549                         {
1550 //                              AddFixup(FU_FLOATEXT, sloc, exprbuf);
1551 //                              D_extend(extDbl);
1552                                 return error("labels not allowed in floating point expressions");
1553                         }
1554                         else
1555                         {
1556 //Would this *ever* happen?
1557 //                              if (tdb)
1558 //                                      MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
1559
1560                                 PTR ptr;
1561                                 ptr.u64 = &eval;
1562                                 DoubleToExtended(*ptr.dp, extDbl);
1563                                 D_extend(extDbl);
1564                         }
1565
1566                         break;
1567                 }
1568
1569 comma:
1570                 if (*tok != ',')
1571                         break;
1572         }
1573
1574         ErrorIfNotAtEOL();
1575         return 0;
1576 }
1577
1578
1579 //
1580 // dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2'
1581 //
1582 int d_dcb(WORD siz)
1583 {
1584         uint64_t evalc, eval;
1585         WORD eattr;
1586
1587         DEBUG { printf("dcb: section is %s%s%s (scattr=$%X)\n", (cursect & TEXT ? "TEXT" : ""), (cursect & DATA ? " DATA" : ""), (cursect & BSS ? "BSS" : ""), scattr); }
1588
1589         if ((scattr & SBSS) != 0)
1590                 return error("illegal initialization of section");
1591
1592         if (abs_expr(&evalc) != OK)
1593                 return 0;
1594
1595         if (*tok++ != ',')
1596                 return error("missing comma");
1597
1598         if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1599                 return 0;
1600
1601         if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
1602                 auto_even();
1603
1604         dep_block((uint32_t)evalc, siz, (uint32_t)eval, eattr, exprbuf);
1605         return 0;
1606 }
1607
1608
1609 //
1610 // Generalized initialization directive
1611 //
1612 // .init[.siz] [#count,] expression [.size] , ...
1613 //
1614 // The size suffix on the ".init" directive becomes the default size of the
1615 // objects to deposit. If an item is preceeded with a sharp (immediate) sign
1616 // and an expression, it specifies a repeat count. The value to be deposited
1617 // may be followed by a size suffix, which overrides the default size.
1618 //
1619 int d_init(WORD def_siz)
1620 {
1621         uint64_t count;
1622         uint64_t eval;
1623         WORD eattr;
1624         WORD siz;
1625
1626         if ((scattr & SBSS) != 0)
1627                 return error(".init not permitted in BSS or ABS");
1628
1629         if (rgpu || rdsp)
1630                 return error("directive forbidden in gpu/dsp mode");
1631
1632         for(;;)
1633         {
1634                 // Get repeat count (defaults to 1)
1635                 if (*tok == '#')
1636                 {
1637                         tok++;
1638
1639                         if (abs_expr(&count) != OK)
1640                                 return 0;
1641
1642                         if (*tok++ != ',')
1643                                 return error(comma_error);
1644                 }
1645                 else
1646                         count = 1;
1647
1648                 // Evaluate expression to deposit
1649                 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1650                         return 0;
1651
1652                 switch (*tok++)
1653                 {                                 // Determine size of object to deposit
1654                 case DOTB: siz = SIZB; break;
1655                 case DOTW: siz = SIZB; break;
1656                 case DOTL: siz = SIZL; break;
1657                 default:
1658                         siz = def_siz;
1659                         tok--;
1660                         break;
1661                 }
1662
1663                 dep_block((uint32_t)count, siz, (uint32_t)eval, eattr, exprbuf);
1664
1665                 switch (*tok)
1666                 {
1667                 case EOL:
1668                         return 0;
1669                 case ',':
1670                         tok++;
1671                         continue;
1672                 default:
1673                         return error(comma_error);
1674                 }
1675         }
1676 }
1677
1678
1679 //
1680 // Deposit 'count' values of size 'siz' in the current (non-BSS) segment
1681 //
1682 int dep_block(uint32_t count, WORD siz, uint32_t eval, WORD eattr, TOKEN * exprbuf)
1683 {
1684         WORD tdb = eattr & TDB;
1685         WORD defined = eattr & DEFINED;
1686
1687         while (count--)
1688         {
1689                 if ((challoc - ch_size) < 4)
1690                         chcheck(4L);
1691
1692                 switch(siz)
1693                 {
1694                 case SIZB:
1695                         if (!defined)
1696                         {
1697                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1698                                 D_byte(0);
1699                         }
1700                         else
1701                         {
1702                                 if (tdb)
1703                                         return error("non-absolute byte value");
1704
1705                                 if (eval + 0x100 >= 0x200)
1706                                         return error(range_error);
1707
1708                                 D_byte(eval);
1709                         }
1710
1711                         break;
1712                 case SIZW:
1713                 case SIZN:
1714                         if (!defined)
1715                         {
1716                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1717                                 D_word(0);
1718                         }
1719                         else
1720                         {
1721                                 if (tdb)
1722                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1723
1724                                 if (eval + 0x10000 >= 0x20000)
1725                                         return error(range_error);
1726
1727                                 // Deposit 68000 or 6502 (byte-reversed) word
1728                                 if (cursect != M6502)
1729                                         D_word(eval)
1730                                 else
1731                                         D_rword(eval)
1732
1733                         }
1734
1735                         break;
1736                 case SIZL:
1737                         if (m6502)
1738                                 return error(in_6502mode);
1739
1740                         if (!defined)
1741                         {
1742                                 AddFixup(FU_LONG, sloc, exprbuf);
1743                                 D_long(0);
1744                         }
1745                         else
1746                         {
1747                                 if (tdb)
1748                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1749
1750                                 D_long(eval);
1751                         }
1752
1753                         break;
1754                 }
1755         }
1756
1757         return 0;
1758 }
1759
1760
1761 //
1762 // .comm symbol, size
1763 //
1764 int d_comm(void)
1765 {
1766         SYM * sym;
1767         char * p;
1768         uint64_t eval;
1769
1770         if (m6502)
1771                 return error(in_6502mode);
1772
1773         if (*tok != SYMBOL)
1774                 return error("missing symbol");
1775
1776         p = string[tok[1]];
1777         tok += 2;
1778
1779         if (*p == '.')                                          // Cannot .comm a local symbol
1780                 return error(locgl_error);
1781
1782         if ((sym = lookup(p, LABEL, 0)) == NULL)
1783                 sym = NewSymbol(p, LABEL, 0);
1784         else
1785         {
1786                 if (sym->sattr & DEFINED)
1787                         return error(".comm symbol already defined");
1788         }
1789
1790         sym->sattr = GLOBAL | COMMON | BSS;
1791
1792         if (*tok++ != ',')
1793                 return error(comma_error);
1794
1795         if (abs_expr(&eval) != OK)                      // Parse size of common region
1796                 return 0;
1797
1798         sym->svalue = eval;                                     // Install common symbol's size
1799         ErrorIfNotAtEOL();
1800         return 0;
1801 }
1802
1803
1804 //
1805 // .list - Turn listing on
1806 //
1807 int d_list(void)
1808 {
1809         if (list_flag)
1810                 listing++;
1811
1812         return 0;
1813 }
1814
1815
1816 //
1817 // .nlist - Turn listing off
1818 //
1819 int d_nlist(void)
1820 {
1821         if (list_flag)
1822                 listing--;
1823
1824         return 0;
1825 }
1826
1827
1828 //
1829 // .68000 - Back to 68000 TEXT segment
1830 //
1831 int d_68000(void)
1832 {
1833         rgpu = rdsp = robjproc = dsp56001 = 0;
1834         // Switching from gpu/dsp sections should reset any ORG'd Address
1835         orgactive = 0;
1836         orgwarning = 0;
1837         SaveSection();
1838         SwitchSection(TEXT);
1839         activecpu = CPU_68000;
1840         return 0;
1841 }
1842
1843
1844 //
1845 // .68020 - Back to 68000 TEXT segment and select 68020
1846 //
1847 int d_68020(void)
1848 {
1849         d_68000();
1850         activecpu = CPU_68020;
1851         return 0;
1852 }
1853
1854
1855 //
1856 // .68030 - Back to 68000 TEXT segment and select 68030
1857 //
1858 int d_68030(void)
1859 {
1860         d_68000();
1861         activecpu = CPU_68030;
1862         return 0;
1863 }
1864
1865
1866 //
1867 // .68040 - Back to 68000 TEXT segment and select 68040
1868 //
1869 int d_68040(void)
1870 {
1871         d_68000();
1872         activecpu = CPU_68040;
1873         activefpu = FPU_68040;
1874         return 0;
1875 }
1876
1877
1878 //
1879 // .68060 - Back to 68000 TEXT segment and select 68060
1880 //
1881 int d_68060(void)
1882 {
1883         d_68000();
1884         activecpu = CPU_68060;
1885         activefpu = FPU_68060;
1886         return 0;
1887 }
1888
1889
1890 //
1891 // .68881 - Back to 680x0 TEXT segment and select 68881 FPU
1892 //
1893 int d_68881(void)
1894 {
1895         //d_68000();
1896         activefpu = FPU_68881;
1897         return 0;
1898 }
1899
1900
1901 //
1902 // .68882 - Back to 680x0 TEXT segment and select 68882 FPU
1903 //
1904 int d_68882(void)
1905 {
1906         //d_68000();
1907         activefpu = FPU_68882;
1908         return 0;
1909 }
1910
1911
1912 //
1913 // nofpu - Deselect FPUs.
1914 //
1915 int d_nofpu(void)
1916 {
1917         activefpu = FPU_NONE;
1918         return 0;
1919 }
1920
1921
1922 //
1923 // .56001 - Switch to DSP56001 assembler
1924 //
1925 int d_56001(void)
1926 {
1927         dsp56001 = 1;
1928         rgpu = rdsp = robjproc = 0;
1929         SaveSection();
1930
1931         if ((obj_format == LOD) || (obj_format == P56))
1932                 SwitchSection(M56001P);
1933
1934         return 0;
1935 }
1936
1937
1938 //
1939 // .gpu - Switch to GPU assembler
1940 //
1941 int d_gpu(void)
1942 {
1943         if ((cursect != TEXT) && (cursect != DATA))
1944         {
1945                 error(".gpu can only be used in the TEXT or DATA segments");
1946                 return ERROR;
1947         }
1948
1949         // If previous section was DSP or 68000 then we need to reset ORG'd Addresses
1950         if (!rgpu)
1951         {
1952                 orgactive = 0;
1953                 orgwarning = 0;
1954         }
1955
1956         rgpu = 1;                       // Set GPU assembly
1957         rdsp = 0;                       // Unset DSP assembly
1958         robjproc = 0;           // Unset OP assembly
1959         dsp56001 = 0;           // Unset 56001 assembly
1960         regbank = BANK_N;       // Set no default register bank
1961         return 0;
1962 }
1963
1964
1965 //
1966 // .dsp - Switch to DSP assembler
1967 //
1968 int d_dsp(void)
1969 {
1970         if ((cursect != TEXT) && (cursect != DATA))
1971         {
1972                 error(".dsp can only be used in the TEXT or DATA segments");
1973                 return ERROR;
1974         }
1975
1976         // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
1977         if (!rdsp)
1978         {
1979                 orgactive = 0;
1980                 orgwarning = 0;
1981         }
1982
1983         rdsp = 1;                       // Set DSP assembly
1984         rgpu = 0;                       // Unset GPU assembly
1985         robjproc = 0;           // Unset OP assembly
1986         dsp56001 = 0;           // Unset 56001 assembly
1987         regbank = BANK_N;       // Set no default register bank
1988         return 0;
1989 }
1990
1991
1992 //
1993 // .cargs [#offset], symbol[.size], ...
1994 //
1995 // Lists of registers may also be mentioned; they just take up space. Good for
1996 // "documentation" purposes:
1997 //
1998 // .cargs a6, .arg1, .arg2, .arg3...
1999 //
2000 // Symbols thus created are ABS and EQUATED.
2001 //
2002 int d_cargs(void)
2003 {
2004         uint64_t eval = 4;      // Default to 4 if no offset specified (to account for
2005                                                 // return address)
2006         WORD rlist;
2007         SYM * symbol;
2008         char * p;
2009         int env;
2010         int i;
2011
2012         if (rgpu || rdsp)
2013                 return error("directive forbidden in gpu/dsp mode");
2014
2015         if (*tok == '#')
2016         {
2017                 tok++;
2018
2019                 if (abs_expr(&eval) != OK)
2020                         return 0;
2021
2022                 // Eat the comma, if it's there
2023                 if (*tok == ',')
2024                         tok++;
2025         }
2026
2027         for(;;)
2028         {
2029                 if (*tok == SYMBOL)
2030                 {
2031                         p = string[tok[1]];
2032
2033                         // Set env to either local (dot prefixed) or global scope
2034                         env = (*p == '.' ? curenv : 0);
2035                         symbol = lookup(p, LABEL, env);
2036
2037                         if (symbol == NULL)
2038                         {
2039                                 symbol = NewSymbol(p, LABEL, env);
2040                                 symbol->sattr = 0;
2041                         }
2042                         else if (symbol->sattr & DEFINED)
2043                                 return error("multiply-defined label '%s'", p);
2044
2045                         // Put symbol in "order of definition" list
2046                         AddToSymbolDeclarationList(symbol);
2047
2048                         symbol->sattr |= (ABS | DEFINED | EQUATED);
2049                         symbol->svalue = eval;
2050                         tok += 2;
2051
2052                         // What this does is eat any dot suffixes attached to a symbol. If
2053                         // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
2054                         // there is no dot suffix, it assumes a size of 2.
2055                         switch ((int)*tok)
2056                         {
2057                         case DOTL:
2058                                 eval += 2;
2059                         case DOTB:
2060                         case DOTW:
2061                                 tok++;
2062                         }
2063
2064                         eval += 2;
2065                 }
2066                 else if (*tok >= KW_D0 && *tok <= KW_A7)
2067                 {
2068                         if (reglist(&rlist) < 0)
2069                                 return 0;
2070
2071                         for(i=0; i<16; i++, rlist>>=1)
2072                         {
2073                                 if (rlist & 1)
2074                                         eval += 4;
2075                         }
2076                 }
2077                 else
2078                 {
2079                         switch ((int)*tok)
2080                         {
2081                         case KW_USP:
2082                         case KW_SSP:
2083                         case KW_PC:
2084                                 eval += 2;
2085                                 // FALLTHROUGH
2086                         case KW_SR:
2087                         case KW_CCR:
2088                                 eval += 2;
2089                                 tok++;
2090                                 break;
2091                         case EOL:
2092                                 return 0;
2093                         default:
2094                                 return error(".cargs syntax");
2095                         }
2096                 }
2097
2098                 // Eat commas in between each argument, if they exist
2099                 if (*tok == ',')
2100                         tok++;
2101         }
2102 }
2103
2104
2105 //
2106 // .cstruct [#offset], symbol[.size], ...
2107 //
2108 // Lists of registers may also be mentioned; they just take up space. Good for
2109 // "documentation" purposes:
2110 //
2111 // .cstruct a6, .arg1, .arg2, .arg3...
2112 //
2113 // Symbols thus created are ABS and EQUATED. Note that this is for
2114 // compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
2115 // the suggestion.
2116 //
2117 int d_cstruct(void)
2118 {
2119         uint64_t eval = 0;      // Default, if no offset specified, is zero
2120         WORD rlist;
2121         SYM * symbol;
2122         char * symbolName;
2123         int env;
2124         int i;
2125
2126         if (rgpu || rdsp)
2127                 return error("directive forbidden in gpu/dsp mode");
2128
2129         if (*tok == '#')
2130         {
2131                 tok++;
2132
2133                 if (abs_expr(&eval) != OK)
2134                         return 0;
2135
2136                 // Eat the comma, if it's there
2137                 if (*tok == ',')
2138                         tok++;
2139         }
2140
2141         for(;;)
2142         {
2143                 if (*tok == SYMBOL)
2144                 {
2145                         symbolName = string[tok[1]];
2146
2147                         // Set env to either local (dot prefixed) or global scope
2148                         env = (symbolName[0] == '.' ? curenv : 0);
2149                         symbol = lookup(symbolName, LABEL, env);
2150
2151                         // If the symbol wasn't found, then define it. Otherwise, throw an
2152                         // error.
2153                         if (symbol == NULL)
2154                         {
2155                                 symbol = NewSymbol(symbolName, LABEL, env);
2156                                 symbol->sattr = 0;
2157                         }
2158                         else if (symbol->sattr & DEFINED)
2159                                 return error("multiply-defined label '%s'", symbolName);
2160
2161                         // Put symbol in "order of definition" list
2162                         AddToSymbolDeclarationList(symbol);
2163
2164                         tok += 2;
2165
2166                         // Adjust label start address if it's a word or a long, as a byte
2167                         // label might have left us on an odd address.
2168                         switch ((int)*tok)
2169                         {
2170                         case DOTW:
2171                         case DOTL:
2172                                 eval += eval & 0x01;
2173                         }
2174
2175                         symbol->sattr |= (ABS | DEFINED | EQUATED);
2176                         symbol->svalue = eval;
2177
2178                         // Check for dot suffixes and adjust space accordingly (longs and
2179                         // words on an odd boundary get bumped to the next word aligned
2180                         // address). If no suffix, then throw an error.
2181                         switch ((int)*tok)
2182                         {
2183                         case DOTL:
2184                                 eval += 4;
2185                                 break;
2186                         case DOTW:
2187                                 eval += 2;
2188                                 break;
2189                         case DOTB:
2190                                 eval += 1;
2191                                 break;
2192                         default:
2193                                 return error("Symbol missing dot suffix in .cstruct construct");
2194                         }
2195
2196                         tok++;
2197                 }
2198                 else if (*tok >= KW_D0 && *tok <= KW_A7)
2199                 {
2200                         if (reglist(&rlist) < 0)
2201                                 return 0;
2202
2203                         for(i=0; i<16; i++, rlist>>=1)
2204                         {
2205                                 if (rlist & 1)
2206                                         eval += 4;
2207                         }
2208                 }
2209                 else
2210                 {
2211                         switch ((int)*tok)
2212                         {
2213                         case KW_USP:
2214                         case KW_SSP:
2215                         case KW_PC:
2216                                 eval += 2;
2217                                 // FALLTHROUGH
2218                         case KW_SR:
2219                         case KW_CCR:
2220                                 eval += 2;
2221                                 tok++;
2222                                 break;
2223                         case EOL:
2224                                 return 0;
2225                         default:
2226                                 return error(".cstruct syntax");
2227                         }
2228                 }
2229
2230                 // Eat commas in between each argument, if they exist
2231                 if (*tok == ',')
2232                         tok++;
2233         }
2234 }
2235
2236
2237 //
2238 // Define start of OP object list (allows the use of ORG)
2239 //
2240 int d_objproc(void)
2241 {
2242         if ((cursect != TEXT) && (cursect != DATA))
2243         {
2244                 error(".objproc can only be used in the TEXT or DATA segments");
2245                 return ERROR;
2246         }
2247
2248         // If previous section was DSP or 68000 then we need to reset ORG'd
2249         // Addresses
2250         if (!robjproc)
2251         {
2252                 orgactive = 0;
2253                 orgwarning = 0;
2254         }
2255
2256         robjproc = 1;           // Set OP assembly
2257         rgpu = 0;                       // Unset GPU assembly
2258         rdsp = 0;                       // Unset DSP assembly
2259         dsp56001 = 0;           // Unset 56001 assembly
2260         return OK;
2261 }
2262
2263
2264 //
2265 // Undefine a macro - .undefmac macname [, macname...]
2266 //
2267 int undmac1(char * p)
2268 {
2269         SYM * symbol = lookup(p, MACRO, 0);
2270
2271         // If the macro symbol exists, cause it to disappear
2272         if (symbol != NULL)
2273                 symbol->stype = (BYTE)SY_UNDEF;
2274
2275         return OK;
2276 }
2277
2278
2279 int d_undmac(void)
2280 {
2281         symlist(undmac1);
2282         return 0;
2283 }
2284
2285
2286 int d_jpad(void)
2287 {
2288         warn("JPAD directive is deprecated/non-functional");
2289         return OK;
2290 }
2291
2292
2293 int d_nojpad(void)
2294 {
2295         warn("NOJPAD directive is deprecated/non-functional");
2296         return OK;
2297 }
2298
2299
2300 int d_gpumain(void)
2301 {
2302         return error("What the hell? Do you think we adhere to the Goof standard?");
2303 }
2304
2305
2306 //
2307 // .opt - turn a specific (or all) optimisation on or off
2308 //
2309 int d_opt(void)
2310 {
2311         while (*tok != EOL)
2312         {
2313                 if (*tok == STRING)
2314                 {
2315                         tok++;
2316                         char * tmpstr = string[*tok++];
2317
2318                         if (ParseOptimization(tmpstr) != OK)
2319                                 return error("unknown optimization flag '%s'", tmpstr);
2320                 }
2321                 else
2322                         return error(".opt directive needs every switch enclosed inside quotation marks");
2323         }
2324
2325         return OK;
2326 }
2327
2328
2329 //
2330 // .if, Start conditional assembly
2331 //
2332 int d_if(void)
2333 {
2334         WORD eattr;
2335         uint64_t eval;
2336         SYM * esym;
2337         IFENT * rif = f_ifent;
2338
2339         // Alloc an IFENTRY
2340         if (rif == NULL)
2341                 rif = (IFENT *)malloc(sizeof(IFENT));
2342         else
2343                 f_ifent = rif->if_prev;
2344
2345         rif->if_prev = ifent;
2346         ifent = rif;
2347
2348         if (!disabled)
2349         {
2350                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
2351                         return 0;
2352
2353                 if ((eattr & DEFINED) == 0)
2354                         return error(undef_error);
2355
2356                 disabled = !eval;
2357         }
2358
2359         rif->if_state = (WORD)disabled;
2360         return 0;
2361 }
2362
2363
2364 //
2365 // .else, Do alternate case for .if
2366 //
2367 int d_else(void)
2368 {
2369         IFENT * rif = ifent;
2370
2371         if (rif->if_prev == NULL)
2372                 return error("mismatched .else");
2373
2374         if (disabled)
2375                 disabled = rif->if_prev->if_state;
2376         else
2377                 disabled = 1;
2378
2379         rif->if_state = (WORD)disabled;
2380         return 0;
2381 }
2382
2383
2384 //
2385 // .endif, End of conditional assembly block
2386 // This is also called by fpop() to pop levels of IFENTs in case a macro or
2387 // include file exits early with `exitm' or `end'.
2388 //
2389 int d_endif(void)
2390 {
2391         IFENT * rif = ifent;
2392
2393         if (rif->if_prev == NULL)
2394                 return error("mismatched .endif");
2395
2396         ifent = rif->if_prev;
2397         disabled = rif->if_prev->if_state;
2398         rif->if_prev = f_ifent;
2399         f_ifent = rif;
2400         return 0;
2401 }
2402