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