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