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