Fix for bug #77. Thanks for ggn for reporting. :-)
[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         DEBUG { printf("Directive: .ds.[size] = %u, sloc = $%X\n", siz, sloc); }
818
819         VALUE eval;
820
821         // This gets kind of stupid.  This directive is disallowed in normal 68000
822         // mode ("for your own good!"), but is permitted for 6502 and Alcyon-
823         // compatibility modes. For obvious reasons, no auto-even is done in 8-bit
824         // processor modes.
825         if (as68_flag == 0 && (scattr & SBSS) == 0)
826                 return error(".ds permitted only in BSS");
827
828         if (siz != SIZB && (sloc & 1))                            // Automatic .even 
829                 auto_even();
830
831         if (abs_expr(&eval) != OK)
832                 return 0;
833
834         // Check to see if the value being passed in is negative (who the hell does
835         // that?--nobody does; it's the code gremlins, or rum, that does it)
836         if (eval < 0)
837                 return error("negative sizes not allowed");
838
839         // In non-TDB section (BSS, ABS and M6502) just advance the location
840         // counter appropriately. In TDB sections, deposit (possibly large) chunks
841         // of zeroed memory....
842         if (scattr & SBSS)
843         {
844                 listvalue(eval);
845                 eval *= siz;
846                 sloc += eval;
847                 just_bss = 1;                                         // No data deposited (8-bit CPU mode)
848         }
849         else
850         {
851                 dep_block(eval, siz, (VALUE)0, (WORD)(DEFINED | ABS), NULL);
852         }
853
854         at_eol();
855         return 0;
856 }
857
858
859 //
860 // dc.b, dc.w / dc, dc.l
861 //
862 int d_dc(WORD siz)
863 {
864         WORD eattr;
865         VALUE eval;
866         WORD tdb;
867         WORD defined;
868         LONG i;
869         char * p;
870         int movei = 0; // movei flag for dc.i
871
872         if ((scattr & SBSS) != 0)
873                 return error("illegal initialization of section");
874
875         // Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
876         if ((siz != SIZB) && (sloc & 1))
877                 auto_even();
878
879         // Check to see if we're trying to set LONGS on a non 32-bit aligned
880         // address in a GPU or DSP section, in their local RAM
881         if ((siz == SIZL) && (orgaddr & 0x03)
882                 && ((rgpu && (orgaddr >= 0xF03000) && (orgaddr <= 0xF03FFFF))
883                 || (rdsp && (orgaddr >= 0xF1B000) && (orgaddr <= 0xF1CFFFF))))
884                 warn("depositing LONGs on a non-long address in local RAM");
885
886         for(;; ++tok)
887         {
888                 // dc.b 'string' [,] ...
889                 if (siz == SIZB && *tok == STRING && (tok[2] == ',' || tok[2] == EOL))
890                 {
891                         i = strlen(string[tok[1]]);
892
893                         if ((challoc - ch_size) < i) 
894                                 chcheck(i);
895
896                         for(p=string[tok[1]]; *p!=EOS; ++p)
897                                 D_byte(*p);
898
899                         tok += 2;
900                         goto comma;
901                 }
902
903                 if (*tok == 'I')
904                 {
905                         movei = 1;
906                         tok++;
907                         siz = SIZL;
908                 }
909
910                 // dc.x <expression>
911                 if (expr(exprbuf, &eval, &eattr, NULL) != OK)
912                         return 0;
913
914                 tdb = (WORD)(eattr & TDB);
915                 defined = (WORD)(eattr & DEFINED);
916
917                 if ((challoc - ch_size) < 4)
918                         chcheck(4);
919
920                 switch (siz)
921                 {
922                 case SIZB:
923                         if (!defined)
924                         {
925                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
926                                 D_byte(0);
927                         }
928                         else
929                         {
930                                 if (tdb)
931                                         return error("non-absolute byte value");
932
933                                 if (eval + 0x100 >= 0x200)
934                                 {
935                                         sprintf(buffer, "%s (value = $%X)", range_error, eval);
936                                         return error(buffer);
937                                 }
938
939                                 D_byte(eval);
940                         }
941
942                         break;
943                 case SIZW:
944                 case SIZN:
945                         if (!defined)
946                         {
947                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
948                                 D_word(0);
949                         }
950                         else
951                         {
952                                 if (tdb)
953                                         rmark(cursect, sloc, tdb, MWORD, NULL);
954
955                                 if (eval + 0x10000 >= 0x20000)
956                                         return error(range_error);
957
958                                 // Deposit 68000 or 6502 (byte-reversed) word 
959                                 D_word(eval);
960                         }
961
962                         break;
963                 case SIZL:
964                         if (!defined)
965                         {
966                                 if (movei)
967                                         AddFixup(FU_LONG | FU_MOVEI, sloc, exprbuf);
968                                 else
969                                         AddFixup(FU_LONG, sloc, exprbuf);
970
971                                 D_long(0);
972                         }
973                         else
974                         {
975                                 if (tdb)
976                                         rmark(cursect, sloc, tdb, MLONG, NULL);
977
978                                 if (movei) 
979                                         eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
980
981                                 D_long(eval);
982                         }
983                         break;
984                 }
985                 
986 comma:
987                 if (*tok != ',')
988                         break;
989         }
990
991         at_eol();
992         return 0;
993 }
994
995
996 //
997 // dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2'
998 //
999 int d_dcb(WORD siz)
1000 {
1001         VALUE evalc, eval;
1002         WORD eattr;
1003
1004         DEBUG { printf("dcb: section is %s%s%s (scattr=$%X)\n", (cursect & TEXT ? "TEXT" : ""), (cursect & DATA ? " DATA" : ""), (cursect & BSS ? "BSS" : ""), scattr); }
1005
1006         if ((scattr & SBSS) != 0)
1007                 return error("illegal initialization of section");
1008
1009         if (abs_expr(&evalc) != OK)
1010                 return 0;
1011
1012         if (*tok++ != ',')
1013                 return error("missing comma");
1014
1015         if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1016                 return 0;
1017
1018         if ((siz != SIZB) && (sloc & 1))
1019                 auto_even();
1020
1021         dep_block(evalc, siz, eval, eattr, exprbuf);
1022         return 0;
1023 }
1024
1025
1026 //
1027 // Generalized initialization directive
1028 // 
1029 // .init[.siz] [#count,] expression [.size] , ...
1030 // 
1031 // The size suffix on the ".init" directive becomes the default size of the
1032 // objects to deposit. If an item is preceeded with a sharp (immediate) sign
1033 // and an expression, it specifies a repeat count. The value to be deposited
1034 // may be followed by a size suffix, which overrides the default size.
1035 //
1036 int d_init(WORD def_siz)
1037 {
1038         VALUE count;
1039         VALUE eval;
1040         WORD eattr;
1041         WORD siz;
1042
1043         if ((scattr & SBSS) != 0)
1044                 return error(".init not permitted in BSS or ABS");
1045
1046         if (rgpu || rdsp)
1047                 return error("directive forbidden in gpu/dsp mode");
1048
1049         for(;;)
1050         {
1051                 // Get repeat count (defaults to 1)
1052                 if (*tok == '#')
1053                 {
1054                         ++tok;
1055
1056                         if (abs_expr(&count) != OK)
1057                                 return 0;
1058
1059                         if (*tok++ != ',')
1060                                 return error(comma_error);
1061                 }
1062                 else
1063                         count = 1;
1064
1065                 // Evaluate expression to deposit
1066                 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
1067                         return 0;
1068
1069                 switch ((int)*tok++)
1070                 {                                 // Determine size of object to deposit
1071                 case DOTB: siz = SIZB; break;
1072                 case DOTW: siz = SIZB; break;
1073                 case DOTL: siz = SIZL; break;
1074                 default: 
1075                         siz = def_siz;
1076                         --tok;
1077                         break;
1078                 }
1079
1080                 dep_block(count, siz, eval, eattr, exprbuf);
1081
1082                 switch ((int)*tok)
1083                 {
1084                 case EOL:
1085                         return 0;
1086                 case ',':
1087                         ++tok;
1088                         continue;
1089                 default:
1090                         return error(comma_error);
1091                 }
1092         }
1093 }
1094
1095
1096 //
1097 // Deposit 'count' values of size 'siz' in the current (non-BSS) segment
1098 //
1099 int dep_block(VALUE count, WORD siz, VALUE eval, WORD eattr, TOKEN * exprbuf)
1100 {
1101         WORD tdb;
1102         WORD defined;
1103
1104         tdb = (WORD)(eattr & TDB);
1105         defined = (WORD)(eattr & DEFINED);
1106
1107         while (count--)
1108         {
1109                 if ((challoc - ch_size) < 4)
1110                         chcheck(4L);
1111
1112                 switch(siz)
1113                 {
1114                 case SIZB:
1115                         if (!defined)
1116                         {
1117                                 AddFixup(FU_BYTE | FU_SEXT, sloc, exprbuf);
1118                                 D_byte(0);
1119                         }
1120                         else
1121                         {
1122                                 if (tdb)
1123                                         return error("non-absolute byte value");
1124
1125                                 if (eval + 0x100 >= 0x200)
1126                                         return error(range_error);
1127
1128                                 D_byte(eval);
1129                         }
1130
1131                         break;
1132                 case SIZW:
1133                 case SIZN:
1134                         if (!defined)
1135                         {
1136                                 AddFixup(FU_WORD | FU_SEXT, sloc, exprbuf);
1137                                 D_word(0);
1138                         }
1139                         else
1140                         {
1141                                 if (tdb)
1142                                         rmark(cursect, sloc, tdb, MWORD, NULL);
1143
1144                                 if (eval + 0x10000 >= 0x20000)
1145                                         return error(range_error);
1146
1147                                 // Deposit 68000 or 6502 (byte-reversed) word
1148                                 D_word(eval);
1149                         }
1150
1151                         break;
1152                 case SIZL:
1153                         if (!defined)
1154                         {
1155                                 AddFixup(FU_LONG, sloc, exprbuf);
1156                                 D_long(0);
1157                         }
1158                         else
1159                         {
1160                                 if (tdb)
1161                                         rmark(cursect, sloc, tdb, MLONG, NULL);
1162
1163                                 D_long(eval);
1164                         }
1165
1166                         break;
1167                 }
1168         }
1169
1170         return 0;
1171 }
1172
1173
1174 //
1175 // .comm symbol, size
1176 //
1177 int d_comm(void)
1178 {
1179         SYM * sym;
1180         char * p;
1181         VALUE eval;
1182
1183         if (*tok != SYMBOL)
1184                 return error("missing symbol");
1185
1186         p = string[tok[1]];
1187         tok += 2;
1188
1189         if (*p == '.')                                                  // Cannot .comm a local symbol
1190                 return error(locgl_error);
1191
1192         if ((sym = lookup(p, LABEL, 0)) == NULL)
1193                 sym = NewSymbol(p, LABEL, 0);
1194         else
1195         {
1196                 if (sym->sattr & DEFINED)
1197                         return error(".comm symbol already defined");
1198         }
1199
1200         sym->sattr = GLOBAL | COMMON | BSS;
1201
1202         if (*tok++ != ',')
1203                 return error(comma_error);
1204
1205         if (abs_expr(&eval) != OK)                              // Parse size of common region
1206                 return 0;
1207
1208         sym->svalue = eval;                                             // Install common symbol's size
1209         at_eol();
1210         return 0;
1211 }
1212
1213
1214 //
1215 // .list - Turn listing on
1216 //
1217 int d_list(void)
1218 {
1219         if (list_flag)
1220                 listing++;
1221
1222         return 0;
1223 }
1224
1225
1226 //
1227 // .nlist - Turn listing off
1228 //
1229 int d_nlist(void)
1230 {
1231         if (list_flag)
1232                 listing--;
1233
1234         return 0;
1235 }
1236
1237
1238 //
1239 // .68000 - Back to 68000 TEXT segment
1240 //
1241 int d_68000(void)
1242 {
1243         rgpu = rdsp = 0;
1244         // Switching from gpu/dsp sections should reset any ORG'd Address
1245         orgactive = 0;                               
1246         orgwarning = 0;
1247         SaveSection();
1248         SwitchSection(TEXT);
1249         return 0;
1250 }
1251
1252
1253 //
1254 // .gpu - Switch to GPU assembler
1255 //
1256 int d_gpu(void)
1257 {
1258         if ((cursect != TEXT) && (cursect != DATA))
1259         {
1260                 error(".gpu can only be used in the TEXT or DATA segments");
1261                 return ERROR;
1262         }
1263
1264         // If previous section was dsp or 68000 then we need to reset ORG'd Addresses
1265         if (!rgpu)
1266         {
1267 //printf("Resetting ORG...\n");
1268                 orgactive = 0;
1269                 orgwarning = 0;
1270         }
1271 //else printf("NOT resetting ORG!\n");
1272
1273         rgpu = 1;                       // Set GPU assembly
1274         rdsp = 0;                       // Unset DSP assembly
1275         regbank = BANK_N;       // Set no default register bank
1276         return 0;
1277 }
1278
1279
1280 //
1281 // .dsp - Switch to DSP assembler
1282 //
1283 int d_dsp(void)
1284 {
1285         if ((cursect != TEXT) && (cursect != DATA))
1286         {
1287                 error(".dsp can only be used in the TEXT or DATA segments");
1288                 return ERROR;
1289         }
1290
1291         // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
1292         if (!rdsp)
1293         {
1294                 orgactive = 0;
1295                 orgwarning = 0;
1296         }
1297
1298         rdsp = 1;                       // Set DSP assembly
1299         rgpu = 0;                       // Unset GPU assembly
1300         regbank = BANK_N;       // Set no default register bank
1301         return 0;
1302 }
1303
1304
1305 //
1306 // .cargs [#offset], symbol[.size], ...
1307 // 
1308 // Lists of registers may also be mentioned; they just take up space. Good for
1309 // "documentation" purposes:
1310 // 
1311 // .cargs a6, .arg1, .arg2, .arg3...
1312 // 
1313 // Symbols thus created are ABS and EQUATED.
1314 //
1315 int d_cargs(void)
1316 {
1317         VALUE eval = 4;         // Default to 4 if no offset specified (to account for
1318                                                 // return address)
1319         WORD rlist;
1320         SYM * symbol;
1321         char * p;
1322         int env;
1323         int i;
1324
1325         if (rgpu || rdsp)
1326                 return error("directive forbidden in gpu/dsp mode");
1327
1328         if (*tok == '#')
1329         {
1330                 tok++;
1331
1332                 if (abs_expr(&eval) != OK)
1333                         return 0;
1334
1335                 // Eat the comma, if it's there
1336                 if (*tok == ',')
1337                         tok++;
1338         }
1339
1340         for(;;)
1341         {
1342                 if (*tok == SYMBOL)
1343                 {
1344                         p = string[tok[1]];
1345
1346                         // Set env to either local (dot prefixed) or global scope
1347                         env = (*p == '.' ? curenv : 0);
1348                         symbol = lookup(p, LABEL, env);
1349
1350                         if (symbol == NULL)
1351                         {
1352                                 symbol = NewSymbol(p, LABEL, env);
1353                                 symbol->sattr = 0;
1354                         }
1355                         else if (symbol->sattr & DEFINED)
1356                                 return errors("multiply-defined label '%s'", p);
1357
1358                         // Put symbol in "order of definition" list
1359                         AddToSymbolDeclarationList(symbol);
1360
1361                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1362                         symbol->svalue = eval;
1363                         tok += 2;
1364
1365                         // What this does is eat any dot suffixes attached to a symbol. If
1366                         // it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
1367                         // there is no dot suffix, it assumes a size of 2.
1368                         switch ((int)*tok)
1369                         {
1370                         case DOTL:
1371                                 eval += 2;
1372                         case DOTB:
1373                         case DOTW:
1374                                 tok++;
1375                         }
1376
1377                         eval += 2;
1378                 }
1379                 else if (*tok >= KW_D0 && *tok <= KW_A7)
1380                 {
1381                         if (reglist(&rlist) < 0)
1382                                 return 0;
1383
1384                         for(i=0; i<16; i++, rlist>>=1)
1385                         {
1386                                 if (rlist & 1)
1387                                         eval += 4;
1388                         }
1389                 }
1390                 else
1391                 {
1392                         switch ((int)*tok)
1393                         {
1394                         case KW_USP:
1395                         case KW_SSP:
1396                         case KW_PC:
1397                                 eval += 2;
1398                                 // FALLTHROUGH
1399                         case KW_SR:
1400                         case KW_CCR:
1401                                 eval += 2;
1402                                 tok++;
1403                                 break;
1404                         case EOL:
1405                                 return 0;
1406                         default:
1407                                 return error(".cargs syntax");
1408                         }
1409                 }
1410
1411                 // Eat commas in between each argument, if they exist
1412                 if (*tok == ',')
1413                         tok++;
1414         }
1415 }
1416
1417
1418 //
1419 // .cstruct [#offset], symbol[.size], ...
1420 // 
1421 // Lists of registers may also be mentioned; they just take up space. Good for
1422 // "documentation" purposes:
1423 // 
1424 // .cstruct a6, .arg1, .arg2, .arg3...
1425 // 
1426 // Symbols thus created are ABS and EQUATED. Note that this is for
1427 // compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
1428 // the suggestion.
1429 //
1430 int d_cstruct(void)
1431 {
1432         VALUE eval = 0;         // Default, if no offset specified, is zero
1433         WORD rlist;
1434         SYM * symbol;
1435         char * symbolName;
1436         int env;
1437         int i;
1438
1439         if (rgpu || rdsp)
1440                 return error("directive forbidden in gpu/dsp mode");
1441
1442         if (*tok == '#')
1443         {
1444                 tok++;
1445
1446                 if (abs_expr(&eval) != OK)
1447                         return 0;
1448
1449                 // Eat the comma, if it's there
1450                 if (*tok == ',')
1451                         tok++;
1452         }
1453
1454         for(;;)
1455         {
1456                 if (*tok == SYMBOL)
1457                 {
1458                         symbolName = string[tok[1]];
1459
1460                         // Set env to either local (dot prefixed) or global scope
1461                         env = (symbolName[0] == '.' ? curenv : 0);
1462                         symbol = lookup(symbolName, LABEL, env);
1463
1464                         // If the symbol wasn't found, then define it. Otherwise, throw an
1465                         // error.
1466                         if (symbol == NULL)
1467                         {
1468                                 symbol = NewSymbol(symbolName, LABEL, env);
1469                                 symbol->sattr = 0;
1470                         }
1471                         else if (symbol->sattr & DEFINED)
1472                                 return errors("multiply-defined label '%s'", symbolName);
1473
1474                         // Put symbol in "order of definition" list
1475                         AddToSymbolDeclarationList(symbol);
1476
1477                         tok += 2;
1478
1479                         // Adjust label start address if it's a word or a long, as a byte
1480                         // label might have left us on an odd address.
1481                         switch ((int)*tok)
1482                         {
1483                         case DOTW:
1484                         case DOTL:
1485                                 eval += eval & 0x01;
1486                         }
1487
1488                         symbol->sattr |= (ABS | DEFINED | EQUATED);
1489                         symbol->svalue = eval;
1490
1491                         // Check for dot suffixes and adjust space accordingly (longs and
1492                         // words on an odd boundary get bumped to the next word aligned
1493                         // address). If no suffix, then throw an error.
1494                         switch ((int)*tok)
1495                         {
1496                         case DOTL:
1497                                 eval += 4;
1498                                 break;
1499                         case DOTW:
1500                                 eval += 2;
1501                                 break;
1502                         case DOTB:
1503                                 eval += 1;
1504                                 break;
1505                         default:
1506                                 return error("Symbol missing dot suffix in .cstruct construct");
1507                         }
1508
1509                         tok++;
1510                 }
1511                 else if (*tok >= KW_D0 && *tok <= KW_A7)
1512                 {
1513                         if (reglist(&rlist) < 0)
1514                                 return 0;
1515
1516                         for(i=0; i<16; i++, rlist>>=1)
1517                         {
1518                                 if (rlist & 1)
1519                                         eval += 4;
1520                         }
1521                 }
1522                 else
1523                 {
1524                         switch ((int)*tok)
1525                         {
1526                         case KW_USP:
1527                         case KW_SSP:
1528                         case KW_PC:
1529                                 eval += 2;
1530                                 // FALLTHROUGH
1531                         case KW_SR:
1532                         case KW_CCR:
1533                                 eval += 2;
1534                                 tok++;
1535                                 break;
1536                         case EOL:
1537                                 return 0;
1538                         default:
1539                                 return error(".cstruct syntax");
1540                         }
1541                 }
1542
1543                 // Eat commas in between each argument, if they exist
1544                 if (*tok == ',')
1545                         tok++;
1546         }
1547 }
1548
1549
1550 //
1551 // Undefine a macro - .undefmac macname [, macname...]
1552 //
1553 int undmac1(char * p)
1554 {
1555         SYM * symbol = lookup(p, MACRO, 0);
1556
1557         // If the macro symbol exists, cause it to disappear
1558 //      if ((sy = lookup(p, MACRO, 0)) != NULL)
1559         if (symbol != NULL)
1560                 symbol->stype = (BYTE)SY_UNDEF;
1561
1562         return OK;
1563 }
1564
1565
1566 int d_undmac(void)
1567 {
1568         symlist(undmac1);
1569         return 0;
1570 }
1571
1572
1573 int d_jpad(void)
1574 {
1575         warn("JPAD directive is deprecated/non-functional");
1576         return OK;
1577 }
1578
1579
1580 int d_nojpad(void)
1581 {
1582         warn("NOJPAD directive is deprecated/non-functional");
1583         return OK;
1584 }
1585
1586
1587 int d_gpumain(void)
1588 {
1589         return error("What the hell? Do you think we adhere to the Goof standard?");
1590 }
1591