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