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