]> Shamusworld >> Repos - rmac/blob - direct.c
Version bump for last commit. :-)
[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
632                 if (*tok++ != ',')
633                 {
634                         close(fd);
635                         return error("expected comma after incbin filename");
636                 }
637
638                 if (*tok != EOL)
639                 {
640                         if (*tok != ',')
641                         {
642                                 if (abs_expr(&requested_size) != OK)
643                                 {
644                                         close(fd);
645                                         return ERROR;
646                                 }
647
648                                 if ((int64_t)requested_size <= 0 || requested_size > size)
649                                 {
650                                         close(fd);
651                                         return error("invalid incbin size requested");
652                                 }
653                         }
654
655                         if (*tok != EOL)
656                         {
657                                 if (*tok++ != ',')
658                                 {
659                                         close(fd);
660                                         return error("expected comma after size parameter");
661                                 }
662
663                                 if (*tok != EOL)
664                                 {
665                                         if (abs_expr(&pos) != OK)
666                                         {
667                                                 close(fd);
668                                                 return ERROR;
669                                         }
670
671                                         if ((int64_t)pos <= 0 || pos > size)
672                                         {
673                                                 close(fd);
674                                                 return error("invalid incbin position requested");
675                                         }
676                                 }
677                         }
678
679                         if (*tok != EOL)
680                         {
681                                 close(fd);
682                                 return error("extra characters following incbin");
683                         }
684                 }
685
686                 // Adjust size if the user didn't specify it via the parameter
687                 if (requested_size == -1)
688                 {
689                         requested_size = size - pos;
690                 }
691
692                 // Are we going to read past the end of the file?
693                 if (pos + requested_size > size)
694                 {
695                         close(fd);
696                         return error("invalid combination of incbin position and size");
697                 }
698                 size = requested_size;
699
700                 // All checks passed, let's seek to where the user requested, otherwise at file start
701                 lseek(fd, pos, SEEK_SET);
702         }
703
704         chcheck(size);
705
706         DEBUG { printf("INCBIN: File '%s' is %li bytes.\n", string[filename], size); }
707
708         char * fileBuffer = (char *)malloc(size);
709         bytesRead = read(fd, fileBuffer, size);
710
711         if (bytesRead != size)
712         {
713                 error("was only able to read %li bytes from binary file (%s, %li bytes)", bytesRead, string[filename], size);
714                 return ERROR;
715         }
716
717         memcpy(chptr, fileBuffer, size);
718         chptr += size;
719         sloc += size;
720         ch_size += size;
721
722         if (orgactive)
723                 orgaddr += size;
724
725         free(fileBuffer);
726         close(fd);
727         return 0;
728 }
729
730
731 //
732 // Set RISC register banks
733 //
734 int d_regbank0(void)
735 {
736         // Deprecated, it's not as if this did anything useful, ever
737         warn("regbank0 ignored");
738         return 0;
739 }
740
741
742 int d_regbank1(void)
743 {
744         // Deprecated, it's not as if this did anything useful, ever
745         warn("regbank1 ignored");
746         return 0;
747 }
748
749
750 //
751 // Helper function, to cut down on mistakes & typing
752 //
753 static inline void SkipBytes(unsigned bytesToSkip)
754 {
755         if (!bytesToSkip)
756                 return;
757
758         if ((scattr & SBSS) == 0)
759         {
760                 chcheck(bytesToSkip);
761                 D_ZEROFILL(bytesToSkip);
762         }
763         else
764         {
765                 sloc += bytesToSkip;
766
767                 if (orgactive)
768                         orgaddr += bytesToSkip;
769         }
770 }
771
772
773 //
774 // Adjust location to an EVEN value
775 //
776 int d_even(void)
777 {
778         if (m6502)
779                 return error(in_6502mode);
780
781         unsigned skip = (rgpu || rdsp ? orgaddr : sloc) & 0x01;
782
783         if (skip)
784         {
785                 if ((scattr & SBSS) == 0)
786                 {
787                         chcheck(1);
788                         D_byte(0);
789                 }
790                 else
791                 {
792                         sloc++;
793
794                         if (orgactive)
795                                 orgaddr++;
796                 }
797         }
798
799         return 0;
800 }
801
802
803 //
804 // Adjust location to a LONG value
805 //
806 int d_long(void)
807 {
808         unsigned lower2Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x03;
809         unsigned bytesToSkip = (0x04 - lower2Bits) & 0x03;
810         SkipBytes(bytesToSkip);
811         SetLargestAlignment(4);
812
813         return 0;
814 }
815
816
817 //
818 // Adjust location to a PHRASE value
819 //
820 // N.B.: We have to handle the GPU/DSP cases separately because you can embed
821 //       RISC code in the middle of a regular 68K section. Also note that all
822 //       of the alignment pseudo-ops will have to be fixed this way.
823 //
824 // This *must* behave differently when in a RISC section, as following sloc
825 // (instead of orgaddr) will fuck things up royally. Note that we do it this
826 // way because you can embed RISC code in a 68K section, and have the origin
827 // pointing to a different alignment in the RISC section than the 68K section.
828 //
829 int d_phrase(void)
830 {
831         unsigned lower3Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x07;
832         unsigned bytesToSkip = (0x08 - lower3Bits) & 0x07;
833         SkipBytes(bytesToSkip);
834         SetLargestAlignment(8);
835
836         return 0;
837 }
838
839
840 //
841 // Adjust location to a DPHRASE value
842 //
843 int d_dphrase(void)
844 {
845         unsigned lower4Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x0F;
846         unsigned bytesToSkip = (0x10 - lower4Bits) & 0x0F;
847         SkipBytes(bytesToSkip);
848         SetLargestAlignment(16);
849
850         return 0;
851 }
852
853
854 //
855 // Adjust location to a QPHRASE value
856 //
857 int d_qphrase(void)
858 {
859         unsigned lower5Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x1F;
860         unsigned bytesToSkip = (0x20 - lower5Bits) & 0x1F;
861         SkipBytes(bytesToSkip);
862         SetLargestAlignment(32);
863
864         return 0;
865 }
866
867
868 //
869 // Adjust location to <alignment> bytes
870 //
871 int d_align(void)
872 {
873         unsigned bytesToSkip;
874         uint64_t eval;
875
876         if (abs_expr(&eval) != OK)
877                 return 0;
878
879         if (eval < 2)
880         {
881                 return error("Invalid .align value specified");
882         }
883
884         if (dsp56001)
885         {
886                 bytesToSkip = eval - sloc % eval;
887                 D_ZEROFILL(bytesToSkip*3);
888                 return 0;
889         }
890
891         bytesToSkip = eval - (rgpu || rdsp ? orgaddr : sloc) % eval;
892         if ( bytesToSkip != eval )
893         {
894                 if ((scattr & SBSS) == 0)
895                 {
896                         D_ZEROFILL(bytesToSkip);
897                 }
898                 else
899                 {
900                         sloc += bytesToSkip;
901
902                         if (orgactive)
903                                 orgaddr += bytesToSkip;
904                 }
905         }
906         return 0;
907 }
908
909
910 //
911 // Do auto-even.  This must be called ONLY if 'sloc' is odd.
912 //
913 // This is made hairy because, if there was a label on the line, we also have
914 // to adjust its value. This won't work with more than one label on the line,
915 // which is OK since multiple labels are only allowed in AS68 kludge mode, and
916 // the C compiler is VERY paranoid and uses ".even" whenever it can
917 //
918 // N.B.: This probably needs the same fixes as above...
919 //
920 void auto_even(void)
921 {
922         if (cursect != M6502)
923         {
924                 if (scattr & SBSS)
925                         sloc++;                         // Bump BSS section
926                 else
927                         D_byte(0);                      // Deposit 0.b in non-BSS
928
929                 if (lab_sym != NULL)    // Bump label if we have to
930                         lab_sym->svalue++;
931         }
932 }
933
934
935 //
936 // Unimplemened directive error
937 //
938 int d_unimpl(void)
939 {
940         return error("unimplemented directive");
941 }
942
943
944 //
945 // Return absolute (not TDB) and defined expression or return an error
946 //
947 int abs_expr(uint64_t * a_eval)
948 {
949         WORD eattr;
950
951         if (expr(exprbuf, a_eval, &eattr, NULL) < 0)
952                 return ERROR;
953
954         if (!(eattr & DEFINED))
955                 return error(undef_error);
956
957         if (eattr & TDB)
958                 return error(rel_error);
959
960         return OK;
961 }
962
963
964 //
965 // Hand symbols in a symbol-list to a function (kind of like mapcar...)
966 //
967 int symlist(int(* func)())
968 {
969         const char * em = "symbol list syntax";
970
971         for(;;)
972         {
973                 if (*tok != SYMBOL)
974                         return error(em);
975
976                 if ((*func)(string[tok[1]]) != OK)
977                         break;
978
979                 tok += 2;
980
981                 if (*tok == EOL)
982                         break;
983
984                 if (*tok != ',')
985                         return error(em);
986
987                 tok++;
988         }
989
990         return 0;
991 }
992
993
994 //
995 // .include "filename"
996 //
997 int d_include(void)
998 {
999         int j;
1000         int i;
1001         char * fn;
1002         char buf[128];
1003         char buf1[128];
1004
1005         if (*tok == STRING)                     // Leave strings ALONE
1006                 fn = string[*++tok];
1007         else if (*tok == SYMBOL)        // Try to append ".s" to symbols
1008         {
1009                 strcpy(buf, string[*++tok]);
1010                 fext(buf, ".s", 0);
1011                 fn = &buf[0];
1012         }
1013         else                                            // Punt if no STRING or SYMBOL
1014                 return error("missing filename");
1015
1016         // Make sure the user didn't try anything like:
1017         // .include equates.s
1018         if (*++tok != EOL)
1019                 return error("extra stuff after filename--enclose it in quotes");
1020
1021         // Attempt to open the include file in the current directory, then (if that
1022         // failed) try list of include files passed in the enviroment string or by
1023         // the "-i" option.
1024         if ((j = open(fn, 0)) < 0)
1025         {
1026                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
1027                 {
1028                         j = strlen(buf1);
1029
1030                         // Append path char if necessary
1031                         if (j > 0 && buf1[j - 1] != SLASHCHAR)
1032                                 strcat(buf1, SLASHSTRING);
1033
1034                         strcat(buf1, fn);
1035
1036                         if ((j = open(buf1, 0)) >= 0)
1037                                 goto allright;
1038                 }
1039
1040                 return error("cannot open: \"%s\"", fn);
1041         }
1042
1043 allright:
1044         include(j, fn);
1045         return 0;
1046 }
1047
1048
1049 //
1050 // .assert expression [, expression...]
1051 //
1052 int d_assert(void)
1053 {
1054         WORD eattr;
1055         uint64_t eval;
1056
1057         for(; expr(exprbuf, &eval, &eattr, NULL)==OK; ++tok)
1058         {
1059                 if (!(eattr & DEFINED))
1060                         return error("forward or undefined .assert");
1061
1062                 if (!eval)
1063                         return error("assert failure");
1064
1065                 if (*tok != ',')
1066                         break;
1067         }
1068
1069         ErrorIfNotAtEOL();
1070         return 0;
1071 }
1072
1073
1074 //
1075 // .globl symbol [, symbol] <<<cannot make local symbols global>>>
1076 //
1077 int globl1(char * p)
1078 {
1079         SYM * sy;
1080
1081         if (*p == '.')
1082                 return error("cannot .globl local symbol");
1083
1084         if ((sy = lookup(p, LABEL, 0)) == NULL)
1085         {
1086                 sy = NewSymbol(p, LABEL, 0);
1087                 sy->svalue = 0;
1088                 sy->sattr = GLOBAL;
1089 //printf("glob1: Making global symbol: attr=%04X, eattr=%08X, %s\n", sy->sattr, sy->sattre, sy->sname);
1090         }
1091         else
1092                 sy->sattr |= GLOBAL;
1093
1094         return OK;
1095 }
1096
1097
1098 int d_globl(void)
1099 {
1100         if (m6502)
1101                 return error(in_6502mode);
1102
1103         symlist(globl1);
1104         return 0;
1105 }
1106
1107
1108 //
1109 // .prgflags expression
1110 //
1111 int d_prgflags(void)
1112 {
1113         uint64_t eval;
1114
1115         if (*tok == EOL)
1116                 return error("PRGFLAGS requires value");
1117         else if (abs_expr(&eval) == OK)
1118         {
1119                 PRGFLAGS = (uint32_t)eval;
1120                 return 0;
1121         }
1122         else
1123         {
1124                 return error("PRGFLAGS requires value");
1125         }
1126 }
1127
1128
1129 //
1130 // .abs [expression]
1131 //
1132 int d_abs(void)
1133 {
1134         uint64_t eval;
1135
1136         if (m6502)
1137                 return error(in_6502mode);
1138
1139         SaveSection();
1140
1141         if (*tok == EOL)
1142                 eval = 0;
1143         else if (abs_expr(&eval) != OK)
1144                 return 0;
1145
1146         SwitchSection(ABS);
1147         sloc = (uint32_t)eval;
1148         return 0;
1149 }
1150
1151
1152 //
1153 // Switch segments
1154 //
1155 int d_text(void)
1156 {
1157         if (rgpu || rdsp)
1158                 return error("directive forbidden in gpu/dsp mode");
1159         else if (m6502)
1160                 return error(in_6502mode);
1161
1162         if (cursect != TEXT)
1163         {
1164                 SaveSection();
1165                 SwitchSection(TEXT);
1166         }
1167
1168         return 0;
1169 }
1170
1171
1172 int d_data(void)
1173 {
1174         if (rgpu || rdsp)
1175                 return error("directive forbidden in gpu/dsp mode");
1176         else if (m6502)
1177                 return error(in_6502mode);
1178
1179         if (cursect != DATA)
1180         {
1181                 SaveSection();
1182                 SwitchSection(DATA);
1183         }
1184
1185         return 0;
1186 }
1187
1188
1189 int d_bss(void)
1190 {
1191         if (rgpu || rdsp)
1192                 return error("directive forbidden in gpu/dsp mode");
1193         else if (m6502)
1194                 return error(in_6502mode);
1195
1196         if (cursect != BSS)
1197         {
1198                 SaveSection();
1199                 SwitchSection(BSS);
1200         }
1201
1202         return 0;
1203 }
1204
1205
1206 //
1207 // .ds[.size] expression
1208 //
1209 int d_ds(WORD siz)
1210 {
1211         DEBUG { printf("Directive: .ds.[size] = %u, sloc = $%X\n", siz, sloc); }
1212
1213         uint64_t eval;
1214     WORD eattr;
1215
1216         if ((cursect & (M6502 | M56KPXYL)) == 0)
1217         {
1218                 if ((siz != SIZB) && (sloc & 1))        // Automatic .even
1219                         auto_even();
1220         }
1221
1222         if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1223                 return ERROR;
1224
1225         // Check to see if the value being passed in is negative (who the hell does
1226         // that?--nobody does; it's the code gremlins, or rum, what does it)
1227         // N.B.: Since 'eval' is of type uint64_t, if it goes negative, it will
1228         //       have its high bit set.
1229         if (eval & 0x8000000000000000)
1230                 return error("negative sizes not allowed in DS");
1231
1232         // In non-TDB section (BSS, ABS and M6502) just advance the location
1233         // counter appropriately. In TDB sections, deposit (possibly large) chunks
1234         // of zeroed memory....
1235         if ((scattr & SBSS) || cursect == M6502)
1236         {
1237                 listvalue((uint32_t)eval);
1238                 eval *= siz;
1239                 sloc += (uint32_t)eval;
1240
1241                 if (cursect == M6502)
1242                         chptr += eval;
1243
1244                 just_bss = 1;                                   // No data deposited (8-bit CPU mode)
1245         }
1246         else if (cursect & M56KPXYL)
1247         {
1248                 // Change segment instead of marking blanks.
1249                 // Only mark segments we actually wrote something
1250                 if (chptr != dsp_currentorg->start && dsp_written_data_in_current_org)
1251                 {
1252                         dsp_currentorg->end = chptr;
1253                         dsp_currentorg++;
1254                         dsp_currentorg->memtype = dsp_currentorg[-1].memtype;
1255                 }
1256
1257                 listvalue((uint32_t)eval);
1258                 sloc += (uint32_t)eval;
1259
1260                 // And now let's create a new segment
1261                 dsp_currentorg->start = chptr;
1262                 dsp_currentorg->chunk = scode;  // Mark down which chunk this org starts from (will be needed when outputting)
1263                 sect[cursect].orgaddr = sloc;
1264                 dsp_currentorg->orgadr = sloc;
1265                 dsp_written_data_in_current_org = 0;
1266
1267                 just_bss = 1;                                   // No data deposited
1268         }
1269         else
1270         {
1271                 dep_block(eval, siz, 0, (DEFINED | ABS), NULL);
1272         }
1273
1274         ErrorIfNotAtEOL();
1275         return OK;
1276 }
1277
1278
1279 //
1280 // dsm[.siz] expression
1281 // Define modulo storage
1282 // Quoting the Motorola assembler manual:
1283 // "The DSM directive reserves a block of memory the length of which in words is equal to
1284 // the value of <expression>.If the runtime location counter is not zero, this directive first
1285 // advances the runtime location counter to a base address that is a multiple of 2k, where
1286 // 2k >= <expression>."
1287 // The kicker of course is written a few sentences after:
1288 // "<label>, if present, will be assigned the value of the runtime location counter after a valid
1289 // base address has been established."
1290 //
1291 int d_dsm(WORD siz)
1292 {
1293         TOKEN * tok_current = tok;  // Keep track of where tok was when we entered this procedure
1294         uint64_t eval;
1295
1296         if (abs_expr(&eval) != OK)
1297                 return 0;
1298
1299         // Round up to the next highest power of 2
1300         // Nicked from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
1301         eval--;
1302         eval |= eval >> 1;
1303         eval |= eval >> 2;
1304         eval |= eval >> 4;
1305         eval |= eval >> 8;
1306         eval |= eval >> 16;
1307
1308         int units_to_skip;
1309         units_to_skip = eval + 1 - sloc;
1310         sloc += units_to_skip;          // Bump up sloc - TODO: check if this goes over the RAM limits?
1311
1312         // If a label has been defined in the same line as dsm, its value also needs to be adjusted
1313         if (label_defined)
1314         {
1315                 SYM * label = lookup(label_defined, LABEL, 0);
1316                 label->svalue += units_to_skip;
1317         }
1318
1319         tok = tok_current;              // Rewind tok back to where it was
1320         return d_ds(siz);               // And let d_ds take over from here
1321 }
1322
1323
1324 //
1325 // dc.b, dc.w / dc, dc.l, dc.i, dc.q, dc.d, dc.s, dc.x
1326 //
1327 int d_dc(WORD siz)
1328 {
1329         WORD eattr;
1330         uint64_t eval;
1331         uint8_t * p;
1332
1333         if ((scattr & SBSS) != 0)
1334                 return error("illegal initialization of section");
1335
1336         // Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
1337         if ((cursect != M6502) && (cursect != M56001P) && (cursect != M56001X)
1338                 && (cursect != M56001Y) && (cursect != M56001L)
1339                 && (siz != SIZB) && (sloc & 1))
1340                 auto_even();
1341
1342         // Check to see if we're trying to set LONGS on a non 32-bit aligned
1343         // address in a GPU or DSP section, in their local RAM
1344         if ((siz == SIZL) && (orgaddr & 0x03)
1345                 && ((rgpu && (orgaddr >= 0xF03000) && (orgaddr <= 0xF03FFFF))
1346                 || (rdsp && (orgaddr >= 0xF1B000) && (orgaddr <= 0xF1CFFFF))))
1347                 warn("depositing LONGs on a non-long address in local RAM");
1348
1349         for(;; tok++)
1350         {
1351                 // dc.b 'string' [,] ...
1352                 if (siz == SIZB && (*tok == STRING || *tok == STRINGA8) && (tok[2] == ',' || tok[2] == EOL))
1353                 {
1354                         uint32_t i = strlen(string[tok[1]]);
1355
1356                         if ((challoc - ch_size) < i)
1357                                 chcheck(i);
1358
1359                         if (*tok == STRING)
1360                         {
1361                                 for(p=string[tok[1]]; *p!=EOS; p++)
1362                                         D_byte(*p);
1363                         }
1364                         else if (*tok == STRINGA8)
1365                         {
1366                                 for(p=string[tok[1]]; *p!=EOS; p++)
1367                                         D_byte(strtoa8[*p]);
1368                         }
1369                         else
1370                         {
1371                                 error("String format not supported... yet");
1372                         }
1373
1374                         tok += 2;
1375                         goto comma;
1376                 }
1377
1378                 int movei = 0; // MOVEI flag for dc.i
1379
1380                 if (*tok == DOTI)
1381                 {
1382                         movei = 1;
1383                         tok++;
1384                         siz = SIZL;
1385                 }
1386
1387                 // dc.x <expression>
1388                 SYM * esym = 0;
1389
1390                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
1391                         return 0;
1392
1393                 uint16_t tdb = eattr & TDB;
1394                 uint16_t defined = eattr & DEFINED;
1395
1396 // 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 !!!
1397                 if (dsp56001)
1398                 {
1399                         if (cursect != M56001L)
1400                         {
1401                                 if (!defined)
1402                                 {
1403                                         AddFixup(FU_DSPIMM24 | FU_SEXT, sloc, exprbuf);
1404                                         D_dsp(0);
1405                                 }
1406                                 else
1407                                 {
1408                                         if (eattr & FLOAT)
1409                                         {
1410                                                 double fval = *(double *)&eval;
1411                                                 eval = DoubleToDSPFloat(fval);
1412                                         }
1413                                         else
1414                                         {
1415                                                 if ((uint32_t)eval + 0x1000000 >= 0x2000000)
1416                                                         return error(range_error);
1417                                         }
1418
1419                                         // Deposit DSP word (24-bit)
1420                                         D_dsp(eval);
1421                                 }
1422                         }
1423                         else
1424                         {
1425                                 // In L: we deposit stuff to both X: and Y: instead
1426                                 // We will be a bit lazy and require that there is a 2nd value
1427                                 // in the same source line. (Motorola's assembler can parse
1428                                 // 12-digit hex values, which we can't do at the moment) This
1429                                 // of course requires to parse 2 values in one pass. If there
1430                                 // isn't another value in this line, assume X: value is 0.
1431                                 int secondword = 0;
1432                                 uint32_t evaly;
1433 l_parse_loop:
1434
1435                                 if (!defined)
1436                                 {
1437                                         AddFixup(FU_DSPIMM24 | FU_SEXT, sloc, exprbuf);
1438                                         D_dsp(0);
1439                                 }
1440                                 else
1441                                 {
1442                                         if (eattr & FLOAT)
1443                                         {
1444                                                 float fval = *(float *)&eval;
1445                                                 eval = DoubleToDSPFloat(fval);
1446                                         }
1447                                         else
1448                                         {
1449                                                 if (eval + 0x1000000 >= 0x2000000)
1450                                                         return error(range_error);
1451                                         }
1452
1453                                         // Parse 2nd value if we didn't do this yet
1454                                         if (secondword == 0)
1455                                         {
1456                                                 evaly = (uint32_t)eval;
1457                                                 secondword = 1;
1458
1459                                                 if (*tok != ':')
1460                                                 {
1461                                                         // If we don't have a : then we're probably at EOL,
1462                                                         // which means the X: value will be 0
1463                                                         eval = 0;
1464                                                         ErrorIfNotAtEOL();
1465                                                 }
1466                                                 else
1467                                                 {
1468                                                         tok++; // Eat the comma;
1469
1470                                                         if (expr(exprbuf, &eval, &eattr, NULL) != OK)
1471                                                                 return 0;
1472
1473                                                         defined = (WORD)(eattr & DEFINED);
1474                                                         goto l_parse_loop;
1475                                                 }
1476                                         }
1477
1478                                         // Deposit DSP words (24-bit)
1479                                         D_dsp(eval);
1480                                         D_dsp(evaly);
1481                                         sloc--; // We do write 2 DSP words but as far as L: space is concerned we actually advance our counter by one
1482                                 }
1483
1484                         }
1485
1486                         goto comma;
1487                 }
1488
1489                 switch (siz)
1490                 {
1491                 case SIZB:
1492                         if (!defined)
1493                         {
1494                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1495                                 D_byte(0);
1496                         }
1497                         else
1498                         {
1499                                 if (tdb)
1500                                         return error("non-absolute byte value");
1501
1502                                 if (eval + 0x100 >= 0x200)
1503                                         return error("%s (value = $%X)", range_error, eval);
1504
1505                                 D_byte(eval);
1506                         }
1507
1508                         break;
1509
1510                 case SIZW:
1511                 case SIZN:
1512                         if (!defined)
1513                         {
1514                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1515                                 D_word(0);
1516                         }
1517                         else
1518                         {
1519                                 if (eval + 0x10000 >= 0x20000)
1520                                         return error(range_error);
1521
1522                                 if (tdb)
1523                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1524
1525                                 // Deposit 68000 or 6502 (byte-reversed) word
1526                                 if (cursect != M6502)
1527                                         D_word(eval)
1528                                 else
1529                                         D_rword(eval)
1530                         }
1531
1532                         break;
1533
1534                 case SIZL:
1535                         // Shamus: Why can't we do longs in 6502 mode?
1536                         if (m6502)
1537                                 return error(in_6502mode);
1538
1539                         if (!defined)
1540                         {
1541                                 AddFixup(FU_LONG | (movei ? FU_MOVEI : 0), sloc, exprbuf);
1542                                 D_long(0);
1543                         }
1544                         else
1545                         {
1546                                 if (tdb)
1547                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1548
1549                                 if (movei)
1550                                         eval = WORDSWAP32(eval);
1551
1552                                 D_long(eval);
1553                         }
1554
1555                         break;
1556
1557                 case SIZQ:
1558                         // 64-bit size
1559                         if (m6502)
1560                                 return error(in_6502mode);
1561
1562                         // DEFINITELY NEED FIXUPS HERE!
1563                         if (!defined)
1564                         {
1565                                 AddFixup(FU_QUAD, sloc, exprbuf);
1566                                 eval = 0;
1567                         }
1568
1569                         D_quad(eval);
1570                         break;
1571
1572                 case SIZS:
1573                         // 32-bit float size
1574                         if (m6502)
1575                                 return error(in_6502mode);
1576
1577 /* Seems to me that if something is undefined here, then that should be an error.  Likewise for the D & X variants. */
1578                         if (!defined)
1579                         {
1580 //                              AddFixup(FU_FLOATSING, sloc, exprbuf);
1581 //                              D_long(0);
1582                                 return error("labels not allowed in floating point expressions");
1583                         }
1584                         else
1585                         {
1586 //Would this *ever* happen?
1587 //                              if (tdb)
1588 //                                      MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
1589
1590                                 PTR ptr;
1591                                 ptr.u64 = &eval;
1592                                 uint32_t ieee754 = FloatToIEEE754((float)*ptr.dp);
1593                                 D_long(ieee754);
1594                         }
1595
1596                         break;
1597
1598                 case SIZD:
1599                         // 64-bit double size
1600                         if (m6502)
1601                                 return error(in_6502mode);
1602
1603                         if (!defined)
1604                         {
1605 //                              AddFixup(FU_FLOATDOUB, sloc, exprbuf);
1606 //                              D_quad(0LL);
1607                                 return error("labels not allowed in floating point expressions");
1608                         }
1609                         else
1610                         {
1611 //Would this *ever* happen?
1612 //                              if (tdb)
1613 //                                      MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
1614
1615                                 PTR ptr;
1616                                 ptr.u64 = &eval;
1617                                 uint64_t ieee754 = DoubleToIEEE754(*ptr.dp);
1618                                 D_quad(ieee754);
1619                         }
1620
1621                         break;
1622
1623                 case SIZX:
1624                         if (m6502)
1625                                 return error(in_6502mode);
1626
1627                         uint8_t extDbl[12];
1628                         memset(extDbl, 0, 12);
1629
1630                         if (!defined)
1631                         {
1632 //                              AddFixup(FU_FLOATEXT, sloc, exprbuf);
1633 //                              D_extend(extDbl);
1634                                 return error("labels not allowed in floating point expressions");
1635                         }
1636                         else
1637                         {
1638 //Would this *ever* happen?
1639 //                              if (tdb)
1640 //                                      MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
1641
1642                                 PTR ptr;
1643                                 ptr.u64 = &eval;
1644                                 DoubleToExtended(*ptr.dp, extDbl);
1645                                 D_extend(extDbl);
1646                         }
1647
1648                         break;
1649                 }
1650
1651 comma:
1652                 if (*tok != ',')
1653                         break;
1654         }
1655
1656         ErrorIfNotAtEOL();
1657         return 0;
1658 }
1659
1660
1661 //
1662 // dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2'
1663 //
1664 int d_dcb(WORD siz)
1665 {
1666         uint64_t evalc, eval;
1667         WORD eattr;
1668
1669         DEBUG { printf("dcb: section is %s%s%s (scattr=$%X)\n", (cursect & TEXT ? "TEXT" : ""), (cursect & DATA ? " DATA" : ""), (cursect & BSS ? "BSS" : ""), scattr); }
1670
1671         if ((scattr & SBSS) != 0)
1672                 return error("illegal initialization of section");
1673
1674         if (abs_expr(&evalc) != OK)
1675                 return 0;
1676
1677         if (*tok++ != ',')
1678                 return error("missing comma");
1679
1680         if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1681                 return 0;
1682
1683         if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
1684                 auto_even();
1685
1686         dep_block((uint32_t)evalc, siz, (uint32_t)eval, eattr, exprbuf);
1687         return 0;
1688 }
1689
1690
1691 //
1692 // Generalized initialization directive
1693 //
1694 // .init[.siz] [#count,] expression [.size] , ...
1695 //
1696 // The size suffix on the ".init" directive becomes the default size of the
1697 // objects to deposit. If an item is preceeded with a sharp (immediate) sign
1698 // and an expression, it specifies a repeat count. The value to be deposited
1699 // may be followed by a size suffix, which overrides the default size.
1700 //
1701 int d_init(WORD def_siz)
1702 {
1703         uint64_t count;
1704         uint64_t eval;
1705         WORD eattr;
1706         WORD siz;
1707
1708         if ((scattr & SBSS) != 0)
1709                 return error(".init not permitted in BSS or ABS");
1710
1711         if (rgpu || rdsp)
1712                 return error("directive forbidden in gpu/dsp mode");
1713
1714         for(;;)
1715         {
1716                 // Get repeat count (defaults to 1)
1717                 if (*tok == '#')
1718                 {
1719                         tok++;
1720
1721                         if (abs_expr(&count) != OK)
1722                                 return 0;
1723
1724                         if (*tok++ != ',')
1725                                 return error(comma_error);
1726                 }
1727                 else
1728                         count = 1;
1729
1730                 // Evaluate expression to deposit
1731                 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1732                         return 0;
1733
1734                 switch (*tok++)
1735                 {                                 // Determine size of object to deposit
1736                 case DOTB: siz = SIZB; break;
1737                 case DOTW: siz = SIZB; break;
1738                 case DOTL: siz = SIZL; break;
1739                 default:
1740                         siz = def_siz;
1741                         tok--;
1742                         break;
1743                 }
1744
1745                 dep_block((uint32_t)count, siz, (uint32_t)eval, eattr, exprbuf);
1746
1747                 switch (*tok)
1748                 {
1749                 case EOL:
1750                         return 0;
1751                 case ',':
1752                         tok++;
1753                         continue;
1754                 default:
1755                         return error(comma_error);
1756                 }
1757         }
1758 }
1759
1760
1761 //
1762 // Deposit 'count' values of size 'siz' in the current (non-BSS) segment
1763 //
1764 int dep_block(uint32_t count, WORD siz, uint32_t eval, WORD eattr, TOKEN * exprbuf)
1765 {
1766         WORD tdb = eattr & TDB;
1767         WORD defined = eattr & DEFINED;
1768
1769         while (count--)
1770         {
1771                 if ((challoc - ch_size) < 4)
1772                         chcheck(4L);
1773
1774                 switch(siz)
1775                 {
1776                 case SIZB:
1777                         if (!defined)
1778                         {
1779                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1780                                 D_byte(0);
1781                         }
1782                         else
1783                         {
1784                                 if (tdb)
1785                                         return error("non-absolute byte value");
1786
1787                                 if (eval + 0x100 >= 0x200)
1788                                         return error(range_error);
1789
1790                                 D_byte(eval);
1791                         }
1792
1793                         break;
1794                 case SIZW:
1795                 case SIZN:
1796                         if (!defined)
1797                         {
1798                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1799                                 D_word(0);
1800                         }
1801                         else
1802                         {
1803                                 if (tdb)
1804                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1805
1806                                 if (eval + 0x10000 >= 0x20000)
1807                                         return error(range_error);
1808
1809                                 // Deposit 68000 or 6502 (byte-reversed) word
1810                                 if (cursect != M6502)
1811                                         D_word(eval)
1812                                 else
1813                                         D_rword(eval)
1814
1815                         }
1816
1817                         break;
1818                 case SIZL:
1819                         if (m6502)
1820                                 return error(in_6502mode);
1821
1822                         if (!defined)
1823                         {
1824                                 AddFixup(FU_LONG, sloc, exprbuf);
1825                                 D_long(0);
1826                         }
1827                         else
1828                         {
1829                                 if (tdb)
1830                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1831
1832                                 D_long(eval);
1833                         }
1834
1835                         break;
1836                 }
1837         }
1838
1839         return 0;
1840 }
1841
1842
1843 //
1844 // .comm symbol, size
1845 //
1846 int d_comm(void)
1847 {
1848         SYM * sym;
1849         char * p;
1850         uint64_t eval;
1851
1852         if (m6502)
1853                 return error(in_6502mode);
1854
1855         if (*tok != SYMBOL)
1856                 return error("missing symbol");
1857
1858         p = string[tok[1]];
1859         tok += 2;
1860
1861         if (*p == '.')                                          // Cannot .comm a local symbol
1862                 return error(locgl_error);
1863
1864         if ((sym = lookup(p, LABEL, 0)) == NULL)
1865                 sym = NewSymbol(p, LABEL, 0);
1866         else
1867         {
1868                 if (sym->sattr & DEFINED)
1869                         return error(".comm symbol already defined");
1870         }
1871
1872         sym->sattr = GLOBAL | COMMON | BSS;
1873
1874         if (*tok++ != ',')
1875                 return error(comma_error);
1876
1877         if (abs_expr(&eval) != OK)                      // Parse size of common region
1878                 return 0;
1879
1880         sym->svalue = eval;                                     // Install common symbol's size
1881         ErrorIfNotAtEOL();
1882         return 0;
1883 }
1884
1885
1886 //
1887 // .list - Turn listing on
1888 //
1889 int d_list(void)
1890 {
1891         if (list_flag)
1892                 listing++;
1893
1894         return 0;
1895 }
1896
1897
1898 //
1899 // .nlist - Turn listing off
1900 //
1901 int d_nlist(void)
1902 {
1903         if (list_flag)
1904                 listing--;
1905
1906         return 0;
1907 }
1908
1909
1910 //
1911 // .68000 - Back to 68000 TEXT segment
1912 //
1913 int d_68000(void)
1914 {
1915         rgpu = rdsp = robjproc = dsp56001 = 0;
1916         // Switching from gpu/dsp sections should reset any ORG'd Address
1917         orgactive = 0;
1918         orgwarning = 0;
1919         SaveSection();
1920         SwitchSection(TEXT);
1921         activecpu = CPU_68000;
1922         regbase = reg68base;    // Update register DFA tables
1923         regtab = reg68tab;
1924         regcheck = reg68check;
1925         regaccept = reg68accept;
1926         return 0;
1927 }
1928
1929
1930 //
1931 // .68020 - Back to 68000 TEXT segment and select 68020
1932 //
1933 int d_68020(void)
1934 {
1935         d_68000();
1936         activecpu = CPU_68020;
1937         return 0;
1938 }
1939
1940
1941 //
1942 // .68030 - Back to 68000 TEXT segment and select 68030
1943 //
1944 int d_68030(void)
1945 {
1946         d_68000();
1947         activecpu = CPU_68030;
1948         return 0;
1949 }
1950
1951
1952 //
1953 // .68040 - Back to 68000 TEXT segment and select 68040
1954 //
1955 int d_68040(void)
1956 {
1957         d_68000();
1958         activecpu = CPU_68040;
1959         activefpu = FPU_68040;
1960         return 0;
1961 }
1962
1963
1964 //
1965 // .68060 - Back to 68000 TEXT segment and select 68060
1966 //
1967 int d_68060(void)
1968 {
1969         d_68000();
1970         activecpu = CPU_68060;
1971         activefpu = FPU_68060;
1972         return 0;
1973 }
1974
1975
1976 //
1977 // .68881 - Back to 680x0 TEXT segment and select 68881 FPU
1978 //
1979 int d_68881(void)
1980 {
1981         activefpu = FPU_68881;
1982         regbase = reg68base;    // Update register DFA tables
1983         regtab = reg68tab;
1984         regcheck = reg68check;
1985         regaccept = reg68accept;
1986         return 0;
1987 }
1988
1989
1990 //
1991 // .68882 - Back to 680x0 TEXT segment and select 68882 FPU
1992 //
1993 int d_68882(void)
1994 {
1995         activefpu = FPU_68882;
1996         regbase = reg68base;    // Update register DFA tables
1997         regtab = reg68tab;
1998         regcheck = reg68check;
1999         regaccept = reg68accept;
2000         return 0;
2001 }
2002
2003
2004 //
2005 // nofpu - Deselect FPUs.
2006 //
2007 int d_nofpu(void)
2008 {
2009         activefpu = FPU_NONE;
2010         return 0;
2011 }
2012
2013
2014 //
2015 // .56001 - Switch to DSP56001 assembler
2016 //
2017 int d_56001(void)
2018 {
2019         dsp56001 = 1;
2020         rgpu = rdsp = robjproc = 0;
2021         SaveSection();
2022
2023         if ((obj_format == LOD) || (obj_format == P56))
2024                 SwitchSection(M56001P);
2025
2026         regbase = reg56base;    // Update register DFA tables
2027         regtab = reg56tab;
2028         regcheck = reg56check;
2029         regaccept = reg56accept;
2030         used_architectures |= M56001P | M56001X | M56001Y | M56001L;
2031         return 0;
2032 }
2033
2034
2035 //
2036 // .gpu - Switch to GPU assembler
2037 //
2038 int d_gpu(void)
2039 {
2040         if ((cursect != TEXT) && (cursect != DATA))
2041         {
2042                 error(".gpu can only be used in the TEXT or DATA segments");
2043                 return ERROR;
2044         }
2045
2046         // If previous section was DSP or 68000 then we need to reset ORG'd Addresses
2047         if (!rgpu)
2048         {
2049                 orgactive = 0;
2050                 orgwarning = 0;
2051         }
2052
2053         rgpu = 1;                       // Set GPU assembly
2054         rdsp = 0;                       // Unset DSP assembly
2055         robjproc = 0;           // Unset OP assembly
2056         dsp56001 = 0;           // Unset 56001 assembly
2057
2058         regbase = regriscbase;  // Update register DFA tables
2059         regtab = regrisctab;
2060         regcheck = regrisccheck;
2061         regaccept = regriscaccept;
2062         //used_architectures |= MGPU;   // TODO: Should GPU/DSP have their own dedicated sections in the long run?
2063         return 0;
2064 }
2065
2066
2067 //
2068 // .dsp - Switch to DSP assembler
2069 //
2070 int d_dsp(void)
2071 {
2072         if ((cursect != TEXT) && (cursect != DATA))
2073         {
2074                 error(".dsp can only be used in the TEXT or DATA segments");
2075                 return ERROR;
2076         }
2077
2078         // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
2079         if (!rdsp)
2080         {
2081                 orgactive = 0;
2082                 orgwarning = 0;
2083         }
2084
2085         rdsp = 1;                       // Set DSP assembly
2086         rgpu = 0;                       // Unset GPU assembly
2087         robjproc = 0;           // Unset OP assembly
2088         dsp56001 = 0;           // Unset 56001 assembly
2089
2090         regbase = regriscbase;  // Update register DFA tables
2091         regtab = regrisctab;
2092         regcheck = regrisccheck;
2093         regaccept = regriscaccept;
2094         //used_architectures |= MDSP;   // TODO: Should GPU/DSP have their own dedicated sections in the long run?
2095         return 0;
2096 }
2097
2098
2099 //
2100 // .cargs [#offset], symbol[.size], ...
2101 //
2102 // Lists of registers may also be mentioned; they just take up space. Good for
2103 // "documentation" purposes:
2104 //
2105 // .cargs a6, .arg1, .arg2, .arg3...
2106 //
2107 // Symbols thus created are ABS and EQUATED.
2108 //
2109 int d_cargs(void)
2110 {
2111         uint64_t eval = 4;      // Default to 4 if no offset specified (to account for
2112                                                 // return address)
2113         WORD rlist;
2114         SYM * symbol;
2115         char * p;
2116         int env;
2117         int i;
2118
2119         if (rgpu || rdsp)
2120                 return error("directive forbidden in gpu/dsp mode");
2121
2122         if (*tok == '#')
2123         {
2124                 tok++;
2125
2126                 if (abs_expr(&eval) != OK)
2127                         return 0;
2128
2129                 // Eat the comma, if it's there
2130                 if (*tok == ',')
2131                         tok++;
2132         }
2133
2134         for(;;)
2135         {
2136                 if (*tok == SYMBOL)
2137                 {
2138                         p = string[tok[1]];
2139
2140                         // Set env to either local (dot prefixed) or global scope
2141                         env = (*p == '.' ? curenv : 0);
2142                         symbol = lookup(p, LABEL, env);
2143
2144                         if (symbol == NULL)
2145                         {
2146                                 symbol = NewSymbol(p, LABEL, env);
2147                                 symbol->sattr = 0;
2148                         }
2149                         else if (symbol->sattr & DEFINED)
2150                                 return error("multiply-defined label '%s'", p);
2151
2152                         // Put symbol in "order of definition" list
2153                         AddToSymbolDeclarationList(symbol);
2154
2155                         symbol->sattr |= (ABS | DEFINED | EQUATED);
2156                         symbol->svalue = eval;
2157                         tok += 2;
2158
2159                         // What this does is eat any dot suffixes attached to a symbol. If
2160                         // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
2161                         // there is no dot suffix, it assumes a size of 2.
2162                         switch ((int)*tok)
2163                         {
2164                         case DOTL:
2165                                 eval += 2;
2166                         case DOTB:
2167                         case DOTW:
2168                                 tok++;
2169                         }
2170
2171                         eval += 2;
2172                 }
2173                 else if (*tok >= REG68_D0 && *tok <= REG68_A7)
2174                 {
2175                         if (reglist(&rlist) < 0)
2176                                 return 0;
2177
2178                         for(i=0; i<16; i++, rlist>>=1)
2179                         {
2180                                 if (rlist & 1)
2181                                         eval += 4;
2182                         }
2183                 }
2184                 else
2185                 {
2186                         switch ((int)*tok)
2187                         {
2188                         case REG68_USP:
2189                         case REG68_SSP:
2190                         case REG68_PC:
2191                                 eval += 2;
2192                                 // FALLTHROUGH
2193                         case REG68_SR:
2194                         case REG68_CCR:
2195                                 eval += 2;
2196                                 tok++;
2197                                 break;
2198                         case EOL:
2199                                 return 0;
2200                         default:
2201                                 return error(".cargs syntax");
2202                         }
2203                 }
2204
2205                 // Eat commas in between each argument, if they exist
2206                 if (*tok == ',')
2207                         tok++;
2208         }
2209 }
2210
2211
2212 //
2213 // .cstruct [#offset], symbol[.size], ...
2214 //
2215 // Lists of registers may also be mentioned; they just take up space. Good for
2216 // "documentation" purposes:
2217 //
2218 // .cstruct a6, .arg1, .arg2, .arg3...
2219 //
2220 // Symbols thus created are ABS and EQUATED. Note that this is for
2221 // compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
2222 // the suggestion.
2223 //
2224 int d_cstruct(void)
2225 {
2226         uint64_t eval = 0;      // Default, if no offset specified, is zero
2227         WORD rlist;
2228         SYM * symbol;
2229         char * symbolName;
2230         int env;
2231         int i;
2232
2233         if (rgpu || rdsp)
2234                 return error("directive forbidden in gpu/dsp mode");
2235
2236         if (*tok == '#')
2237         {
2238                 tok++;
2239
2240                 if (abs_expr(&eval) != OK)
2241                         return 0;
2242
2243                 // Eat the comma, if it's there
2244                 if (*tok == ',')
2245                         tok++;
2246         }
2247
2248         for(;;)
2249         {
2250                 if (*tok == SYMBOL)
2251                 {
2252                         symbolName = string[tok[1]];
2253
2254                         // Set env to either local (dot prefixed) or global scope
2255                         env = (symbolName[0] == '.' ? curenv : 0);
2256                         symbol = lookup(symbolName, LABEL, env);
2257
2258                         // If the symbol wasn't found, then define it. Otherwise, throw an
2259                         // error.
2260                         if (symbol == NULL)
2261                         {
2262                                 symbol = NewSymbol(symbolName, LABEL, env);
2263                                 symbol->sattr = 0;
2264                         }
2265                         else if (symbol->sattr & DEFINED)
2266                                 return error("multiply-defined label '%s'", symbolName);
2267
2268                         // Put symbol in "order of definition" list
2269                         AddToSymbolDeclarationList(symbol);
2270
2271                         tok += 2;
2272
2273                         // Adjust label start address if it's a word or a long, as a byte
2274                         // label might have left us on an odd address.
2275                         switch ((int)*tok)
2276                         {
2277                         case DOTW:
2278                         case DOTL:
2279                                 eval += eval & 0x01;
2280                         }
2281
2282                         symbol->sattr |= (ABS | DEFINED | EQUATED);
2283                         symbol->svalue = eval;
2284
2285                         // Check for dot suffixes and adjust space accordingly (longs and
2286                         // words on an odd boundary get bumped to the next word aligned
2287                         // address). If no suffix, then throw an error.
2288                         switch ((int)*tok)
2289                         {
2290                         case DOTL:
2291                                 eval += 4;
2292                                 break;
2293                         case DOTW:
2294                                 eval += 2;
2295                                 break;
2296                         case DOTB:
2297                                 eval += 1;
2298                                 break;
2299                         default:
2300                                 return error("Symbol missing dot suffix in .cstruct construct");
2301                         }
2302
2303                         tok++;
2304                 }
2305                 else if (*tok >= REG68_D0 && *tok <= REG68_A7)
2306                 {
2307                         if (reglist(&rlist) < 0)
2308                                 return 0;
2309
2310                         for(i=0; i<16; i++, rlist>>=1)
2311                         {
2312                                 if (rlist & 1)
2313                                         eval += 4;
2314                         }
2315                 }
2316                 else
2317                 {
2318                         switch ((int)*tok)
2319                         {
2320                         case REG68_USP:
2321                         case REG68_SSP:
2322                         case REG68_PC:
2323                                 eval += 2;
2324                                 // FALLTHROUGH
2325                         case REG68_SR:
2326                         case REG68_CCR:
2327                                 eval += 2;
2328                                 tok++;
2329                                 break;
2330                         case EOL:
2331                                 return 0;
2332                         default:
2333                                 return error(".cstruct syntax");
2334                         }
2335                 }
2336
2337                 // Eat commas in between each argument, if they exist
2338                 if (*tok == ',')
2339                         tok++;
2340         }
2341 }
2342
2343
2344 //
2345 // Define start of OP object list (allows the use of ORG)
2346 //
2347 int d_objproc(void)
2348 {
2349         if ((cursect != TEXT) && (cursect != DATA))
2350         {
2351                 error(".objproc can only be used in the TEXT or DATA segments");
2352                 return ERROR;
2353         }
2354
2355         // If previous section was DSP or 68000 then we need to reset ORG'd
2356         // Addresses
2357         if (!robjproc)
2358         {
2359                 orgactive = 0;
2360                 orgwarning = 0;
2361         }
2362
2363         robjproc = 1;           // Set OP assembly
2364         rgpu = 0;                       // Unset GPU assembly
2365         rdsp = 0;                       // Unset DSP assembly
2366         dsp56001 = 0;           // Unset 56001 assembly
2367         //used_architectures |= MOP;    // TODO: Should OP have its own dedicated section in the long run?
2368         return OK;
2369 }
2370
2371
2372 //
2373 // Undefine a macro - .undefmac macname [, macname...]
2374 //
2375 int undmac1(char * p)
2376 {
2377         SYM * symbol = lookup(p, MACRO, 0);
2378
2379         // If the macro symbol exists, cause it to disappear
2380         if (symbol != NULL)
2381                 symbol->stype = (BYTE)SY_UNDEF;
2382
2383         return OK;
2384 }
2385
2386
2387 int d_undmac(void)
2388 {
2389         symlist(undmac1);
2390         return 0;
2391 }
2392
2393
2394 int d_jpad(void)
2395 {
2396         warn("JPAD directive is deprecated/non-functional");
2397         return OK;
2398 }
2399
2400
2401 int d_nojpad(void)
2402 {
2403         warn("NOJPAD directive is deprecated/non-functional");
2404         return OK;
2405 }
2406
2407
2408 int d_gpumain(void)
2409 {
2410         return error("What the hell? Do you think we adhere to the Goof standard?");
2411 }
2412
2413
2414 //
2415 // .opt - turn a specific (or all) optimisation on or off
2416 //
2417 int d_opt(void)
2418 {
2419         while (*tok != EOL)
2420         {
2421                 if (*tok == STRING)
2422                 {
2423                         tok++;
2424                         char * tmpstr = string[*tok++];
2425
2426                         if (ParseOptimization(tmpstr) != OK)
2427                                 return error("unknown optimization flag '%s'", tmpstr);
2428                 }
2429                 else
2430                         return error(".opt directive needs every switch enclosed inside quotation marks");
2431         }
2432
2433         return OK;
2434 }
2435
2436
2437 //
2438 // .if, Start conditional assembly
2439 //
2440 int d_if(void)
2441 {
2442         WORD eattr;
2443         uint64_t eval;
2444         SYM * esym;
2445         IFENT * rif = f_ifent;
2446
2447         // Alloc an IFENTRY
2448         if (rif == NULL)
2449                 rif = (IFENT *)malloc(sizeof(IFENT));
2450         else
2451                 f_ifent = rif->if_prev;
2452
2453         rif->if_prev = ifent;
2454         ifent = rif;
2455
2456         if (!disabled)
2457         {
2458                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
2459                         return 0;
2460
2461                 if ((eattr & DEFINED) == 0)
2462                         return error(undef_error);
2463
2464                 disabled = !eval;
2465         }
2466
2467         rif->if_state = (WORD)disabled;
2468         return 0;
2469 }
2470
2471
2472 //
2473 // .else, Do alternate case for .if
2474 //
2475 int d_else(void)
2476 {
2477         IFENT * rif = ifent;
2478
2479         if (rif->if_prev == NULL)
2480                 return error("mismatched .else");
2481
2482         if (disabled)
2483                 disabled = rif->if_prev->if_state;
2484         else
2485                 disabled = 1;
2486
2487         rif->if_state = (WORD)disabled;
2488         return 0;
2489 }
2490
2491
2492 //
2493 // .endif, End of conditional assembly block
2494 // This is also called by fpop() to pop levels of IFENTs in case a macro or
2495 // include file exits early with `exitm' or `end'.
2496 //
2497 int d_endif(void)
2498 {
2499         IFENT * rif = ifent;
2500
2501         if (rif->if_prev == NULL)
2502                 return error("mismatched .endif");
2503
2504         ifent = rif->if_prev;
2505         disabled = rif->if_prev->if_state;
2506         rif->if_prev = f_ifent;
2507         f_ifent = rif;
2508         return 0;
2509 }
2510