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