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