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