]> Shamusworld >> Repos - rmac/blob - direct.c
15ce236287200236f9ce403ef7db7c5055144f65
[rmac] / direct.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // DIRECT.C - Directive Handling
4 // Copyright (C) 199x Landon Dyer, 2017 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 "sect.h"
11 #include "riscasm.h"
12 #include "error.h"
13 #include "token.h"
14 #include "procln.h"
15 #include "expr.h"
16 #include "mach.h"
17 #include "listing.h"
18 #include "mark.h"
19 #include "symbol.h"
20
21 #define DEF_KW
22 #include "kwtab.h"
23
24 TOKEN exprbuf[128];                     // Expression buffer
25 SYM * symbolPtr[1000000];       // Symbol pointers table
26 static long unused;                     // For supressing 'write' warnings
27 char buffer[256];                       // Scratch buffer for messages
28
29
30 // Directive handler table
31 int (*dirtab[])() = {
32         d_org,                          // 0 org
33         d_even,                         // 1 even
34         d_6502,                     // 2 .6502
35         d_68000,                        // 3 .68000
36         d_bss,                          // 4 bss
37         d_data,                         // 5 data
38         d_text,                         // 6 text
39         d_abs,                          // 7 abs
40         d_comm,                         // 8 comm
41         (void *)d_init,         // 9 init
42         d_cargs,                        // 10 cargs
43         (void *)d_goto,         // 11 goto
44         (void *)d_dc,           // 12 dc
45         (void *)d_ds,           // 13 ds
46         d_undmac,                       // 14 undefmac
47         d_gpu,                          // 15 .gpu
48         d_dsp,                          // 16 .dsp
49         (void *)d_dcb,          // 17 dcb
50         d_unimpl,                       // 18* set
51         d_unimpl,                       // 19* reg
52         d_unimpl,                       // 20 dump
53         d_incbin,                       // 21 .incbin //load
54         d_unimpl,                       // 22 disable
55         d_unimpl,                       // 23 enable
56         d_globl,                        // 24 globl
57         d_regbank0,                     // 25 .regbank0
58         d_regbank1,                     // 26 .regbank1
59         d_unimpl,                       // 27 xdef
60         d_assert,                       // 28 assert
61         d_unimpl,                       // 29* if
62         d_unimpl,                       // 30* endif
63         d_unimpl,                       // 31* endc
64         d_unimpl,                       // 32* iif
65         d_include,                      // 33 include
66         fpop,                           // 34 end
67         d_unimpl,                       // 35* macro
68         ExitMacro,                      // 36* exitm
69         d_unimpl,                       // 37* endm
70         d_list,                         // 38 list
71         d_nlist,                        // 39 nlist
72         d_long,                         // 40* rept
73         d_phrase,                       // 41* endr
74         d_dphrase,                      // 42 struct
75         d_qphrase,                      // 43 ends
76         d_title,                        // 44 title
77         d_subttl,                       // 45 subttl
78         eject,                          // 46 eject
79         d_error,                        // 47 error
80         d_warn,                         // 48 warn
81         d_noclear,                      // 49 .noclear
82         d_equrundef,            // 50 .equrundef/.regundef
83         d_ccundef,                      // 51 .ccundef
84         d_print,                        // 52 .print
85         d_cstruct,                      // 53 .cstruct
86         d_jpad,                         // 54 .jpad (deprecated)
87         d_nojpad,                       // 55 .nojpad (deprecated)
88         d_gpumain,                      // 56 .gpumain (deprecated)
89         d_prgflags,                     // 57 .prgflags
90         d_opt,                          // 58 .opt
91 };
92
93
94 //
95 // .error - Abort compilation, printing an error message
96 //
97 int d_error(char *str)
98 {
99         if (*tok == EOL)
100                 return error("error directive encountered - aborting assembling");
101         else
102         {
103                 switch(*tok)
104                 {
105                 case STRING:
106                         return error(string[tok[1]]);
107                         break;
108                 default:
109                         return error("error directive encountered - aborting assembling");
110                 }
111         }
112 }
113
114
115 //
116 // .warn - Just display a warning on screen
117 //
118 int d_warn(char *str)
119 {
120         if (*tok == EOL)
121                 return warn("WARNING WARNING WARNING");
122         else
123         {
124                 switch(*tok)
125                 {
126                 case STRING:
127                         return warn(string[tok[1]]);
128                         break;
129                 default:
130                         return warn("WARNING WARNING WARNING");
131                 }
132         }
133 }
134
135
136 //
137 // .org - Set origin
138 //
139 int d_org(void)
140 {
141     VALUE address;
142     
143     if (!rgpu && !rdsp && !m6502)
144         return error(".org permitted only in gpu/dsp and 6502 sections");
145     
146     if (rgpu | rdsp)
147     {
148         orgaddr = 0;
149
150         if (abs_expr(&address) == ERROR)
151         {
152             error("cannot determine org'd address");
153             return ERROR;
154         }
155
156         orgaddr = address;
157         orgactive = 1;
158         //printf("ORG: address = $%08X...\n", orgaddr);
159
160         return 0;
161     }
162     else
163     {
164         // 6502
165         // We also kludge `lsloc' so the listing generator doesn't
166         // try to spew out megabytes.
167             VALUE eval;
168
169             //if (m6502 == 0) return error(".org permitted only in .6502 section");
170             if (abs_expr(&eval) < 0) return 0;
171             if (eval >= 0x10000L) return error(range_error);
172
173         if (sloc != currentorg[0])
174         {
175             currentorg[1] = sloc;
176             currentorg += 2;
177         }
178
179         currentorg[0] = eval;
180             ch_size = 0;
181             lsloc = sloc = eval;
182             chptr = scode->chptr + eval;
183         orgactive = 1;
184         orgaddr = eval;
185             at_eol();
186         return 0;
187     }
188 }
189
190
191 //
192 // Print directive
193 //
194 int d_print(void)
195 {
196         char prntstr[LNSIZ];            // String for PRINT directive
197         char format[LNSIZ];                     // Format for PRINT directive
198         int formatting = 0;                     // Formatting on/off
199         int wordlong = 0;                       // WORD = 0, LONG = 1
200         int outtype = 0;                        // 0:hex, 1:decimal, 2:unsigned
201
202         VALUE eval;                                     // Expression value
203         WORD eattr;                                     // Expression attributes
204         SYM * esym;                                     // External symbol involved in expr.
205         TOKEN r_expr[EXPRSIZE];
206
207         while (*tok != EOL)
208         {
209                 switch(*tok)
210                 {
211                 case STRING:
212                         sprintf(prntstr, "%s", string[tok[1]]);
213                         printf("%s", prntstr);
214
215                         if (list_fd)
216                                 unused = write(list_fd, prntstr, (LONG)strlen(prntstr));
217
218                         tok += 2;
219                         break;
220                 case '/':
221                         formatting = 1;
222
223                         if (tok[1] != SYMBOL)
224                                 goto token_err;
225
226 //                      strcpy(prntstr, (char *)tok[2]);
227                         strcpy(prntstr, string[tok[2]]);
228
229                         switch(prntstr[0])
230                         {
231                         case 'l': case 'L': wordlong = 1; break;
232                         case 'w': case 'W': wordlong = 0; break;
233                         case 'x': case 'X': outtype  = 0; break;
234                         case 'd': case 'D': outtype  = 1; break;
235                         case 'u': case 'U': outtype  = 2; break;
236                         default:
237                                 error("unknown print format flag");
238                                 return ERROR;
239                         }
240
241                         tok += 3;
242                         break;
243                 case ',':
244                         tok++;
245                         break;
246                 default:
247                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
248                                 goto token_err;
249                         else
250                         {
251                                 switch(outtype)
252                                 {
253                                 case 0: strcpy(format, "%X"); break;
254                                 case 1: strcpy(format, "%d" ); break;
255                                 case 2: strcpy(format, "%u" ); break;
256                                 }
257
258                                 if (wordlong)
259                                         sprintf(prntstr, format, eval);
260                                 else
261                                         sprintf(prntstr, format, eval & 0xFFFF);
262
263                                 printf("%s", prntstr);
264
265                                 if (list_fd)
266                                         unused = write(list_fd, prntstr, (LONG)strlen(prntstr));
267
268                                 formatting = 0;
269                                 wordlong = 0;
270                                 outtype = 0;
271                         }
272
273                         break;
274                 }
275         }
276
277         printf("\n");
278
279         return 0;
280
281 token_err:
282         error("illegal print token");
283         return ERROR;
284 }
285
286
287 //
288 // Undefine an equated condition code
289 //
290 int d_ccundef(void)
291 {
292         SYM * ccname;
293
294         // Check that we are in a RISC section
295         if (!rgpu && !rdsp)
296         {
297                 error(".ccundef must be defined in .gpu/.dsp section");
298                 return ERROR;
299         }
300
301         if (*tok != SYMBOL)
302         {
303                 error("syntax error; expected symbol");
304                 return ERROR;
305         }
306
307         ccname = lookup(string[tok[1]], LABEL, 0);
308
309         // Make sure symbol is a valid ccdef
310         if (!ccname || !(ccname->sattre & EQUATEDCC))
311         {
312                 error("invalid equated condition name specified");
313                 return ERROR;
314         }
315
316         ccname->sattre |= UNDEF_CC;
317
318         return 0;
319 }
320
321
322 //
323 // Undefine an equated register
324 //
325 int d_equrundef(void)
326 {
327         SYM * regname;
328
329         // Check that we are in a RISC section
330         if (!rgpu && !rdsp)
331                 return error(".equrundef/.regundef must be defined in .gpu/.dsp section");
332
333         while (*tok != EOL)
334         {
335                 // Skip preceeding or seperating commas (if any)
336                 if (*tok == ',')
337                         tok++;
338
339                 // Check we are dealing with a symbol
340                 if (*tok != SYMBOL)
341                         return error("syntax error; expected symbol");
342
343                 // Lookup and undef if equated register
344                 regname = lookup(string[tok[1]], LABEL, 0);
345
346                 if (regname && (regname->sattre & EQUATEDREG))
347                 {
348                         // Reset the attributes of this symbol...
349                         regname->sattr = 0;
350                         regname->sattre &= ~(EQUATEDREG | BANK_0 | BANK_1);
351                         regname->sattre |= UNDEF_EQUR;
352                 }
353
354                 // Skip over symbol token and address
355                 tok += 2;
356         }
357
358         return 0;
359 }
360
361
362 //
363 // Do not allow use of the CLR.L opcode
364 //
365 int d_noclear(void)
366 {
367         warn("CLR.L opcode ignored...");
368         return 0;
369 }
370
371
372 //
373 // Include binary file
374 //
375 int d_incbin(void)
376 {
377         int fd;
378         int bytes = 0;
379         long pos, size, bytesRead;
380         char msg[256];
381         char buf1[256];
382         int i;
383
384         // Check to see if we're in BSS, and, if so, throw an error
385         if (scattr & SBSS)
386         {
387                 errors("cannot include binary file \"%s\" in BSS section", string[tok[1]]);
388                 return ERROR;
389         }
390
391         if (*tok != STRING)
392         {
393                 error("syntax error; string missing");
394                 return ERROR;
395         }
396
397         // Attempt to open the include file in the current directory, then (if that
398         // failed) try list of include files passed in the enviroment string or by
399         // the "-d" option.
400         if ((fd = open(string[tok[1]], _OPEN_INC)) < 0)
401         {
402                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
403                 {
404                         fd = strlen(buf1);
405
406                         // Append path char if necessary
407                         if (fd > 0 && buf1[fd - 1] != SLASHCHAR)
408                                 strcat(buf1, SLASHSTRING);
409
410                         strcat(buf1, string[tok[1]]);
411
412                         if ((fd = open(buf1, _OPEN_INC)) >= 0)
413                                 goto allright;
414                 }
415
416                 return errors("cannot open: \"%s\"", string[tok[1]]);
417         }
418
419 allright:
420
421         size = lseek(fd, 0L, SEEK_END);
422         pos = lseek(fd, 0L, SEEK_SET);
423         chcheck(size);
424
425         DEBUG { printf("INCBIN: File '%s' is %li bytes.\n", string[tok[1]], size); }
426
427         char * fileBuffer = (char *)malloc(size);
428         bytesRead = read(fd, fileBuffer, size);
429
430         if (bytesRead != size)
431         {
432                 sprintf(msg, "was only able to read %li bytes from binary file (%s, %li bytes)", bytesRead, string[tok[1]], size);
433                 error(msg);
434                 return ERROR;
435         }
436
437         memcpy(chptr, fileBuffer, size);
438         chptr += size;
439         sloc += size;
440         ch_size += size;
441
442         if (orgactive)
443                 orgaddr += size;
444
445         free(fileBuffer);
446         close(fd);
447         return 0;
448 }
449
450
451 //
452 // Set RISC register banks
453 //
454 int d_regbank0(void)
455 {
456         // Set active register bank zero
457         regbank = BANK_0;
458         return 0;
459 }
460
461
462 int d_regbank1(void)
463 {
464         // Set active register bank one
465         regbank = BANK_1;
466         return 0;
467 }
468
469
470 //
471 // Helper function, to cut down on mistakes & typing
472 //
473 static inline void SkipBytes(unsigned bytesToSkip)
474 {
475         if (!bytesToSkip)
476                 return;
477
478         if ((scattr & SBSS) == 0)
479         {
480                 chcheck(bytesToSkip);
481                 D_ZEROFILL(bytesToSkip);
482         }
483         else
484         {
485                 sloc += bytesToSkip;
486
487                 if (orgactive)
488                         orgaddr += bytesToSkip;
489         }
490 }
491
492
493 //
494 // Adjust location to an EVEN value
495 //
496 int d_even(void)
497 {
498     if (m6502)
499         return error(in_6502mode);
500
501         unsigned skip = (rgpu || rdsp ? orgaddr : sloc) & 0x01;
502
503         if (skip)
504         {
505                 if ((scattr & SBSS) == 0)
506                 {
507                         chcheck(1);
508                         D_byte(0);
509                 }
510                 else
511                 {
512                         sloc++;
513
514                         if (orgactive)
515                                 orgaddr++;
516                 }
517         }
518
519         return 0;
520 }
521
522
523 //
524 // Adjust location to a LONG value
525 //
526 int d_long(void)
527 {
528         unsigned lower2Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x03;
529         unsigned bytesToSkip = (0x04 - lower2Bits) & 0x03;
530         SkipBytes(bytesToSkip);
531
532         return 0;
533 }
534
535
536 //
537 // Adjust location to a PHRASE value
538 //
539 // N.B.: We have to handle the GPU/DSP cases separately because you can embed
540 //       RISC code in the middle of a regular 68K section. Also note that all
541 //       of the alignment pseudo-ops will have to be fixed this way.
542 //
543 // This *must* behave differently when in a RISC section, as following sloc
544 // (instead of orgaddr) will fuck things up royally. Note that we do it this
545 // way because you can embed RISC code in a 68K section, and have the origin
546 // pointing to a different alignment in the RISC section than the 68K section.
547 //
548 int d_phrase(void)
549 {
550         unsigned lower3Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x07;
551         unsigned bytesToSkip = (0x08 - lower3Bits) & 0x07;
552         SkipBytes(bytesToSkip);
553
554         return 0;
555 }
556
557
558 //
559 // Adjust location to a DPHRASE value
560 //
561 int d_dphrase(void)
562 {
563         unsigned lower4Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x0F;
564         unsigned bytesToSkip = (0x10 - lower4Bits) & 0x0F;
565         SkipBytes(bytesToSkip);
566
567         return 0;
568 }
569
570
571 //
572 // Adjust location to a QPHRASE value
573 //
574 int d_qphrase(void)
575 {
576         unsigned lower5Bits = (rgpu || rdsp ? orgaddr : sloc) & 0x1F;
577         unsigned bytesToSkip = (0x20 - lower5Bits) & 0x1F;
578         SkipBytes(bytesToSkip);
579
580         return 0;
581 }
582
583
584 //
585 // Do auto-even.  This must be called ONLY if 'sloc' is odd.
586 //
587 // This is made hairy because, if there was a label on the line, we also have
588 // to adjust its value. This won't work with more than one label on the line,
589 // which is OK since multiple labels are only allowed in AS68 kludge mode, and
590 // the C compiler is VERY paranoid and uses ".even" whenever it can
591 //
592 // N.B.: This probably needs the same fixes as above...
593 //
594 void auto_even(void)
595 {
596   if (cursect != M6502)
597   {    
598         if (scattr & SBSS)
599                 sloc++;                         // Bump BSS section
600         else
601                 D_byte(0);                      // Deposit 0.b in non-BSS
602
603         if (lab_sym != NULL)    // Bump label if we have to
604                 lab_sym->svalue++;
605   }
606 }
607
608
609 //
610 // Unimplemened directive error
611 //
612 int d_unimpl(void)
613 {
614         return error("unimplemented directive");
615 }
616
617
618 //
619 // Return absolute (not TDB) and defined expression or return an error
620 //
621 int abs_expr(VALUE * a_eval)
622 {
623         WORD eattr;
624
625         if (expr(exprbuf, a_eval, &eattr, NULL) < 0)
626                 return ERROR;
627
628         if (!(eattr & DEFINED))
629                 return error(undef_error);
630
631         if (eattr & TDB)
632                 return error(rel_error);
633
634         return OK;
635 }
636
637
638 //
639 // Hand symbols in a symbol-list to a function (kind of like mapcar...)
640 //
641 int symlist(int(* func)())
642 {
643         const char * em = "symbol list syntax";
644
645         for(;;)
646         {
647                 if (*tok != SYMBOL)
648                         return error(em);
649
650                 if ((*func)(string[tok[1]]) != OK)
651                         break;
652
653                 tok += 2;
654
655                 if (*tok == EOL)
656                         break;
657
658                 if (*tok != ',')
659                         return error(em);
660
661                 tok++;
662         }
663
664         return 0;
665 }
666
667
668 //
669 // .include "filename"
670 //
671 int d_include(void)
672 {
673         int j;
674         int i;
675         char * fn;
676         char buf[128];
677         char buf1[128];
678
679         if (*tok == STRING)                     // Leave strings ALONE
680                 fn = string[*++tok];
681         else if (*tok == SYMBOL)        // Try to append ".s" to symbols
682         {
683                 strcpy(buf, string[*++tok]);
684                 fext(buf, ".s", 0);
685                 fn = &buf[0];
686         }
687         else                                            // Punt if no STRING or SYMBOL
688                 return error("missing filename");
689
690         // Make sure the user didn't try anything like:
691         // .include equates.s
692         if (*++tok != EOL)
693                 return error("extra stuff after filename -- enclose it in quotes");
694
695         // Attempt to open the include file in the current directory, then (if that
696         // failed) try list of include files passed in the enviroment string or by
697         // the "-i" option.
698         if ((j = open(fn, 0)) < 0)
699         {
700                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
701                 {
702                         j = strlen(buf1);
703
704                         // Append path char if necessary
705                         if (j > 0 && buf1[j - 1] != SLASHCHAR)
706                                 strcat(buf1, SLASHSTRING);
707
708                         strcat(buf1, fn);
709
710                         if ((j = open(buf1, 0)) >= 0)
711                                 goto allright;
712                 }
713
714                 return errors("cannot open: \"%s\"", fn);
715         }
716
717 allright:
718         include(j, fn);
719         return 0;
720 }
721
722
723 //
724 // .assert expression [, expression...]
725 //
726 int d_assert(void)
727 {
728         WORD eattr;
729         VALUE eval;
730
731         for(; expr(exprbuf, &eval, &eattr, NULL)==OK; ++tok)
732         {
733                 if (!(eattr & DEFINED))
734                         return error("forward or undefined .assert");
735
736                 if (!eval)
737                         return error("assert failure");
738
739                 if (*tok != ',')
740                         break;
741         }
742
743         at_eol();
744         return 0;
745 }
746
747
748 //
749 // .globl symbol [, symbol] <<<cannot make local symbols global>>>
750 //
751 int globl1(char * p)
752 {
753         SYM * sy;
754
755         if (*p == '.')
756                 return error("cannot .globl local symbol");
757
758         if ((sy = lookup(p, LABEL, 0)) == NULL)
759         {
760                 sy = NewSymbol(p, LABEL, 0);
761                 sy->svalue = 0;
762                 sy->sattr = GLOBAL;
763 //printf("glob1: Making global symbol: attr=%04X, eattr=%08X, %s\n", sy->sattr, sy->sattre, sy->sname);
764         }
765         else
766                 sy->sattr |= GLOBAL;
767
768         return OK;
769 }
770
771
772 int d_globl(void)
773 {
774   if (m6502)
775     return error(in_6502mode);
776
777         symlist(globl1);
778         return 0;
779 }
780
781
782 //
783 // .prgflags expression
784 //
785 int d_prgflags(void)
786 {
787         VALUE eval;
788
789         if (*tok == EOL)
790                 return error("PRGFLAGS requires value");
791         else if (abs_expr(&eval) == OK)
792         {
793                 PRGFLAGS=eval;
794                 return 0;
795         }
796         else
797         {
798                 return error("PRGFLAGS requires value");
799         }
800 }
801
802
803 //
804 // .abs [expression]
805 //
806 int d_abs(void)
807 {
808         VALUE eval;
809
810     if (m6502)
811         return error(in_6502mode);
812     
813         SaveSection();
814
815         if (*tok == EOL)
816                 eval = 0;
817         else if (abs_expr(&eval) != OK)
818                 return 0;
819
820         SwitchSection(ABS);
821         sloc = eval;
822         return 0;
823 }
824
825
826 //
827 // Switch segments
828 //
829 int d_text(void)
830 {
831         if (rgpu || rdsp)
832                 return error("directive forbidden in gpu/dsp mode");
833     if (m6502)
834         return error(in_6502mode);
835
836         if (cursect != TEXT)
837         {
838                 SaveSection();
839                 SwitchSection(TEXT);
840         }
841
842         return 0;
843 }
844
845
846 int d_data(void)
847 {
848         if (rgpu || rdsp)
849                 return error("directive forbidden in gpu/dsp mode");
850     if (m6502)
851         return error(in_6502mode);
852
853         if (cursect != DATA)
854         {
855                 SaveSection();
856                 SwitchSection(DATA);
857         }
858
859         return 0;
860 }
861
862
863 int d_bss(void)
864 {
865         if (rgpu || rdsp)
866                 return error("directive forbidden in gpu/dsp mode");
867     if (m6502)
868         return error(in_6502mode);
869
870         if (cursect != BSS)
871         {
872                 SaveSection();
873                 SwitchSection(BSS);
874         }
875
876         return 0;
877 }
878
879
880 //
881 // .ds[.size] expression
882 //
883 int d_ds(WORD siz)
884 {
885         DEBUG { printf("Directive: .ds.[size] = %u, sloc = $%X\n", siz, sloc); }
886
887         VALUE eval;
888
889     if (cursect != M6502)
890     {
891             if ((siz != SIZB) && (sloc & 1))    // Automatic .even
892                     auto_even();
893     }
894
895         if (abs_expr(&eval) != OK)
896                 return 0;
897
898         // Check to see if the value being passed in is negative (who the hell does
899         // that?--nobody does; it's the code gremlins, or rum, that does it)
900         if (eval < 0)
901                 return error("negative sizes not allowed");
902
903         // In non-TDB section (BSS, ABS and M6502) just advance the location
904         // counter appropriately. In TDB sections, deposit (possibly large) chunks
905         // of zeroed memory....
906         if ((scattr & SBSS) || cursect == M6502)
907         {
908                 listvalue(eval);
909                 eval *= siz;
910                 sloc += eval;
911         if (cursect == M6502) chptr += eval;
912                 just_bss = 1;                                   // No data deposited (8-bit CPU mode)
913         }
914         else
915         {
916                 dep_block(eval, siz, (VALUE)0, (WORD)(DEFINED | ABS), NULL);
917         }
918
919         at_eol();
920         return 0;
921 }
922
923
924 //
925 // dc.b, dc.w / dc, dc.l, dc.i
926 //
927 int d_dc(WORD siz)
928 {
929         WORD eattr;
930         VALUE eval;
931         uint8_t * p;
932
933         if ((scattr & SBSS) != 0)
934                 return error("illegal initialization of section");
935
936         // Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
937         if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
938                 auto_even();
939
940         // Check to see if we're trying to set LONGS on a non 32-bit aligned
941         // address in a GPU or DSP section, in their local RAM
942         if ((siz == SIZL) && (orgaddr & 0x03)
943                 && ((rgpu && (orgaddr >= 0xF03000) && (orgaddr <= 0xF03FFFF))
944                 || (rdsp && (orgaddr >= 0xF1B000) && (orgaddr <= 0xF1CFFFF))))
945                 warn("depositing LONGs on a non-long address in local RAM");
946
947         for(;; tok++)
948         {
949                 // dc.b 'string' [,] ...
950                 if (siz == SIZB && *tok == STRING && (tok[2] == ',' || tok[2] == EOL))
951                 {
952                         uint32_t i = strlen(string[tok[1]]);
953
954                         if ((challoc - ch_size) < i)
955                                 chcheck(i);
956
957                         for(p=string[tok[1]]; *p!=EOS; p++)
958                                 D_byte(*p);
959
960                         tok += 2;
961                         goto comma;
962                 }
963
964                 int movei = 0; // MOVEI flag for dc.i
965
966                 if (*tok == DOTI)
967                 {
968                         movei = 1;
969                         tok++;
970                         siz = SIZL;
971                 }
972
973                 // dc.x <expression>
974                 SYM * esym = 0;
975
976                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
977                         return 0;
978
979                 uint16_t tdb = eattr & TDB;
980                 uint16_t defined = eattr & DEFINED;
981
982                 if ((challoc - ch_size) < 4)
983                         chcheck(4);
984
985                 switch (siz)
986                 {
987                 case SIZB:
988                         if (!defined)
989                         {
990                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
991                                 D_byte(0);
992                         }
993                         else
994                         {
995                                 if (eval + 0x100 >= 0x200)
996                                 {
997                                         sprintf(buffer, "%s (value = $%X)", range_error, eval);
998                                         return error(buffer);
999                                 }
1000
1001                                 if (tdb)
1002                                         return error("non-absolute byte value");
1003
1004                                 D_byte(eval);
1005                         }
1006
1007                         break;
1008                 case SIZW:
1009                 case SIZN:
1010                         if (!defined)
1011                         {
1012                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1013                                 D_word(0);
1014                         }
1015                         else
1016                         {
1017                                 if (eval + 0x10000 >= 0x20000)
1018                                         return error(range_error);
1019
1020                                 if (tdb)
1021                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1022
1023                                 // Deposit 68000 or 6502 (byte-reversed) word
1024                     if (cursect != M6502)
1025                         {
1026                             D_word(eval);
1027                         }
1028                     else
1029                         {
1030                             D_rword(eval);
1031                         }
1032         
1033                         }
1034
1035                         break;
1036                 case SIZL:
1037                 if (m6502)
1038                     return error(in_6502mode);
1039
1040                         if (!defined)
1041                         {
1042                                 if (movei)
1043                                         AddFixup(FU_LONG | FU_MOVEI, sloc, exprbuf);
1044                                 else
1045                                         AddFixup(FU_LONG, sloc, exprbuf);
1046
1047                                 D_long(0);
1048                         }
1049                         else
1050                         {
1051                                 if (tdb)
1052                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1053
1054                                 if (movei)
1055                                         eval = WORDSWAP32(eval);
1056
1057                                 D_long(eval);
1058                         }
1059                         break;
1060                 }
1061
1062 comma:
1063                 if (*tok != ',')
1064                         break;
1065         }
1066
1067         at_eol();
1068         return 0;
1069 }
1070
1071
1072 //
1073 // dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2'
1074 //
1075 int d_dcb(WORD siz)
1076 {
1077         VALUE evalc, eval;
1078         WORD eattr;
1079
1080         DEBUG { printf("dcb: section is %s%s%s (scattr=$%X)\n", (cursect & TEXT ? "TEXT" : ""), (cursect & DATA ? " DATA" : ""), (cursect & BSS ? "BSS" : ""), scattr); }
1081
1082         if ((scattr & SBSS) != 0)
1083                 return error("illegal initialization of section");
1084
1085         if (abs_expr(&evalc) != OK)
1086                 return 0;
1087
1088         if (*tok++ != ',')
1089                 return error("missing comma");
1090
1091         if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1092                 return 0;
1093
1094         if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
1095                 auto_even();
1096
1097         dep_block(evalc, siz, eval, eattr, exprbuf);
1098         return 0;
1099 }
1100
1101
1102 //
1103 // Generalized initialization directive
1104 //
1105 // .init[.siz] [#count,] expression [.size] , ...
1106 //
1107 // The size suffix on the ".init" directive becomes the default size of the
1108 // objects to deposit. If an item is preceeded with a sharp (immediate) sign
1109 // and an expression, it specifies a repeat count. The value to be deposited
1110 // may be followed by a size suffix, which overrides the default size.
1111 //
1112 int d_init(WORD def_siz)
1113 {
1114         VALUE count;
1115         VALUE eval;
1116         WORD eattr;
1117         WORD siz;
1118
1119         if ((scattr & SBSS) != 0)
1120                 return error(".init not permitted in BSS or ABS");
1121
1122         if (rgpu || rdsp)
1123                 return error("directive forbidden in gpu/dsp mode");
1124
1125         for(;;)
1126         {
1127                 // Get repeat count (defaults to 1)
1128                 if (*tok == '#')
1129                 {
1130                         ++tok;
1131
1132                         if (abs_expr(&count) != OK)
1133                                 return 0;
1134
1135                         if (*tok++ != ',')
1136                                 return error(comma_error);
1137                 }
1138                 else
1139                         count = 1;
1140
1141                 // Evaluate expression to deposit
1142                 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1143                         return 0;
1144
1145                 switch ((int)*tok++)
1146                 {                                 // Determine size of object to deposit
1147                 case DOTB: siz = SIZB; break;
1148                 case DOTW: siz = SIZB; break;
1149                 case DOTL: siz = SIZL; break;
1150                 default:
1151                         siz = def_siz;
1152                         tok--;
1153                         break;
1154                 }
1155
1156                 dep_block(count, siz, eval, eattr, exprbuf);
1157
1158                 switch ((int)*tok)
1159                 {
1160                 case EOL:
1161                         return 0;
1162                 case ',':
1163                         tok++;
1164                         continue;
1165                 default:
1166                         return error(comma_error);
1167                 }
1168         }
1169 }
1170
1171
1172 //
1173 // Deposit 'count' values of size 'siz' in the current (non-BSS) segment
1174 //
1175 int dep_block(VALUE count, WORD siz, VALUE eval, WORD eattr, TOKEN * exprbuf)
1176 {
1177         WORD tdb;
1178         WORD defined;
1179
1180         tdb = (WORD)(eattr & TDB);
1181         defined = (WORD)(eattr & DEFINED);
1182
1183         while (count--)
1184         {
1185                 if ((challoc - ch_size) < 4)
1186                         chcheck(4L);
1187
1188                 switch(siz)
1189                 {
1190                 case SIZB:
1191                         if (!defined)
1192                         {
1193                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1194                                 D_byte(0);
1195                         }
1196                         else
1197                         {
1198                                 if (tdb)
1199                                         return error("non-absolute byte value");
1200
1201                                 if (eval + 0x100 >= 0x200)
1202                                         return error(range_error);
1203
1204                                 D_byte(eval);
1205                         }
1206
1207                         break;
1208                 case SIZW:
1209                 case SIZN:
1210                         if (!defined)
1211                         {
1212                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1213                                 D_word(0);
1214                         }
1215                         else
1216                         {
1217                                 if (tdb)
1218                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
1219
1220                                 if (eval + 0x10000 >= 0x20000)
1221                                         return error(range_error);
1222
1223                                 // Deposit 68000 or 6502 (byte-reversed) word
1224                                 if (cursect != M6502)
1225                                 {
1226                                         D_word(eval);
1227                                 }
1228                                 else
1229                                 {
1230                                         D_rword(eval);
1231                                 }
1232
1233                         }
1234
1235                         break;
1236                 case SIZL:
1237                         if (m6502)
1238                                 return error(in_6502mode);
1239             
1240                         if (!defined)
1241                         {
1242                                 AddFixup(FU_LONG, sloc, exprbuf);
1243                                 D_long(0);
1244                         }
1245                         else
1246                         {
1247                                 if (tdb)
1248                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
1249
1250                                 D_long(eval);
1251                         }
1252
1253                         break;
1254                 }
1255         }
1256
1257         return 0;
1258 }
1259
1260
1261 //
1262 // .comm symbol, size
1263 //
1264 int d_comm(void)
1265 {
1266         SYM * sym;
1267         char * p;
1268         VALUE eval;
1269
1270         if (m6502)
1271                 return error(in_6502mode);
1272
1273         if (*tok != SYMBOL)
1274                 return error("missing symbol");
1275
1276         p = string[tok[1]];
1277         tok += 2;
1278
1279         if (*p == '.')                                                  // Cannot .comm a local symbol
1280                 return error(locgl_error);
1281
1282         if ((sym = lookup(p, LABEL, 0)) == NULL)
1283                 sym = NewSymbol(p, LABEL, 0);
1284         else
1285         {
1286                 if (sym->sattr & DEFINED)
1287                         return error(".comm symbol already defined");
1288         }
1289
1290         sym->sattr = GLOBAL | COMMON | BSS;
1291
1292         if (*tok++ != ',')
1293                 return error(comma_error);
1294
1295         if (abs_expr(&eval) != OK)                              // Parse size of common region
1296                 return 0;
1297
1298         sym->svalue = eval;                                             // Install common symbol's size
1299         at_eol();
1300         return 0;
1301 }
1302
1303
1304 //
1305 // .list - Turn listing on
1306 //
1307 int d_list(void)
1308 {
1309         if (list_flag)
1310                 listing++;
1311
1312         return 0;
1313 }
1314
1315
1316 //
1317 // .nlist - Turn listing off
1318 //
1319 int d_nlist(void)
1320 {
1321         if (list_flag)
1322                 listing--;
1323
1324         return 0;
1325 }
1326
1327
1328 //
1329 // .68000 - Back to 68000 TEXT segment
1330 //
1331 int d_68000(void)
1332 {
1333         rgpu = rdsp = 0;
1334         // Switching from gpu/dsp sections should reset any ORG'd Address
1335         orgactive = 0;
1336         orgwarning = 0;
1337         SaveSection();
1338         SwitchSection(TEXT);
1339         return 0;
1340 }
1341
1342
1343 //
1344 // .gpu - Switch to GPU assembler
1345 //
1346 int d_gpu(void)
1347 {
1348         if ((cursect != TEXT) && (cursect != DATA))
1349         {
1350                 error(".gpu can only be used in the TEXT or DATA segments");
1351                 return ERROR;
1352         }
1353
1354         // If previous section was dsp or 68000 then we need to reset ORG'd Addresses
1355         if (!rgpu)
1356         {
1357 //printf("Resetting ORG...\n");
1358                 orgactive = 0;
1359                 orgwarning = 0;
1360         }
1361 //else printf("NOT resetting ORG!\n");
1362
1363         rgpu = 1;                       // Set GPU assembly
1364         rdsp = 0;                       // Unset DSP assembly
1365         regbank = BANK_N;       // Set no default register bank
1366         return 0;
1367 }
1368
1369
1370 //
1371 // .dsp - Switch to DSP assembler
1372 //
1373 int d_dsp(void)
1374 {
1375         if ((cursect != TEXT) && (cursect != DATA))
1376         {
1377                 error(".dsp can only be used in the TEXT or DATA segments");
1378                 return ERROR;
1379         }
1380
1381         // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
1382         if (!rdsp)
1383         {
1384                 orgactive = 0;
1385                 orgwarning = 0;
1386         }
1387
1388         rdsp = 1;                       // Set DSP assembly
1389         rgpu = 0;                       // Unset GPU assembly
1390         regbank = BANK_N;       // Set no default register bank
1391         return 0;
1392 }
1393
1394
1395 //
1396 // .cargs [#offset], symbol[.size], ...
1397 //
1398 // Lists of registers may also be mentioned; they just take up space. Good for
1399 // "documentation" purposes:
1400 //
1401 // .cargs a6, .arg1, .arg2, .arg3...
1402 //
1403 // Symbols thus created are ABS and EQUATED.
1404 //
1405 int d_cargs(void)
1406 {
1407         VALUE eval = 4;         // Default to 4 if no offset specified (to account for
1408                                                 // return address)
1409         WORD rlist;
1410         SYM * symbol;
1411         char * p;
1412         int env;
1413         int i;
1414
1415         if (rgpu || rdsp)
1416                 return error("directive forbidden in gpu/dsp mode");
1417
1418         if (*tok == '#')
1419         {
1420                 tok++;
1421
1422                 if (abs_expr(&eval) != OK)
1423                         return 0;
1424
1425                 // Eat the comma, if it's there
1426                 if (*tok == ',')
1427                         tok++;
1428         }
1429
1430         for(;;)
1431         {
1432                 if (*tok == SYMBOL)
1433                 {
1434                         p = string[tok[1]];
1435
1436                         // Set env to either local (dot prefixed) or global scope
1437                         env = (*p == '.' ? curenv : 0);
1438                         symbol = lookup(p, LABEL, env);
1439
1440                         if (symbol == NULL)
1441                         {
1442                                 symbol = NewSymbol(p, LABEL, env);
1443                                 symbol->sattr = 0;
1444                         }
1445                         else if (symbol->sattr & DEFINED)
1446                                 return errors("multiply-defined label '%s'", p);
1447
1448                         // Put symbol in "order of definition" list
1449                         AddToSymbolDeclarationList(symbol);
1450
1451                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1452                         symbol->svalue = eval;
1453                         tok += 2;
1454
1455                         // What this does is eat any dot suffixes attached to a symbol. If
1456                         // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
1457                         // there is no dot suffix, it assumes a size of 2.
1458                         switch ((int)*tok)
1459                         {
1460                         case DOTL:
1461                                 eval += 2;
1462                         case DOTB:
1463                         case DOTW:
1464                                 tok++;
1465                         }
1466
1467                         eval += 2;
1468                 }
1469                 else if (*tok >= KW_D0 && *tok <= KW_A7)
1470                 {
1471                         if (reglist(&rlist) < 0)
1472                                 return 0;
1473
1474                         for(i=0; i<16; i++, rlist>>=1)
1475                         {
1476                                 if (rlist & 1)
1477                                         eval += 4;
1478                         }
1479                 }
1480                 else
1481                 {
1482                         switch ((int)*tok)
1483                         {
1484                         case KW_USP:
1485                         case KW_SSP:
1486                         case KW_PC:
1487                                 eval += 2;
1488                                 // FALLTHROUGH
1489                         case KW_SR:
1490                         case KW_CCR:
1491                                 eval += 2;
1492                                 tok++;
1493                                 break;
1494                         case EOL:
1495                                 return 0;
1496                         default:
1497                                 return error(".cargs syntax");
1498                         }
1499                 }
1500
1501                 // Eat commas in between each argument, if they exist
1502                 if (*tok == ',')
1503                         tok++;
1504         }
1505 }
1506
1507
1508 //
1509 // .cstruct [#offset], symbol[.size], ...
1510 //
1511 // Lists of registers may also be mentioned; they just take up space. Good for
1512 // "documentation" purposes:
1513 //
1514 // .cstruct a6, .arg1, .arg2, .arg3...
1515 //
1516 // Symbols thus created are ABS and EQUATED. Note that this is for
1517 // compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
1518 // the suggestion.
1519 //
1520 int d_cstruct(void)
1521 {
1522         VALUE eval = 0;         // Default, if no offset specified, is zero
1523         WORD rlist;
1524         SYM * symbol;
1525         char * symbolName;
1526         int env;
1527         int i;
1528
1529         if (rgpu || rdsp)
1530                 return error("directive forbidden in gpu/dsp mode");
1531
1532         if (*tok == '#')
1533         {
1534                 tok++;
1535
1536                 if (abs_expr(&eval) != OK)
1537                         return 0;
1538
1539                 // Eat the comma, if it's there
1540                 if (*tok == ',')
1541                         tok++;
1542         }
1543
1544         for(;;)
1545         {
1546                 if (*tok == SYMBOL)
1547                 {
1548                         symbolName = string[tok[1]];
1549
1550                         // Set env to either local (dot prefixed) or global scope
1551                         env = (symbolName[0] == '.' ? curenv : 0);
1552                         symbol = lookup(symbolName, LABEL, env);
1553
1554                         // If the symbol wasn't found, then define it. Otherwise, throw an
1555                         // error.
1556                         if (symbol == NULL)
1557                         {
1558                                 symbol = NewSymbol(symbolName, LABEL, env);
1559                                 symbol->sattr = 0;
1560                         }
1561                         else if (symbol->sattr & DEFINED)
1562                                 return errors("multiply-defined label '%s'", symbolName);
1563
1564                         // Put symbol in "order of definition" list
1565                         AddToSymbolDeclarationList(symbol);
1566
1567                         tok += 2;
1568
1569                         // Adjust label start address if it's a word or a long, as a byte
1570                         // label might have left us on an odd address.
1571                         switch ((int)*tok)
1572                         {
1573                         case DOTW:
1574                         case DOTL:
1575                                 eval += eval & 0x01;
1576                         }
1577
1578                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1579                         symbol->svalue = eval;
1580
1581                         // Check for dot suffixes and adjust space accordingly (longs and
1582                         // words on an odd boundary get bumped to the next word aligned
1583                         // address). If no suffix, then throw an error.
1584                         switch ((int)*tok)
1585                         {
1586                         case DOTL:
1587                                 eval += 4;
1588                                 break;
1589                         case DOTW:
1590                                 eval += 2;
1591                                 break;
1592                         case DOTB:
1593                                 eval += 1;
1594                                 break;
1595                         default:
1596                                 return error("Symbol missing dot suffix in .cstruct construct");
1597                         }
1598
1599                         tok++;
1600                 }
1601                 else if (*tok >= KW_D0 && *tok <= KW_A7)
1602                 {
1603                         if (reglist(&rlist) < 0)
1604                                 return 0;
1605
1606                         for(i=0; i<16; i++, rlist>>=1)
1607                         {
1608                                 if (rlist & 1)
1609                                         eval += 4;
1610                         }
1611                 }
1612                 else
1613                 {
1614                         switch ((int)*tok)
1615                         {
1616                         case KW_USP:
1617                         case KW_SSP:
1618                         case KW_PC:
1619                                 eval += 2;
1620                                 // FALLTHROUGH
1621                         case KW_SR:
1622                         case KW_CCR:
1623                                 eval += 2;
1624                                 tok++;
1625                                 break;
1626                         case EOL:
1627                                 return 0;
1628                         default:
1629                                 return error(".cstruct syntax");
1630                         }
1631                 }
1632
1633                 // Eat commas in between each argument, if they exist
1634                 if (*tok == ',')
1635                         tok++;
1636         }
1637 }
1638
1639
1640 //
1641 // Undefine a macro - .undefmac macname [, macname...]
1642 //
1643 int undmac1(char * p)
1644 {
1645         SYM * symbol = lookup(p, MACRO, 0);
1646
1647         // If the macro symbol exists, cause it to disappear
1648         if (symbol != NULL)
1649                 symbol->stype = (BYTE)SY_UNDEF;
1650
1651         return OK;
1652 }
1653
1654
1655 int d_undmac(void)
1656 {
1657         symlist(undmac1);
1658         return 0;
1659 }
1660
1661
1662 int d_jpad(void)
1663 {
1664         warn("JPAD directive is deprecated/non-functional");
1665         return OK;
1666 }
1667
1668
1669 int d_nojpad(void)
1670 {
1671         warn("NOJPAD directive is deprecated/non-functional");
1672         return OK;
1673 }
1674
1675
1676 int d_gpumain(void)
1677 {
1678         return error("What the hell? Do you think we adhere to the Goof standard?");
1679 }
1680
1681
1682 //
1683 // .opt - turn a specific (or all) optimisation on or off
1684 //
1685 int d_opt(void)
1686 {
1687         while (*tok != EOL)
1688         {
1689                 if (*tok == STRING)
1690                 {
1691                         tok++;
1692                         char * tmpstr = string[*tok++];
1693
1694                         if (ParseOptimization(tmpstr) != OK)
1695                         {
1696                                 char temperr[256];
1697                                 sprintf(temperr, "unknown optimization flag '%s'", tmpstr);
1698                                 return error(temperr);
1699                         }
1700                 }
1701                 else
1702                         return error(".opt directive needs every switch enclosed inside quotation marks");
1703         }
1704
1705         return OK;
1706 }
1707