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