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