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