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