]> Shamusworld >> Repos - rmac/blobdiff - amode.c
Version bump for last patch; now at v1.13.4.
[rmac] / amode.c
diff --git a/amode.c b/amode.c
index b09b2da57cb63fc4b6880e4e320c9f0d9811d1c6..ccd86ddf184a95ace8385ea5da725277e0a15f19 100644 (file)
--- a/amode.c
+++ b/amode.c
@@ -1,47 +1,78 @@
 //
-// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC - Reboot's Macro Assembler for all Atari computers
 // AMODE.C - Addressing Modes
-// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2018 Reboot and Friends
 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
 // Source utilised with the kind permission of Landon Dyer
 //
 
 #include "amode.h"
 #include "error.h"
-#include "token.h"
 #include "expr.h"
+#include "mach.h"
+#include "procln.h"
 #include "rmac.h"
+#include "sect.h"
+#include "token.h"
 
 #define DEF_KW
 #include "kwtab.h"
 #define DEF_MN
 #include "mntab.h"
 
+extern char unsupport[];
+
 // Address-mode information
 int nmodes;                                    // Number of addr'ing modes found
 int am0;                                       // Addressing mode
 int a0reg;                                     // Register
 TOKEN a0expr[EXPRSIZE];                // Expression
-VALUE a0exval;                         // Expression's value
+uint64_t a0exval;                      // Expression's value
 WORD a0exattr;                         // Expression's attribute
 int a0ixreg;                           // Index register
 int a0ixsiz;                           // Index register size (and scale)
 TOKEN a0oexpr[EXPRSIZE];       // Outer displacement expression
-VALUE a0oexval;                                // Outer displacement value
+uint64_t a0oexval;                     // Outer displacement value
 WORD a0oexattr;                                // Outer displacement attribute
 SYM * a0esym;                          // External symbol involved in expr
+TOKEN a0bexpr[EXPRSIZE];       // Base displacement expression
+uint64_t a0bexval;                     // Base displacement value
+WORD a0bexattr;                                // Base displacement attribute
+WORD a0bsize;                          // Base displacement size
+WORD a0extension;                      // 020+ extension address word
+WORD am0_030;                          // ea bits for 020+ addressing modes
 
 int am1;                                       // Addressing mode
 int a1reg;                                     // Register
 TOKEN a1expr[EXPRSIZE];                // Expression
-VALUE a1exval;                         // Expression's value
+uint64_t a1exval;                      // Expression's value
 WORD a1exattr;                         // Expression's attribute
 int a1ixreg;                           // Index register
 int a1ixsiz;                           // Index register size (and scale)
 TOKEN a1oexpr[EXPRSIZE];       // Outer displacement expression
-VALUE a1oexval;                                // Outer displacement value
+uint64_t a1oexval;                     // Outer displacement value
 WORD a1oexattr;                                // Outer displacement attribute
 SYM * a1esym;                          // External symbol involved in expr
+TOKEN a1bexpr[EXPRSIZE];       // Base displacement expression
+uint64_t a1bexval;                     // Base displacement value
+WORD a1bexattr;                                // Base displacement attribute
+WORD a1bsize;                          // Base displacement size
+WORD a1extension;                      // 020+ extension address word
+WORD am1_030;                          // ea bits for 020+ addressing modes
+
+int a2reg;                                     // Register for div.l (68020+)
+
+int bfparam1;                          // bfxxx / fmove instruction parameter 1
+int bfparam2;                          // bfxxx / fmove instruction parameter 2
+int bfval1;                                    // bfxxx / fmove value 1
+int bfval2;                                    // bfxxx / fmove value 2
+TOKEN bf0expr[EXPRSIZE];       // Expression
+uint64_t bf0exval;                     // Expression's value
+WORD bf0exattr;                                // Expression's attribute
+SYM * bf0esym;                         // External symbol involved in expr
+
+// Function prototypes
+int Check030Bitfield(void);
 
 
 //
@@ -54,7 +85,15 @@ int amode(int acount)
        am0 = am1 = AM_NONE;
        a0expr[0] = a0oexpr[0] = a1expr[0] = a1oexpr[0] = ENDEXPR;
        a0exattr = a0oexattr = a1exattr = a1oexattr = 0;
-       a0esym = a1esym = (SYM *)NULL;
+       a0esym = a1esym = NULL;
+       a0bexpr[0] = a1bexpr[0] = ENDEXPR;
+       a0bexval = a1bexval = 0;
+       a0bsize = a0extension = a1bsize = a1extension = 0;
+       am0_030 = am1_030 = 0;
+       bfparam1 = bfparam2 = 0;
+       bf0expr[0] = ENDEXPR;
+       bf0exattr = 0;
+       bf0esym = NULL;
 
        // If at EOL, then no addr modes at all
        if (*tok == EOL)
