Code cleanups.
[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         if (!(a0exattr & DEFINED))
449         {                              // Arrange for future fixup 
450                 fixup(FU_BYTE|FU_SEXT, sloc+1, a0expr);
451                 a0exval = 0; 
452         }
453         else if (a0exval + 0x100 >= 0x200)
454                 return error(range_error);
455
456         inst |= reg_9[a1reg] | (a0exval & 0xff);
457         D_word(inst);
458
459         return 0;
460 }
461
462
463 //
464 // movep Dn,disp(An) -- movep disp(An),Dn
465 //
466 int m_movep(WORD inst, WORD siz)
467 {
468         //WORD k;
469
470         if (siz == SIZL)
471                 inst |= 0x0040;
472
473         if (am0 == DREG)
474         {
475                 inst |= reg_9[a0reg] | a1reg;
476                 D_word(inst);
477
478                 if (am1 == AIND)
479                 {
480                         D_word(0);
481                 }
482                 else 
483                         ea1gen(siz);
484         }
485         else
486         {
487                 inst |= reg_9[a1reg] | a0reg;
488                 D_word(inst);
489
490                 if (am0 == AIND)
491                 {
492                         D_word(0);
493                 }
494                 else 
495                         ea0gen(siz);
496         }
497
498         return 0;
499 }
500
501
502 //
503 // Bcc -- BSR
504 //
505 int m_br(WORD inst, WORD siz)
506 {
507         VALUE v;
508
509         if (a0exattr & DEFINED)
510         {
511                 if ((a0exattr & TDB) != cursect)
512                         return error(rel_error);
513
514                 v = a0exval - (sloc + 2);
515
516                 // Optimize branch instr. size
517                 if (siz == SIZN)
518                 {
519                         if (v != 0 && v + 0x80 < 0x100)
520                         {                   // Fits in .B 
521                                 inst |= v & 0xff;
522                                 D_word(inst);
523                                 return 0;
524                         }
525                         else
526                         {                                           // Fits in .W 
527                                 if (v + 0x8000 > 0x10000)
528                                         return error(range_error);
529
530                                 D_word(inst);
531                                 D_word(v);
532                                 return 0;
533                         }
534                 }
535
536                 if (siz == SIZB)
537                 {
538                         if (v + 0x80 >= 0x100)
539                                 return error(range_error);
540
541                         inst |= v & 0xff;
542                         D_word(inst);
543                 }
544                 else
545                 {
546                         if (v + 0x8000 >= 0x10000)
547                                 return error(range_error);
548
549                         D_word(inst);
550                         D_word(v);
551                 }
552
553                 return 0;
554         }
555         else if (siz == SIZN)
556                 siz = SIZW;
557
558         if (siz == SIZB)
559         {                                        // .B 
560                 fixup(FU_BBRA|FU_PCREL|FU_SEXT, sloc, a0expr);
561                 D_word(inst);
562                 return 0;
563         }
564         else
565         {                                                 // .W 
566                 D_word(inst);
567                 fixup(FU_WORD|FU_PCREL|FU_LBRA|FU_ISBRA, sloc, a0expr);
568                 D_word(0);
569         }
570
571         return 0;
572 }
573
574
575 //
576 // ADDQ -- SUBQ
577 //
578 int m_addq(WORD inst, WORD siz)
579 {
580         inst |= siz_6[siz] | am1 | a1reg;
581
582         if (a0exattr & DEFINED)
583         {
584                 if (a0exval > 8 ||      a0exval == 0)                       // Range in 1..8 
585                         return error(range_error);
586
587                 inst |= (a0exval & 7) << 9;
588                 D_word(inst);
589         }
590         else
591         {
592                 fixup(FU_QUICK, sloc, a0expr);
593                 D_word(inst);
594         }
595
596         ea1gen(siz);
597
598         return 0;
599 }
600
601
602 //
603 // trap #n
604 //
605 int m_trap(WORD inst, WORD siz)
606 {
607         siz = siz;
608
609         if (a0exattr & DEFINED)
610         {
611                 if (a0exattr & TDB)
612                         return error(abs_error);
613
614                 if (a0exval >= 16)
615                         return error(range_error);
616
617                 inst |= a0exval;
618                 D_word(inst);
619         }
620         else 
621                 return error(undef_error);
622
623         return 0;
624 }
625
626
627 //
628 // movem <rlist>,ea -- movem ea,<rlist>
629 //
630 int m_movem(WORD inst, WORD siz)
631 {
632         VALUE eval;
633         WORD i;
634         WORD w;
635         WORD rmask;
636
637         if (siz & SIZB)
638                 return error("bad size suffix");
639
640         if (siz == SIZL)
641                 inst |= 0x0040;
642
643         if (*tok == '#')
644         {                                        // Handle #<expr>,ea 
645                 ++tok;
646
647                 if (abs_expr(&eval) != OK)
648                         return 0;
649
650                 if (eval >= 0x10000L)
651                         return error(range_error);
652
653                 rmask = (WORD)eval;
654                 goto immed1;
655         }
656
657         if (*tok >= KW_D0 && *tok <= KW_A7)
658         {                     // <rlist>,ea 
659                 if (reglist(&rmask) < 0)
660                         return 0;
661
662 immed1:
663                 if (*tok++ != ',')
664                         return error("missing comma");
665
666                 if (amode(0) < 0)
667                         return 0;
668
669                 inst |= am0 | a0reg;
670
671                 if (!(amsktab[am0] & (C_ALTCTRL|M_APREDEC)))
672                         return error("invalid addressing mode");
673
674                 // If APREDEC, reverse register mask
675                 if (am0 == APREDEC)
676                 {
677                         w = rmask;
678                         rmask = 0;
679
680                         for(i=0x8000; i; i>>=1, w>>=1)
681                                 rmask = (WORD)((rmask << 1) | w & 1);
682                 }
683         }
684         else
685         {                                                 // ea,<rlist> 
686                 if (amode(0) < 0)
687                         return 0;
688
689                 inst |= 0x0400 | am0 | a0reg;
690
691                 if (*tok++ != ',')
692                         return error("missing comma");
693
694                 if (*tok == EOL)
695                         return error("missing register list");
696
697                 if (*tok == '#')
698                 {                                     // ea,#<expr> 
699                         ++tok;
700
701                         if (abs_expr(&eval) != OK)
702                                 return 0;
703
704                         if (eval >= 0x10000)
705                                 return error(range_error);
706
707                         rmask = (WORD)eval;
708                 }
709                 else if (reglist(&rmask) < 0)
710                         return 0;
711
712                 if (!(amsktab[am0] & (C_CTRL|M_APOSTINC)))
713                         return error("invalid addressing mode");
714         }
715
716         D_word(inst);
717         D_word(rmask);
718         ea0gen(siz);
719
720         return 0;
721 }
722
723
724 //
725 // CLR.x An ==> SUBA.x An,An
726 //
727 int m_clra(WORD inst, WORD siz)
728 {
729         inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
730         D_word(inst);
731
732         return 0;
733 }