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