@@ -76,13 +115,27 @@ int amode(int acount)
        #define AMn_IX0   am0_ix0
        #define AMn_IXN   am0_ixn
        #define CHK_FOR_DISPn CheckForDisp0
+       #define AnBEXPR   a0bexpr
+       #define AnBEXVAL  a0bexval
+       #define AnBEXATTR a0bexattr
+       #define AnBZISE   a0bsize
+       #define AnEXTEN   a0extension
+       #define AMn_030   am0_030
+       #define IS_SUPPRESSEDn IS_SUPPRESSED0
+       #define CHECKODn CHECKOD0
        #include "parmode.h"
 
-       // If caller wants only one mode, return just one (ignore comma); 
-       // If there is no second addressing mode (no comma), then return just one anyway.
+       // If caller wants only one mode, return just one (ignore comma);. If there
+       // is no second addressing mode (no comma), then return just one anyway.
        nmodes = 1;
 
-       if (acount == 0 || *tok != ',')
+       // it's a bitfield instruction--check the parameters inside the {} block
+       // for validity
+       if (*tok == '{')
+               if (Check030Bitfield() == ERROR)
+                       return ERROR;
+
+       if ((acount == 0) || (*tok != ','))
                return 1;
 
        // Eat the comma
@@ -104,17 +157,52 @@ int amode(int acount)
        #define AMn_IX0   am1_ix0
        #define AMn_IXN   am1_ixn
        #define CHK_FOR_DISPn CheckForDisp1
+       #define AnBEXPR   a1bexpr
+       #define AnBEXVAL  a1bexval
+       #define AnBEXATTR a1bexattr
+       #define AnBZISE   a1bsize
+       #define AnEXTEN   a1extension
+       #define AMn_030   am1_030
+       #define IS_SUPPRESSEDn IS_SUPPRESSED1
+       #define CHECKODn CHECKOD1
        #include "parmode.h"
 
+       // It's a bitfield instruction--check the parameters inside the {} block
+       // for validity
+       if (*tok == '{')
+        if (Check030Bitfield() == ERROR)
+               return ERROR;
+
+       // At this point, it is legal for 020+ to have a ':'. For example divu.l
+       // d0,d2:d3
+       if (*tok == ':')
+       {
+               if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
+                       return error(unsupport);
+
+               // TODO: protect this from combinations like Dx:FPx etc :)
+               tok++;  //eat the colon
+
+               if ((*tok >= KW_D0) && (*tok <= KW_D7))
+                       a2reg = (*tok++) & 7;
+               else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
+                       a2reg = (*tok++) & 7;
+               else
+                       return error("a data or FPU register must follow a :");
+       }
+       else
+       {
+               // If no ':' is present then maybe we have something like divs.l d0,d1
+               // which sould translate to divs.l d0,d1:d1
+               a2reg = a1reg;
+       }
+
        nmodes = 2;
        return 2;
 
        // Error messages:
-       badmode:
+badmode:
        return error("addressing mode syntax");
-
-       unmode:
-       return error("unimplemented addressing mode");
 }
 
 
@@ -135,8 +223,8 @@ int reglist(WORD * a_rmask)
 
        for(;;)
        {
-               if (*tok >= KW_D0 && *tok <= KW_A7)
-                       r = *tok++ & 15;
+               if ((*tok >= KW_D0) && (*tok <= KW_A7))
+                       r = *tok++ & 0x0F;
                else
                        break;
 
@@ -144,9 +232,9 @@ int reglist(WORD * a_rmask)
                {
                        tok++;
 
-                       if (*tok >= KW_D0 && *tok <= KW_A7)
-                               cnt = *tok++ & 15;
-                       else 
+                       if ((*tok >= KW_D0) && (*tok <= KW_A7))
+                               cnt = *tok++ & 0x0F;
+                       else
                                return error("register list syntax");
 
                        if (cnt < r)
@@ -154,7 +242,7 @@ int reglist(WORD * a_rmask)
 
                        cnt -= r;
                }
-               else 
+               else
                        cnt = 0;
 
                while (cnt-- >= 0)
@@ -171,3 +259,199 @@ int reglist(WORD * a_rmask)
        return OK;
 }
 
