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