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