+
+//
+// Parse FPU register list
+//
+int fpu_reglist_left(WORD * a_rmask)
+{
+       static WORD msktab_minus[] = {
+               0x0080, 0x0040, 0x0020, 0x0010,
+               0x0008, 0x0004, 0x0002, 0x0001
+       };
+
+       WORD rmask = 0;
+       int r, cnt;
+
+       for(;;)
+       {
+               if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
+                       r = *tok++ & 0x07;
+               else
+                       break;
+
+               if (*tok == '-')
+               {
+                       tok++;
+
+                       if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
+                               cnt = *tok++ & 0x07;
+                       else
+                               return error("register list syntax");
+
+                       if (cnt < r)
+                               return error("register list order");
+
+                       cnt -= r;
+               }
+               else
+                       cnt = 0;
+
+               r = 0;
+
+               while (cnt-- >= 0)
+                       rmask |= msktab_minus[r++];
+
+               if (*tok != '/')
+                       break;
+
+               tok++;
+       }
+
+       *a_rmask = rmask;
+
+       return OK;
+}
+
+
+int fpu_reglist_right(WORD * a_rmask)
+{
+       static WORD msktab_plus[] = {
+               0x0080, 0x0040, 0x0020, 0x0010,
+               0x0008, 0x0004, 0x0002, 0x0001
+       };
+
+       WORD rmask = 0;
+       int r, cnt;
+
+       for(;;)
+       {
+               if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
+                       r = *tok++ & 0x07;
+               else
+                       break;
+
+               if (*tok == '-')
+               {
+                       tok++;
+
+                       if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
+                               cnt = *tok++ & 0x07;
+                       else
+                               return error("register list syntax");
+
+                       if (cnt < r)
+                               return error("register list order");
+
+                       cnt -= r;
+               }
+               else
+                       cnt = 0;
+
+               while (cnt-- >= 0)
+                       rmask |= msktab_plus[r++];
+
+               if (*tok != '/')
+                       break;
+
+               tok++;
+       }
+
+       *a_rmask = rmask;
+
+       return OK;
+}
+
+
+//
+// Check for bitfield instructions extra params
+// These are 020+ instructions and have the following syntax:
+// bfxxx <ea>{param1,param2}
+// param1/2 are either data registers or immediate values
+//
+int Check030Bitfield(void)
+{
+       PTR tp;
+       CHECK00;
+       tok++;
+
+       if (*tok == CONST)
+       {
+               tp.u32 = tok + 1;
+               bfval1 = (int)*tp.u64++;
+               tok = tp.u32;
+
+               // Do=0, offset=immediate - shift it to place
+               bfparam1 = (0 << 11);
+       }
+       else if (*tok == SYMBOL)
+       {
+               if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
+                       return ERROR;
+
+               if (!(bf0exattr & DEFINED))
+                       return error("bfxxx offset: immediate value must evaluate");
+
+               bfval1 = (int)bf0exval;
+
+               // Do=0, offset=immediate - shift it to place
+               bfparam1 = (0 << 11);
+       }
+       else if ((*tok >= KW_D0) && (*tok <= KW_D7))
+       {
+               // Do=1, offset=data register - shift it to place
+               bfparam1 = (1 << 11);
+               bfval1 = (*(int *)tok - 128);
+               tok++;
+       }
+       else
+               return ERROR;
+
+       // Eat the ':', if any
+       if (*tok == ':')
+               tok++;
+
+       if (*tok == '}' && tok[1] == EOL)
+       {
+               // It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
+               tok++;
+               return OK;
+       }
+
+       if (*tok == CONST)
+       {
+               tp.u32 = tok + 1;
+               bfval2 = (int)*tp.u64++;
+               tok = tp.u32;
+
+               // Do=0, offset=immediate - shift it to place
+               bfparam2 = (0 << 5);
+       }
+       else if (*tok == SYMBOL)
+       {
+               if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
+                       return ERROR;
+
+               bfval2 = (int)bf0exval;
+
+               if (!(bf0exattr & DEFINED))
+                       return error("bfxxx width: immediate value must evaluate");
+
+               // Do=0, offset=immediate - shift it to place
+               bfparam2 = (0 << 5);
+       }
+       else if ((*tok >= KW_D0) && (*tok <= KW_D7))
+       {
+               // Do=1, offset=data register - shift it to place
+               bfval2 = (*(int *)tok - 128);
+               bfparam2 = (1 << 5);
+               tok++;
+       }
+       else
+               return ERROR;
+
+       tok++;  // Eat the '}'
+
+       return OK;
+}
+