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