Fix for "*" getting bad section attributes, reported by A. Seed.
[rmac] / mach.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // MACH.C - Code Generation
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 "mach.h"
10 #include "error.h"
11 #include "sect.h"
12 #include "direct.h"
13 #include "token.h"
14 #include "procln.h"
15 #include "riscasm.h"
16
17 #define DEF_KW
18 #include "kwtab.h"
19
20
21 // Fucntion prototypes 
22 int m_unimp(WORD, WORD), m_badmode(WORD, WORD), m_bad6mode(WORD, WORD), m_bad6inst(WORD, WORD);
23 int m_self(WORD, WORD);
24 int m_abcd(WORD, WORD);
25 int m_reg(WORD, WORD);
26 int m_imm(WORD, WORD);
27 int m_imm8(WORD, WORD);
28 int m_shi(WORD, WORD);
29 int m_shr(WORD, WORD);
30 int m_bitop(WORD, WORD);
31 int m_exg(WORD, WORD);
32 int m_ea(WORD, WORD);
33 int m_br(WORD, WORD);
34 int m_dbra(WORD, WORD);
35 int m_link(WORD, WORD);
36 int m_adda(WORD, WORD);
37 int m_addq(WORD, WORD);
38 //int m_move(WORD, int);
39 int m_move(WORD, WORD);
40 int m_moveq(WORD, WORD);
41 int m_usp(WORD, WORD);
42 int m_movep(WORD, WORD);
43 int m_trap(WORD, WORD);
44 int m_movem(WORD, WORD);
45 int m_clra(WORD, WORD);
46
47 // Common error messages
48 char range_error[] = "expression out of range";
49 char abs_error[] = "illegal absolute expression";
50 char seg_error[] = "bad (section) expression";
51 char rel_error[] = "illegal relative address";
52 char siz_error[] = "bad size specified";
53 char undef_error[] = "undefined expression";
54 char fwd_error[] = "forward or undefined expression";
55
56 extern int ea0gen(WORD);
57 extern int ea1gen(WORD);
58
59 // Include code tables
60 MNTAB machtab[] = {
61 //   { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0 
62    { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0 
63    #include "68ktab.h"
64    {  0,  0L,  0L, 0x0000, 0, m_unimp   }                   // Last entry
65 };
66
67 // Register number << 9
68 WORD reg_9[8] = {
69       0, 1<<9, 2<<9, 3<<9,
70    4<<9, 5<<9, 6<<9, 7<<9
71 };
72
73 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
74 WORD siz_6[] = {
75    (WORD)-1,                                                // n/a 
76    0,                                                       // SIZB
77    1<<6, (WORD)-1,                                          // SIZW, n/a 
78    2<<6, (WORD)-1, (WORD)-1, (WORD)-1,                      // SIZL, n/a, n/a, n/a 
79    1<<6                                                     // SIZN 
80 };
81
82 // Byte/word/long size for MOVE instrs
83 WORD siz_12[] = {
84    (WORD)-1,
85    0x1000,                                                  // Byte 
86    0x3000, (WORD)-1,                                        // Word 
87    0x2000, (WORD)-1, (WORD)-1, (WORD)-1,                    // Long
88    0x3000                                                   // Word (SIZN)
89 };
90
91 // Word/long size (0=.w, 1=.l) in bit 8
92 WORD lwsiz_8[] = {
93    (WORD)-1,                                                // n/a
94    (WORD)-1,                                                // SIZB
95    0, (WORD)-1,                                             // SIZW, n/a
96    1<<8, (WORD)-1, (WORD)-1, (WORD)-1,                      // SIZL, n/a, n/a, n/a
97    0                                                        // SIZN
98 };
99
100 // Addressing mode in bits 6..11 (register/mode fields are reversed)
101 WORD am_6[] = {
102    00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
103    00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
104    00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
105    00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
106    00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
107    00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
108    00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
109    00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
110 };
111
112
113 // Error messages
114 int m_unimp(WORD unused1, WORD unused2)
115 {
116         return (int)error("unimplemented mnemonic");
117 }
118
119
120 //int m_badmode(void)
121 int m_badmode(WORD unused1, WORD unused2)
122 {
123         return (int)error("inappropriate addressing mode");
124 }
125
126
127 int m_self(WORD inst, WORD usused)
128 {
129         D_word(inst);
130         return 0;
131 }
132
133
134 //
135 // Do one EA in bits 0..5
136 // 
137 // Bits in `inst' have the following meaning:
138 // 
139 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
140 // of the instr.
141 // 
142 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
143 // is generated after the instruction. Regardless of bit 0's value, ea0 is
144 // always deposited in memory before ea1.
145 // 
146 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
147 // 
148 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
149 // of the instr.
150 //
151 int m_ea(WORD inst, WORD siz)
152 {
153         WORD flg = inst;                                        // Save flag bits 
154         inst &= ~0x3F;                                          // Clobber flag bits in instr 
155
156         // Install "standard" instr size bits 
157         if (flg & 4)
158                 inst |= siz_6[siz];
159
160         if (flg & 16)
161         {
162                 // OR-in register number 
163                 if (flg & 8)
164                 {
165                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11 
166                 }
167                 else
168                 {
169                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11 
170                 }
171         }
172
173         if (flg & 1)
174         {
175                 // Use am1 
176                 inst |= am1 | a1reg;                    // Get ea1 into instr 
177                 D_word(inst);                                   // Deposit instr 
178
179                 // Generate ea0 if requested 
180                 if (flg & 2)
181                         ea0gen(siz);
182
183                 ea1gen(siz);                                    // Generate ea1 
184         }
185         else
186         {
187                 // Use am0 
188                 inst |= am0 | a0reg;                    // Get ea0 into instr 
189                 D_word(inst);                                   // Deposit instr 
190                 ea0gen(siz);                                    // Generate ea0 
191
192                 // Generate ea1 if requested 
193                 if (flg & 2)
194                         ea1gen(siz);
195         }
196
197         return 0;
198 }
199
200
201 //
202 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
203 // 6..7
204 //
205 int m_abcd(WORD inst, WORD siz)
206 {
207         if (inst & 1)
208         {
209                 // Install size bits 
210                 inst--;
211                 inst |= siz_6[siz];
212         }
213
214         inst |= a0reg | reg_9[a1reg];
215         D_word(inst);
216
217         return 0;
218 }
219
220
221 //
222 // {adda} ea,AREG
223 //
224 int m_adda(WORD inst, WORD siz)
225 {
226         inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
227         D_word(inst);
228         ea0gen(siz);    // Generate EA 
229
230         return 0;
231 }
232
233
234 //
235 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
236 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
237 // 
238 int m_reg(WORD inst, WORD siz)
239 {
240         if (inst & 1)
241                 // Install size bits 
242                 inst |= siz_6[siz];
243
244         if (inst & 2)
245                 // Install other register (9..11) 
246                 inst |= reg_9[a1reg];
247
248         inst &= ~7;                     // Clear off crufty bits 
249         inst |= a0reg;          // Install first register 
250         D_word(inst);
251
252         return 0;
253 }
254
255
256 //
257 // <op> #expr
258 //
259 int m_imm(WORD inst, WORD siz)
260 {
261         D_word(inst);
262         ea0gen(siz);
263
264         return 0;
265 }
266
267
268 //
269 // <op>.b #expr
270 //
271 int m_imm8(WORD inst, WORD siz)
272 {
273         siz = siz;
274         D_word(inst);
275         ea0gen(SIZB);
276
277         return 0;
278 }
279
280
281 //
282 // <shift> Dn,Dn
283 //
284 int m_shr(WORD inst, WORD siz)
285 {
286         inst |= reg_9[a0reg] | a1reg | siz_6[siz];
287         D_word(inst);
288
289         return 0;
290 }
291
292
293 //
294 // <shift> #n,Dn
295 //
296 int m_shi(WORD inst, WORD siz)
297 {
298         inst |= a1reg | siz_6[siz];
299
300         if (a0exattr & DEFINED)
301         {
302                 if (a0exval > 8)
303                         return error(range_error);
304
305                 inst |= (a0exval & 7) << 9;
306                 D_word(inst);
307         }
308         else
309         {
310                 AddFixup(FU_QUICK, sloc, a0expr);
311                 D_word(inst);
312         }
313
314         return 0;
315 }
316
317
318 //
319 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
320 //
321 int m_bitop(WORD inst, WORD siz)
322 {
323         // Enforce instruction sizes
324         if (am1 == DREG)
325         {                               // X,Dn must be .n or .l 
326                 if (siz & (SIZB | SIZW))
327                         return error(siz_error);
328         }
329         else if (siz & (SIZW | SIZL))   // X,ea must be .n or .b 
330                 return error(siz_error);
331
332         // Construct instr and EAs
333         inst |= am1 | a1reg;
334
335         if (am0 == IMMED)
336         {
337                 D_word(inst);
338                 ea0gen(SIZB);                           // Immediate bit number 
339         }
340         else
341         {
342                 inst |= reg_9[a0reg];
343                 D_word(inst);
344         }
345
346         // ea to bit-munch 
347         ea1gen(SIZB);
348
349         return 0;
350 }
351
352
353 int m_dbra(WORD inst, WORD siz)
354 {
355         VALUE v;
356
357         siz = siz;
358         inst |= a0reg;
359         D_word(inst);
360
361         if (a1exattr & DEFINED)
362         {
363                 if ((a1exattr & TDB) != cursect)
364                         return error(rel_error);
365
366                 v = a1exval - sloc;
367
368                 if (v + 0x8000 > 0x10000)
369                         return error(range_error);
370
371                 D_word(v);
372         }
373         else
374         {
375                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
376                 D_word(0);
377         }
378
379         return 0;
380 }
381
382
383 //
384 // EXG
385 //
386 int m_exg(WORD inst, WORD siz)
387 {
388         int m;
389
390         siz = siz;
391
392         if (am0 == DREG && am1 == DREG)
393                 m = 0x0040;                                           // Dn,Dn 
394         else if (am0 == AREG && am1 == AREG)
395                 m = 0x0048;                                           // An,An 
396         else
397         {
398                 if (am0 == AREG)
399                 {                                     // Dn,An or An,Dn 
400                         m = a1reg;                                         // Get AREG into a1reg 
401                         a1reg = a0reg;
402                         a0reg = m;
403                 }
404
405                 m = 0x0088;
406         }
407
408         inst |= m | reg_9[a0reg] | a1reg;
409         D_word(inst);
410
411         return 0;
412 }
413
414
415 //
416 // LINK
417 //
418 int m_link(WORD inst, WORD siz)
419 {
420         siz = siz;
421         inst |= a0reg;
422         D_word(inst);
423         ea1gen(SIZW);
424
425         return 0;
426 }
427
428
429 //
430 // Handle MOVE <C_ALL> <C_ALTDATA>
431 //        MOVE <C_ALL> <M_AREG>
432 // 
433 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
434 //
435 //int m_move(WORD inst, int siz)
436 int m_move(WORD inst, WORD size)
437 {
438         // Cast the passed in value to an int
439         int siz = (int)size;
440
441         // Try to optimize to MOVEQ
442         if (siz == SIZL && am0 == IMMED && am1 == DREG
443                 && (a0exattr & (TDB|DEFINED)) == DEFINED && a0exval + 0x80 < 0x100)
444         {
445                 m_moveq((WORD)0x7000, (WORD)0);
446         }
447         else
448         {
449                 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
450
451                 D_word(inst);
452
453                 if (am0 >= ADISP)
454                         ea0gen((WORD)siz);
455
456                 if (am1 >= ADISP)
457                         ea1gen((WORD)siz);
458         }
459
460         return 0;
461 }
462
463
464 //
465 // move USP,An -- move An,USP
466 //
467 int m_usp(WORD inst, WORD siz)
468 {
469         siz = siz;
470
471         if (am0 == AM_USP)
472                 inst |= a1reg;          // USP, An 
473         else
474                 inst |= a0reg;          // An, USP 
475
476         D_word(inst);
477
478         return 0;
479 }
480
481
482 //
483 // moveq
484 //
485 int m_moveq(WORD inst, WORD siz)
486 {
487         siz = siz;
488
489         // Arrange for future fixup 
490         if (!(a0exattr & DEFINED))
491         {
492                 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
493                 a0exval = 0; 
494         }
495         else if (a0exval + 0x100 >= 0x200)
496                 return error(range_error);
497
498         inst |= reg_9[a1reg] | (a0exval & 0xFF);
499         D_word(inst);
500
501         return 0;
502 }
503
504
505 //
506 // movep Dn, disp(An) -- movep disp(An), Dn
507 //
508 int m_movep(WORD inst, WORD siz)
509 {
510         if (siz == SIZL)
511                 inst |= 0x0040;
512
513         if (am0 == DREG)
514         {
515                 inst |= reg_9[a0reg] | a1reg;
516                 D_word(inst);
517
518                 if (am1 == AIND)
519                         D_word(0)
520                 else 
521                         ea1gen(siz);
522         }
523         else
524         {
525                 inst |= reg_9[a1reg] | a0reg;
526                 D_word(inst);
527
528                 if (am0 == AIND)
529                         D_word(0)
530                 else 
531                         ea0gen(siz);
532         }
533
534         return 0;
535 }
536
537
538 //
539 // Bcc -- BSR
540 //
541 int m_br(WORD inst, WORD siz)
542 {
543         VALUE v;
544
545         if (a0exattr & DEFINED)
546         {
547                 if ((a0exattr & TDB) != cursect)
548 //{
549 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
550                         return error(rel_error);
551 //}
552
553                 v = a0exval - (sloc + 2);
554
555                 // Optimize branch instr. size
556                 if (siz == SIZN)
557                 {
558                         if (v != 0 && v + 0x80 < 0x100)
559                         {
560                                 // Fits in .B 
561                                 inst |= v & 0xFF;
562                                 D_word(inst);
563                                 return 0;
564                         }
565                         else
566                         {
567                                 // Fits in .W 
568                                 if (v + 0x8000 > 0x10000)
569                                         return error(range_error);
570
571                                 D_word(inst);
572                                 D_word(v);
573                                 return 0;
574                         }
575                 }
576
577                 if (siz == SIZB)
578                 {
579                         if (v + 0x80 >= 0x100)
580                                 return error(range_error);
581
582                         inst |= v & 0xFF;
583                         D_word(inst);
584                 }
585                 else
586                 {
587                         if (v + 0x8000 >= 0x10000)
588                                 return error(range_error);
589
590                         D_word(inst);
591                         D_word(v);
592                 }
593
594                 return 0;
595         }
596         else if (siz == SIZN)
597                 siz = SIZW;
598
599         if (siz == SIZB)
600         {
601                 // .B 
602                 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
603                 D_word(inst);
604                 return 0;
605         }
606         else
607         {
608                 // .W 
609                 D_word(inst);
610                 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
611                 D_word(0);
612         }
613
614         return 0;
615 }
616
617
618 //
619 // ADDQ -- SUBQ
620 //
621 int m_addq(WORD inst, WORD siz)
622 {
623         inst |= siz_6[siz] | am1 | a1reg;
624
625         if (a0exattr & DEFINED)
626         {
627                 if (a0exval > 8 ||      a0exval == 0)                       // Range in 1..8 
628                         return error(range_error);
629
630                 inst |= (a0exval & 7) << 9;
631                 D_word(inst);
632         }
633         else
634         {
635                 AddFixup(FU_QUICK, sloc, a0expr);
636                 D_word(inst);
637         }
638
639         ea1gen(siz);
640
641         return 0;
642 }
643
644
645 //
646 // trap #n
647 //
648 int m_trap(WORD inst, WORD siz)
649 {
650         siz = siz;
651
652         if (a0exattr & DEFINED)
653         {
654                 if (a0exattr & TDB)
655                         return error(abs_error);
656
657                 if (a0exval >= 16)
658                         return error(range_error);
659
660                 inst |= a0exval;
661                 D_word(inst);
662         }
663         else 
664                 return error(undef_error);
665
666         return 0;
667 }
668
669
670 //
671 // movem <rlist>,ea -- movem ea,<rlist>
672 //
673 int m_movem(WORD inst, WORD siz)
674 {
675         VALUE eval;
676         WORD i;
677         WORD w;
678         WORD rmask;
679
680         if (siz & SIZB)
681                 return error("bad size suffix");
682
683         if (siz == SIZL)
684                 inst |= 0x0040;
685
686         if (*tok == '#')
687         {
688                 // Handle #<expr>, ea 
689                 tok++;
690
691                 if (abs_expr(&eval) != OK)
692                         return 0;
693
694                 if (eval >= 0x10000L)
695                         return error(range_error);
696
697                 rmask = (WORD)eval;
698                 goto immed1;
699         }
700
701         if (*tok >= KW_D0 && *tok <= KW_A7)
702         {
703                 // <rlist>, ea 
704                 if (reglist(&rmask) < 0)
705                         return 0;
706
707 immed1:
708                 if (*tok++ != ',')
709                         return error("missing comma");
710
711                 if (amode(0) < 0)
712                         return 0;
713
714                 inst |= am0 | a0reg;
715
716                 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
717                         return error("invalid addressing mode");
718
719                 // If APREDEC, reverse register mask
720                 if (am0 == APREDEC)
721                 {
722                         w = rmask;
723                         rmask = 0;
724
725                         for(i=0x8000; i; i>>=1, w>>=1)
726                                 rmask = (WORD)((rmask << 1) | w & 1);
727                 }
728         }
729         else
730         {
731                 // ea, <rlist> 
732                 if (amode(0) < 0)
733                         return 0;
734
735                 inst |= 0x0400 | am0 | a0reg;
736
737                 if (*tok++ != ',')
738                         return error("missing comma");
739
740                 if (*tok == EOL)
741                         return error("missing register list");
742
743                 if (*tok == '#')
744                 {
745                         // ea, #<expr> 
746                         tok++;
747
748                         if (abs_expr(&eval) != OK)
749                                 return 0;
750
751                         if (eval >= 0x10000)
752                                 return error(range_error);
753
754                         rmask = (WORD)eval;
755                 }
756                 else if (reglist(&rmask) < 0)
757                         return 0;
758
759                 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
760                         return error("invalid addressing mode");
761         }
762
763         D_word(inst);
764         D_word(rmask);
765         ea0gen(siz);
766
767         return 0;
768 }
769
770
771 //
772 // CLR.x An ==> SUBA.x An,An
773 //
774 int m_clra(WORD inst, WORD siz)
775 {
776         inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
777         D_word(inst);
778
779         return 0;
780 }
781