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