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