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