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