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