]> Shamusworld >> Repos - rmac/commitdiff
Cleanup of codebase and initial commit of 56K assembler by ggn.
authorShamus Hammons <jlhamm@acm.org>
Sat, 23 Jun 2018 16:57:21 +0000 (11:57 -0500)
committerShamus Hammons <jlhamm@acm.org>
Sat, 23 Jun 2018 16:57:21 +0000 (11:57 -0500)
There's still a ways to go before this will work properly as we need to
add proper fixup handling and origin (".org") bookkeeping. As it is now,
the addition of all the miscellaneous bits and bobs to support the main
56K assembler are in place but they don't cause any regressions to the
existing assemblers already present in RMAC. Stay tuned for Round 2!

24 files changed:
.gitignore
6502.c
6502.tab [moved from 6502.tbl with 100% similarity]
68k.mch [moved from 68ktab with 100% similarity]
68kgen.c
direct.c
direct.tab [moved from mntab with 100% similarity]
dsp56k.c [new file with mode: 0644]
dsp56k.h [new file with mode: 0644]
dsp56k.mch [new file with mode: 0644]
dsp56k_amode.c [new file with mode: 0644]
dsp56k_amode.h [new file with mode: 0644]
dsp56k_mach.c [new file with mode: 0644]
dsp56k_mach.h [new file with mode: 0644]
dsp56kgen.c [new file with mode: 0644]
expr.c
kw.tab [moved from kwtab with 73% similarity]
makefile
procln.c
risc.tab [moved from risctab with 100% similarity]
rmac.h
sect.c
sect.h
token.h

index 52dc3f724a20c6cca63e4c3d0b9f3e88db1cbea1..f229d610a573476fe07d935b380fbaaf5c09d62a 100644 (file)
@@ -1,7 +1,7 @@
 68kgen
 68kgen.o
 68ktab.h
-68kmn
+68k.tab
 6502kw.h
 opkw.h
 *.o
diff --git a/6502.c b/6502.c
index 5978240a5bfe53be35059fb0b6820c78e6653532..55c604808283f56c12b5d45373300b70029e9cb1 100644 (file)
--- a/6502.c
+++ b/6502.c
@@ -21,6 +21,9 @@
 #include "sect.h"
 #include "token.h"
 
+#define DEF_KW
+#include "kwtab.h"
+
 #define        UPSEG_SIZE      0x10010L // size of 6502 code buffer, 64K+16bytes
 
 // Internal vars
@@ -50,83 +53,83 @@ char strtoa8[128];  // ASCII to Atari 800 internal conversion table
 #define A65_IMMEDH  12
 #define A65_IMMEDL  13
 
-#define        NMACHOPS 56             // Number of machine ops
-#define        NMODES  14              // Number of addressing modes
-#define        NOP     0xEA            // 6502 NOP instruction
-#define        ILLEGAL 0xFF    // 'Illegal instr' marker
-#define END65  0xFF    // End-of-an-instr-list
+#define        NMACHOPS        56              // Number of machine ops
+#define        NMODES          14              // Number of addressing modes
+#define        NOP                     0xEA    // 6502 NOP instruction
+#define        ILLEGAL         0xFF    // 'Illegal instr' marker
+#define END65          0xFF    // End-of-an-instr-list
 
 static char imodes[] =
 {
-       A65_IMMED, 0x69, A65_ABS, 0x6d, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71,
-       A65_ZPX, 0x75, A65_ABSX, 0x7d, A65_ABSY, 0x79, END65,
-       A65_IMMED, 0x29, A65_ABS, 0x2d, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31,
-       A65_ZPX, 0x35, A65_ABSX, 0x3d, A65_ABSY, 0x39, END65,
-       A65_ABS, 0x0e, A65_ZP, 0x06, A65_IMPL, 0x0a, A65_ZPX, 0x16, A65_ABSX,
-       0x1e, END65,
+       A65_IMMED, 0x69, A65_ABS, 0x6D, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71,
+       A65_ZPX, 0x75, A65_ABSX, 0x7D, A65_ABSY, 0x79, END65,
+       A65_IMMED, 0x29, A65_ABS, 0x2D, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31,
+       A65_ZPX, 0x35, A65_ABSX, 0x3D, A65_ABSY, 0x39, END65,
+       A65_ABS, 0x0E, A65_ZP, 0x06, A65_IMPL, 0x0A, A65_ZPX, 0x16, A65_ABSX,
+       0x1E, END65,
        A65_REL, 0x90, END65,
-       A65_REL, 0xb0, END65,
-       A65_REL, 0xf0, END65,
-       A65_REL, 0xd0, END65,
+       A65_REL, 0xB0, END65,
+       A65_REL, 0xF0, END65,
+       A65_REL, 0xD0, END65,
        A65_REL, 0x30, END65,
        A65_REL, 0x10, END65,
        A65_REL, 0x50, END65,
        A65_REL, 0x70, END65,
-       A65_ABS, 0x2c, A65_ZP, 0x24, END65,
+       A65_ABS, 0x2C, A65_ZP, 0x24, END65,
        A65_IMPL, 0x00, END65,
        A65_IMPL, 0x18, END65,
-       A65_IMPL, 0xd8, END65,
+       A65_IMPL, 0xD8, END65,
        A65_IMPL, 0x58, END65,
-       A65_IMPL, 0xb8, END65,
-       A65_IMMED, 0xc9, A65_ABS, 0xcd, A65_ZP, 0xc5, A65_INDX, 0xc1, A65_INDY, 0xd1,
-       A65_ZPX, 0xd5, A65_ABSX, 0xdd, A65_ABSY, 0xd9, END65,
-       A65_IMMED, 0xe0, A65_ABS, 0xec, A65_ZP, 0xe4, END65,
-       A65_IMMED, 0xc0, A65_ABS, 0xcc, A65_ZP, 0xc4, END65,
-       A65_ABS, 0xce, A65_ZP, 0xc6, A65_ZPX, 0xd6, A65_ABSX, 0xde, END65,
-       A65_IMPL, 0xca, END65,
+       A65_IMPL, 0xB8, END65,
+       A65_IMMED, 0xC9, A65_ABS, 0xCD, A65_ZP, 0xC5, A65_INDX, 0xC1, A65_INDY, 0xD1,
+       A65_ZPX, 0xD5, A65_ABSX, 0xDD, A65_ABSY, 0xD9, END65,
+       A65_IMMED, 0xE0, A65_ABS, 0xEC, A65_ZP, 0xE4, END65,
+       A65_IMMED, 0xC0, A65_ABS, 0xCC, A65_ZP, 0xC4, END65,
+       A65_ABS, 0xCE, A65_ZP, 0xC6, A65_ZPX, 0xD6, A65_ABSX, 0xDE, END65,
+       A65_IMPL, 0xCA, END65,
        A65_IMPL, 0x88, END65,
-       A65_IMMED, 0x49, A65_ABS, 0x4d, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51,
-       A65_ZPX, 0x55, A65_ABSX, 0x5d, A65_ABSY, 0x59, END65,
-       A65_ABS, 0xee, A65_ZP, 0xe6, A65_ZPX, 0xf6, A65_ABSX, 0xfe, END65,
-       A65_IMPL, 0xe8, END65,
-       A65_IMPL, 0xc8, END65,
-       A65_ABS, 0x4c, A65_IND, 0x6c, END65,
+       A65_IMMED, 0x49, A65_ABS, 0x4D, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51,
+       A65_ZPX, 0x55, A65_ABSX, 0x5D, A65_ABSY, 0x59, END65,
+       A65_ABS, 0xEE, A65_ZP, 0xE6, A65_ZPX, 0xF6, A65_ABSX, 0xFE, END65,
+       A65_IMPL, 0xE8, END65,
+       A65_IMPL, 0xC8, END65,
+       A65_ABS, 0x4C, A65_IND, 0x6C, END65,
        A65_ABS, 0x20, END65,
-       A65_IMMED, 0xa9, A65_ABS, 0xad, A65_ZP, 0xa5, A65_INDX, 0xa1, A65_INDY, 0xb1,
-       A65_ZPX, 0xb5, A65_ABSX, 0xbd, A65_ABSY, 0xb9, A65_IMMEDH, 0xa9, A65_IMMEDL, 0xa9, END65,
-       A65_IMMED, 0xa2, A65_ABS, 0xae, A65_ZP, 0xa6, A65_ABSY, 0xbe,
-       A65_ZPY, 0xb6, A65_IMMEDH, 0xa2, A65_IMMEDL, 0xa2, END65,
-       A65_IMMED, 0xa0, A65_ABS, 0xac, A65_ZP, 0xa4, A65_ZPX, 0xb4,
-       A65_ABSX, 0xbc, A65_IMMEDH, 0xa0, A65_IMMEDL, 0xa0, END65,
-       A65_ABS, 0x4e, A65_ZP, 0x46, A65_IMPL, 0x4a, A65_ZPX, 0x56,
-       A65_ABSX, 0x5e, END65,
-       A65_IMPL, 0xea, END65,
-       A65_IMMED, 0x09, A65_ABS, 0x0d, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11,
-       A65_ZPX, 0x15, A65_ABSX, 0x1d, A65_ABSY, 0x19, END65,
+       A65_IMMED, 0xA9, A65_ABS, 0xAD, A65_ZP, 0xA5, A65_INDX, 0xA1, A65_INDY, 0xB1,
+       A65_ZPX, 0xB5, A65_ABSX, 0xBD, A65_ABSY, 0xB9, A65_IMMEDH, 0xA9, A65_IMMEDL, 0xA9, END65,
+       A65_IMMED, 0xA2, A65_ABS, 0xAE, A65_ZP, 0xA6, A65_ABSY, 0xBE,
+       A65_ZPY, 0xB6, A65_IMMEDH, 0xA2, A65_IMMEDL, 0xA2, END65,
+       A65_IMMED, 0xA0, A65_ABS, 0xAC, A65_ZP, 0xA4, A65_ZPX, 0xB4,
+       A65_ABSX, 0xBC, A65_IMMEDH, 0xA0, A65_IMMEDL, 0xA0, END65,
+       A65_ABS, 0x4E, A65_ZP, 0x46, A65_IMPL, 0x4A, A65_ZPX, 0x56,
+       A65_ABSX, 0x5E, END65,
+       A65_IMPL, 0xEA, END65,
+       A65_IMMED, 0x09, A65_ABS, 0x0D, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11,
+       A65_ZPX, 0x15, A65_ABSX, 0x1D, A65_ABSY, 0x19, END65,
        A65_IMPL, 0x48, END65,
        A65_IMPL, 0x08, END65,
        A65_IMPL, 0x68, END65,
        A65_IMPL, 0x28, END65,
-       A65_ABS, 0x2e, A65_ZP, 0x26, A65_IMPL, 0x2a, A65_ZPX, 0x36,
-       A65_ABSX, 0x3e, END65,
-       A65_ABS, 0x6e, A65_ZP, 0x66, A65_IMPL, 0x6a, A65_ZPX, 0x76,
-       A65_ABSX, 0x7e, END65,
+       A65_ABS, 0x2E, A65_ZP, 0x26, A65_IMPL, 0x2A, A65_ZPX, 0x36,
+       A65_ABSX, 0x3E, END65,
+       A65_ABS, 0x6E, A65_ZP, 0x66, A65_IMPL, 0x6A, A65_ZPX, 0x76,
+       A65_ABSX, 0x7E, END65,
        A65_IMPL, 0x40, END65,
        A65_IMPL, 0x60, END65,
-       A65_IMMED, 0xe9, A65_ABS, 0xed, A65_ZP, 0xe5, A65_INDX, 0xe1, A65_INDY, 0xf1,
-       A65_ZPX, 0xf5, A65_ABSX, 0xfd, A65_ABSY, 0xf9, END65,
+       A65_IMMED, 0xE9, A65_ABS, 0xED, A65_ZP, 0xE5, A65_INDX, 0xE1, A65_INDY, 0xF1,
+       A65_ZPX, 0xF5, A65_ABSX, 0xFD, A65_ABSY, 0xF9, END65,
        A65_IMPL, 0x38, END65,
-       A65_IMPL, 0xf8, END65,
+       A65_IMPL, 0xF8, END65,
        A65_IMPL, 0x78, END65,
-       A65_ABS, 0x8d, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95,
-       A65_ABSX, 0x9d, A65_ABSY, 0x99, END65,
-       A65_ABS, 0x8e, A65_ZP, 0x86, A65_ZPY, 0x96, END65,
-       A65_ABS, 0x8c, A65_ZP, 0x84, A65_ZPX, 0x94, END65,
-       A65_IMPL, 0xaa, END65,
-       A65_IMPL, 0xa8, END65,
-       A65_IMPL, 0xba, END65,
-       A65_IMPL, 0x8a, END65,
-       A65_IMPL, 0x9a, END65,
+       A65_ABS, 0x8D, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95,
+       A65_ABSX, 0x9D, A65_ABSY, 0x99, END65,
+       A65_ABS, 0x8E, A65_ZP, 0x86, A65_ZPY, 0x96, END65,
+       A65_ABS, 0x8C, A65_ZP, 0x84, A65_ZPX, 0x94, END65,
+       A65_IMPL, 0xAA, END65,
+       A65_IMPL, 0xA8, END65,
+       A65_IMPL, 0xBA, END65,
+       A65_IMPL, 0x8A, END65,
+       A65_IMPL, 0x9A, END65,
        A65_IMPL, 0x98, END65
 };
 
@@ -264,6 +267,14 @@ void m6502cg(int op)
                amode = A65_IMPL;
                break;
 
+       case KW_A:
+               if (tok[1] != EOL)
+                       goto badmode;
+
+               amode = A65_IMPL;
+               tok++;
+               break;
+
        case '#':
                tok++;
 
@@ -307,6 +318,7 @@ void m6502cg(int op)
                        {
                                // (foo),y
                                tok++;
+#if 0
                                p = string[tok[1]];
 
                                // Sleazo tolower() -----------------vvvvvvvvvvv
@@ -315,6 +327,15 @@ void m6502cg(int op)
 
                                tok += 2;
                                amode = A65_INDY;
+#else
+                               if (tok[0] == KW_Y)
+                                       amode = A65_INDY;
+
+                               if (tok[1] != EOL)
+                                       goto badmode;
+
+                               tok++;
+#endif
                        }
                        else
                                amode = A65_IND;
@@ -421,6 +442,7 @@ not_coinop:
                else if (*tok == ',')
                {
                        tok++;
+#if 0
                        p = string[tok[1]];
 
                        if (*tok != SYMBOL || p[1] != EOS)
@@ -441,6 +463,21 @@ not_coinop:
                                amode = A65_ABSY;
                        else
                                goto badmode;
+#else
+                       if (tok[0] == KW_X)
+                       {
+                               amode = A65_ABSX;
+                               tok++;
+                       }
+                       else if (tok[0] == KW_Y)
+                       {
+                               amode = A65_ABSY;
+                               tok++;
+                       }
+
+                       if (tok[0] != EOL)
+                               goto badmode;
+#endif
                }
                else
                        goto badmode;
@@ -568,9 +605,9 @@ badmode:
                        D_rword(eval);
                        break;
 
-                       //
-                       // Deposit 3 NOPs for illegal things
-                       //
+               //
+               // Deposit 3 NOPs for illegal things (why 3? why not 30? or zero?)
+               //
                default:
                case ILLEGAL:
                        for(i=0; i<3; i++)
@@ -583,6 +620,7 @@ badmode:
        if (sloc > 0x10000L)
                fatal("6502 code pointer > 64K");
 
+//Now why use this instead of at_eol()?
        if (*tok != EOL)
                error(extra_stuff);
 }
@@ -609,6 +647,9 @@ void m6502obj(int ofd)
 
        for(uint16_t * l=&orgmap[0][0]; l<currentorg; l+=2)
        {
+/*
+Why are we assuming endianness here? This is retarded
+*/
                exeheader[1] = l[0];
                exeheader[2] = l[1] - 1;
 
similarity index 100%
rename from 6502.tbl
rename to 6502.tab
diff --git a/68ktab b/68k.mch
similarity index 100%
rename from 68ktab
rename to 68k.mch
index ce156135ddc3c5bd69cca83e32177ee036e39f9e..ca3ce71b8f4c1ed16f043fd5a649d4abd1afecb5 100644 (file)
--- a/68kgen.c
+++ b/68kgen.c
@@ -76,12 +76,11 @@ int main(int argc, char ** argv)
 void procln(int namc, char ** namv)
 {
        int i, j;
-       char * s;
 
        // alias for previous entry
        if (namc == 1)
        {
-               fprintf(kfp, "%s\t%d\n", namv[0], kwnum-1+1000);
+               fprintf(kfp, "%s\t%d\n", namv[0], kwnum - 1 + 1000);
                return;
        }
 
@@ -99,7 +98,7 @@ void procln(int namc, char ** namv)
 
        if (*namv[1] == '!')
                printf("CGSPECIAL");
-       else for (s = namv[1], i=0; *s; ++s)
+       else for(char * s=namv[1], i=0; *s; s++)
                printf("%sSIZ%c", (i++ ? "|" : ""), *s);
 
        printf(", %s, %s, ", namv[2], namv[3]);
@@ -107,12 +106,12 @@ void procln(int namc, char ** namv)
        // enforce little fascist percent signs
        if (*namv[4] == '%')
        {
-               for(i=1, j=0; i<17; ++i)
+               for(i=1, j=0; i<17; i++)
                {
                        j <<= 1;
 
                        if (namv[4][i] == '1' || isupper(namv[4][i]))
-                               ++j;
+                               j++;
                }
 
                printf("0x%04x, ", j);
@@ -121,7 +120,7 @@ void procln(int namc, char ** namv)
                printf("%s, ", namv[4]);
 
        if (namc == 7 && *namv[6] == '+')
-               printf("%d, ", kwnum+1);
+               printf("%d, ", kwnum + 1);
        else
                printf("0, ");
 
index cd9c637ee05c2024d5cd6a8cc4e103caa18c6b5d..294ea4ac32649b19846bc8a69f5951c5ca522278 100644 (file)
--- a/direct.c
+++ b/direct.c
@@ -218,10 +218,11 @@ int d_org(void)
 {
        uint64_t address;
 
-       if (!rgpu && !rdsp && !robjproc && !m6502)
-               return error(".org permitted only in GPU/DSP/OP and 6502 sections");
+       if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001)
+               return error(".org permitted only in GPU/DSP/OP, 56001 and 6502 sections");
 
-       if (abs_expr(&address) == ERROR)
+       // M56K can leave the expression off the org for some reason :-/
+       if ((abs_expr(&address) == ERROR) && !dsp56001)
        {
                error("cannot determine org'd address");
                return ERROR;
@@ -232,9 +233,9 @@ int d_org(void)
                orgaddr = address;
                orgactive = 1;
        }
-       else
+       else if (m6502)
        {
-               // 6502.  We also kludge `lsloc' so the listing generator doesn't try
+               // 6502.  We also kludge 'lsloc' so the listing generator doesn't try
                // to spew out megabytes.
                if (address > 0xFFFF)
                        return error(range_error);
@@ -251,9 +252,12 @@ int d_org(void)
                chptr = scode->chptr + address;
                orgaddr = address;
                orgactive = 1;
-               at_eol();
+       }
+       else if (dsp56001)
+       {
        }
 
+       at_eol();
        return 0;
 }
 
@@ -290,25 +294,39 @@ int d_print(void)
                case '/':
                        formatting = 1;
 
-                       if (tok[1] != SYMBOL)
+                       // "X" & "L" get tokenized now... :-/ Probably should look into preventing this kind of thing from happening (was added with DSP56K code)
+                       if ((tok[1] != SYMBOL) && (tok[1] != KW_L) && (tok[1] != KW_X))
                                goto token_err;
 
-//                     strcpy(prntstr, (char *)tok[2]);
-                       strcpy(prntstr, string[tok[2]]);
-
-                       switch(prntstr[0])
+                       if (tok[1] == KW_L)
                        {
-                       case 'l': case 'L': wordlong = 1; break;
-                       case 'w': case 'W': wordlong = 0; break;
-                       case 'x': case 'X': outtype  = 0; break;
-                       case 'd': case 'D': outtype  = 1; break;
-                       case 'u': case 'U': outtype  = 2; break;
-                       default:
-                               error("unknown print format flag");
-                               return ERROR;
+                               wordlong = 1;
+                               tok += 2;
+                       }
+                       else if (tok[1] == KW_X)
+                       {
+                               outtype = 0;
+                               tok += 2;
+                       }
+                       else
+                       {
+                               strcpy(prntstr, string[tok[2]]);
+
+                               switch(prntstr[0])
+                               {
+                               case 'l': case 'L': wordlong = 1; break;
+                               case 'w': case 'W': wordlong = 0; break;
+                               case 'x': case 'X': outtype  = 0; break;
+                               case 'd': case 'D': outtype  = 1; break;
+                               case 'u': case 'U': outtype  = 2; break;
+                               default:
+                                       error("unknown print format flag");
+                                       return ERROR;
+                               }
+
+                               tok += 3;
                        }
 
-                       tok += 3;
                        break;
                case ',':
                        tok++;
@@ -349,7 +367,7 @@ int d_print(void)
        return 0;
 
 token_err:
-       error("illegal print token");
+       error("illegal print token [@ '%s']", prntstr);
        return ERROR;
 }
 
@@ -958,7 +976,7 @@ int d_ds(WORD siz)
 
        uint64_t eval;
 
-       if (cursect != M6502)
+       if ((cursect & (M6502 | M56KPXYL)) == 0)
        {
                if ((siz != SIZB) && (sloc & 1))        // Automatic .even
                        auto_even();
@@ -1036,7 +1054,7 @@ int d_dc(WORD siz)
                                for(p=string[tok[1]]; *p!=EOS; p++)
                                        D_byte(*p);
                        }
-                       else if(*tok == STRINGA8)
+                       else if (*tok == STRINGA8)
                        {
                                for(p=string[tok[1]]; *p!=EOS; p++)
                                        D_byte(strtoa8[*p]);
@@ -1496,7 +1514,7 @@ int d_nlist(void)
 //
 int d_68000(void)
 {
-       rgpu = rdsp = robjproc = 0;
+       rgpu = rdsp = robjproc = dsp56001 = 0;
        // Switching from gpu/dsp sections should reset any ORG'd Address
        orgactive = 0;
        orgwarning = 0;
@@ -1586,11 +1604,18 @@ int d_nofpu(void)
 
 
 //
-// DSP56001
+// .56001 - Switch to DSP56001 assembler
 //
 int d_56001(void)
 {
-       return error("Not yet, child. Be patient.");
+       dsp56001 = 1;
+       rgpu = rdsp = robjproc = 0;
+       SaveSection();
+
+       if (obj_format == LOD || obj_format == P56)
+               SwitchSection(M56001P);
+
+       return 0;
 }
 
 
@@ -1615,6 +1640,7 @@ int d_gpu(void)
        rgpu = 1;                       // Set GPU assembly
        rdsp = 0;                       // Unset DSP assembly
        robjproc = 0;           // Unset OP assembly
+       dsp56001 = 0;           // Unset 56001 assembly
        regbank = BANK_N;       // Set no default register bank
        return 0;
 }
@@ -1641,6 +1667,7 @@ int d_dsp(void)
        rdsp = 1;                       // Set DSP assembly
        rgpu = 0;                       // Unset GPU assembly
        robjproc = 0;           // Unset OP assembly
+       dsp56001 = 0;           // Unset 56001 assembly
        regbank = BANK_N;       // Set no default register bank
        return 0;
 }
@@ -1913,6 +1940,7 @@ int d_objproc(void)
        robjproc = 1;           // Set OP assembly
        rgpu = 0;                       // Unset GPU assembly
        rdsp = 0;                       // Unset DSP assembly
+       dsp56001 = 0;           // Unset 56001 assembly
        return OK;
 }
 
similarity index 100%
rename from mntab
rename to direct.tab
diff --git a/dsp56k.c b/dsp56k.c
new file mode 100644 (file)
index 0000000..50e8601
--- /dev/null
+++ b/dsp56k.c
@@ -0,0 +1,15 @@
+//
+// RMAC - Reboot's Macro Assembler for all Atari computers
+// DSP56K.C - General DSP56001 routines
+// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source utilised with the kind permission of Landon Dyer
+//
+
+#include "rmac.h"
+#include "dsp56k.h"
+
+DSP_ORG dsp_orgmap[1024];              // Mark all 56001 org changes
+DSP_ORG * dsp_currentorg = &dsp_orgmap[0];
+int dsp_written_data_in_current_org = 0;
+
diff --git a/dsp56k.h b/dsp56k.h
new file mode 100644 (file)
index 0000000..c73e99e
--- /dev/null
+++ b/dsp56k.h
@@ -0,0 +1,42 @@
+//
+// RMAC - Reboot's Macro Assembler for all Atari computers
+// DSP56K.H - General DSP56001 routines
+// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source utilised with the kind permission of Landon Dyer
+//
+
+#pragma once
+
+#include "rmac.h"
+#include "sect.h"
+
+// Exported variables.
+#define DSP_MAX_RAM (32*3*1024)                        // 32k 24-bit words
+#define DSP_ORG struct dsp56001_orgentry
+
+enum MEMTYPES
+{
+       ORG_P,
+       ORG_X,
+       ORG_Y,
+       ORG_L
+} ;
+
+DSP_ORG
+{
+       enum MEMTYPES memtype;
+       uint8_t * start;
+       uint8_t * end;
+       uint32_t orgadr;
+       CHUNK * chunk;
+};
+
+extern DSP_ORG dsp_orgmap[1024];               // Mark all 56001 org changes
+extern DSP_ORG * dsp_currentorg;
+extern int dsp_written_data_in_current_org;
+
+#define dprintf(...) p_buf += sprintf(p_buf, __VA_ARGS__)
+
+// Exported functions
+
diff --git a/dsp56k.mch b/dsp56k.mch
new file mode 100644 (file)
index 0000000..c73ecaf
--- /dev/null
@@ -0,0 +1,336 @@
+abs     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0010d110  dsp_ab                   d=(a=0, b=1)\r
+asl     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0011d010  dsp_ab                   d=(a=0, b=1)\r
+asr     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0010d010  dsp_ab                   d=(a=0, b=1)\r
+clr     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0001d011  dsp_ab                   d=(a=0, b=1)\r
+lsl     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0011d011  dsp_ab                   d=(a=0, b=1)\r
+lsr     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0010d011  dsp_ab                   d=(a=0, b=1)\r
+not     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0001d111  dsp_ab                   d=(a=0, b=1)\r
+addl    M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0001d010  dsp_baab                 d=(b,a=0, a,b=1)\r
+addr    M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0000d010  dsp_baab                 d=(b,a=0, a,b=1)\r
+add     M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0001d000  dsp_baab           +     d=(a=0, b=1)\r
+-       M_ALL48    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0jjjd000  dsp_acc48                jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1)\r
+cmp     M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0000d101  dsp_baab           +     d=(a=0, b=1)\r
+-       M_ALU24    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0jjjd101  dsp_acc48                jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1)\r
+cmpm    M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0000d111  dsp_baab           +     d=(a=0, b=1)\r
+-       M_ALU24    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0jjjd111  dsp_acc48                jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1)\r
+sub     M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0001d100  dsp_baab           +     d=(a=0, b=1)\r
+-       M_ALL48    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0jjjd100  dsp_acc48                jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1)\r
+tfr     M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0000d001  dsp_baab           +     d=(a=0, b=1)\r
+-       M_ALU24    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0jjjd001  dsp_acc48                jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1)      \r
+rnd     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0001d001  dsp_ab                   d=(a=0, b=1)\r
+rol     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0011d111  dsp_ab                   d=(a=0, b=1)\r
+ror     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0010d111  dsp_ab                   d=(a=0, b=1)\r
+subl    M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0001d110  dsp_baab                 d=(b,a=0, a,b=1)\r
+subr    M_ACC56    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm0000d110  dsp_baab                 d=(b,a=0, a,b=1)\r
+tst     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0000d011  dsp_ab                   d=(a=0, b=1)\r
+enddo   M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000010001100  dsp_self\r
+illegal M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000000000101  dsp_self\r
+nop     M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000000000000  dsp_self\r
+reset   M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000010000100  dsp_self\r
+rti     M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000000000100  dsp_self\r
+rts     M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000000001100  dsp_self\r
+stop    M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000010000111  dsp_self\r
+swi     M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000000000110  dsp_self\r
+wait    M_AM_NONE  M_AM_NONE    NOPARMO %000000000000000010000110  dsp_self\r
+adc     M_INP48    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm001jd001  dsp_xyab                 j=(x=0, y=1), d=(a=0, b=1)\r
+sbc     M_INP48    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm001jd101  dsp_xyab                 s1 (j)=(x=0,y=1),s2 (d)=(a=0,b=1)\r
+and     M_ALU24    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm01jjd110  dsp_x0y0ab               jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1)\r
+eor     M_ALU24    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm01jjd011  dsp_x0y0ab               jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1)\r
+div     M_ALU24    M_ACC56      NOPARMO %000000011000000001jjd000  dsp_x0y0ab               jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1)\r
+or      M_ALU24    M_ACC56      PARMOVE %mmmmmmmmmmmmmmmm01jjd010  dsp_x0y0ab               jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1)\r
+andi    M_DSPIM8   M_DSPPCU     NOPARMO %00000000iiiiiiii101110ee  dsp_immcr                ee=(mr=0, ccr=1, omr=2)\r
+ori     M_DSPIM8   M_DSPPCU     NOPARMO %00000000iiiiiiii111110ee  dsp_immcr                ee=(mr=0, ccr=1, omr=2)\r
+tcc     M_ACC56    M_ACC56      NOPARMO %00000010000000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010000000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+ths     M_ACC56    M_ACC56      NOPARMO %00000010000000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010000000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tcs     M_ACC56    M_ACC56      NOPARMO %00000010100000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010100000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tlo     M_ACC56    M_ACC56      NOPARMO %00000010100000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010100000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tec     M_ACC56    M_ACC56      NOPARMO %00000010010100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010010100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+teq     M_ACC56    M_ACC56      NOPARMO %00000010101000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010101000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tes     M_ACC56    M_ACC56      NOPARMO %00000010110100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010110100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tge     M_ACC56    M_ACC56      NOPARMO %00000010000100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010000100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tgt     M_ACC56    M_ACC56      NOPARMO %00000010011100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010011100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tlc     M_ACC56    M_ACC56      NOPARMO %00000010011000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010011000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tle     M_ACC56    M_ACC56      NOPARMO %00000010111100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010111100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tls     M_ACC56    M_ACC56      NOPARMO %00000010111000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010111000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tlt     M_ACC56    M_ACC56      NOPARMO %00000010100100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010100100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tmi     M_ACC56    M_ACC56      NOPARMO %00000010101100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010101100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tne     M_ACC56    M_ACC56      NOPARMO %00000010001000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010001000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tnr     M_ACC56    M_ACC56      NOPARMO %00000010110000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010110000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tpl     M_ACC56    M_ACC56      NOPARMO %00000010001100000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010001100000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+tnn     M_ACC56    M_ACC56      NOPARMO %00000010010000000jjjd000  dsp_baab           +     s1,d1 [s2,d2]\r
+-       M_ALL48    M_ACC56      NOPARMO %00000010010000000jjjd000  dsp_tcc2                 s1,d1 [s2,d2]\r
+jcc     M_DSPABS12 M_AM_NONE    NOPARMO %000011100000aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100000  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jhs     M_DSPABS12 M_AM_NONE    NOPARMO %000011100000aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100000  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jcs     M_DSPABS12 M_AM_NONE    NOPARMO %000011101000aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101000  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jlo     M_DSPABS12 M_AM_NONE    NOPARMO %000011101000aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101000  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jec     M_DSPABS12 M_AM_NONE    NOPARMO %000011100101aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100101  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jeq     M_DSPABS12 M_AM_NONE    NOPARMO %000011101010aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101010  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jes     M_DSPABS12 M_AM_NONE    NOPARMO %000011101101aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101101  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jge     M_DSPABS12 M_AM_NONE    NOPARMO %000011100001aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100001  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jgt     M_DSPABS12 M_AM_NONE    NOPARMO %000011100111aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100111  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jge     M_DSPABS12 M_AM_NONE    NOPARMO %000011100001aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100001  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jlc     M_DSPABS12 M_AM_NONE    NOPARMO %000011100110aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100110  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jle     M_DSPABS12 M_AM_NONE    NOPARMO %000011101111aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101111  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jls     M_DSPABS12 M_AM_NONE    NOPARMO %000011101110aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101110  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jlt     M_DSPABS12 M_AM_NONE    NOPARMO %000011101001aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101001  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jmi     M_DSPABS12 M_AM_NONE    NOPARMO %000011101011aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101011  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jne     M_DSPABS12 M_AM_NONE    NOPARMO %000011100010aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100010  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jnr     M_DSPABS12 M_AM_NONE    NOPARMO %000011101100aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10101100  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jpl     M_DSPABS12 M_AM_NONE    NOPARMO %000011100011aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100011  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jnn     M_DSPABS12 M_AM_NONE    NOPARMO %000011100100aaaaaaaaaaaa  dsp_abs12          +     Jcc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10100100  dsp_ea                   Jcc ea mmmrrr=ea  \r
+jmp     M_DSPABS12 M_AM_NONE    NOPARMO %000011000000aaaaaaaaaaaa  dsp_abs12          +     JMP  xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101011mmmrrr10000000  dsp_ea                   JMP ea (+optional 24bit address)  \r
+jscc    M_DSPABS12 M_AM_NONE    NOPARMO %000011110000aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100000  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jshs    M_DSPABS12 M_AM_NONE    NOPARMO %000011110000aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100000  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jscs    M_DSPABS12 M_AM_NONE    NOPARMO %000011111000aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101000  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jslo    M_DSPABS12 M_AM_NONE    NOPARMO %000011111000aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101000  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsec    M_DSPABS12 M_AM_NONE    NOPARMO %000011110101aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100101  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jseq    M_DSPABS12 M_AM_NONE    NOPARMO %000011111010aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101010  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jses    M_DSPABS12 M_AM_NONE    NOPARMO %000011111101aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101101  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsge    M_DSPABS12 M_AM_NONE    NOPARMO %000011110001aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100001  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsgt    M_DSPABS12 M_AM_NONE    NOPARMO %000011110111aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100111  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jslc    M_DSPABS12 M_AM_NONE    NOPARMO %000011110110aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100110  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsle    M_DSPABS12 M_AM_NONE    NOPARMO %000011111111aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101111  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsls    M_DSPABS12 M_AM_NONE    NOPARMO %000011111110aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101110  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jslt    M_DSPABS12 M_AM_NONE    NOPARMO %000011111001aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101001  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsmi    M_DSPABS12 M_AM_NONE    NOPARMO %000011111011aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101011  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsne    M_DSPABS12 M_AM_NONE    NOPARMO %000011110010aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100010  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsnr    M_DSPABS12 M_AM_NONE    NOPARMO %000011111100aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10101100  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jspl    M_DSPABS12 M_AM_NONE    NOPARMO %000011110011aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100011  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsnn    M_DSPABS12 M_AM_NONE    NOPARMO %000011110100aaaaaaaaaaaa  dsp_abs12          +     JScc xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10100100  dsp_ea                   JScc ea mmmrrr=ea (+optional 24bit address)  \r
+jsr     M_DSPABS12 M_AM_NONE    NOPARMO %000011010000aaaaaaaaaaaa  dsp_abs12          +     JSR  xxx aaaaaaaaaaaa=12bit address \r
+-       C_DSPABSEA M_AM_NONE    NOPARMO %0000101111mmmrrr10000000  dsp_ea                   JSR ea mmmrrr=ea  (+optional 24bit address)  \r
+neg     M_ACC56    M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm0011d110  dsp_ab                   d=(a=0, b=1)\r
+bchg    C_DSPIM    M_DSPEA      NOPARMO %0000101101mmmrrr0s0bbbbb  dsp_ea_imm5        +     bchg #n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101100aaaaaa0s0bbbbb  dsp_ea_imm5        +     bchg #n,X:aa / bchg #n,Y:aa\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101110pppppp0s0bbbbb  dsp_ea_imm5        +     bchg #n,X:pp / bchg #n,Y:pp\r
+-       C_DSPIM    C_DD         NOPARMO %00001011110001dd010bbbbb  dsp_reg_imm5       +     bchg #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101111001ddd010bbbbb  dsp_reg_imm5       +     bchg #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101111010ddd010bbbbb  dsp_reg_imm5       +     bchg #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101111011ddd010bbbbb  dsp_reg_imm5       +     bchg #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101111100ddd010bbbbb  dsp_reg_imm5       +     bchg #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101111111ddd010bbbbb  dsp_reg_imm5             bchg #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+bclr    C_DSPIM    M_DSPEA      NOPARMO %0000101001mmmrrr0s0bbbbb  dsp_ea_imm5        +     bclr #n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101000aaaaaa0s0bbbbb  dsp_ea_imm5        +     bclr #n,X:aa / bclr #n,Y:aa\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101010pppppp0s0bbbbb  dsp_ea_imm5        +     bclr #n,X:pp / bclr #n,Y:pp\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101011001ddd010bbbbb  dsp_reg_imm5       +     bclr #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DD         NOPARMO %00001010110001dd010bbbbb  dsp_reg_imm5       +     bclr #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101011010ddd010bbbbb  dsp_reg_imm5       +     bclr #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101011011ddd010bbbbb  dsp_reg_imm5       +     bclr #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101011100ddd010bbbbb  dsp_reg_imm5       +     bclr #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101011111ddd010bbbbb  dsp_reg_imm5             bclr #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+bset    C_DSPIM    M_DSPEA      NOPARMO %0000101001mmmrrr0s1bbbbb  dsp_ea_imm5        +     bset #n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101000aaaaaa0s1bbbbb  dsp_ea_imm5        +     bset #n,X:aa / bset #n,Y:aa\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101010pppppp0s1bbbbb  dsp_ea_imm5        +     bset #n,X:pp / bset #n,Y:pp\r
+-       C_DSPIM    C_DD         NOPARMO %00001010110001dd011bbbbb  dsp_reg_imm5       +     bset #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101011001ddd011bbbbb  dsp_reg_imm5       +     bset #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101011010ddd011bbbbb  dsp_reg_imm5       +     bset #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101011011ddd011bbbbb  dsp_reg_imm5       +     bset #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101011100ddd011bbbbb  dsp_reg_imm5       +     bset #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101011111ddd011bbbbb  dsp_reg_imm5             bset #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+btst    C_DSPIM    M_DSPEA      NOPARMO %0000101101mmmrrr0s1bbbbb  dsp_ea_imm5        +     btst#n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101100aaaaaa0s1bbbbb  dsp_ea_imm5        +     btst #n,X:aa / btst #n,Y:aa\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101110pppppp0s1bbbbb  dsp_ea_imm5        +     btst #n,X:pp / btst #n,Y:pp\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101111001ddd011bbbbb  dsp_reg_imm5       +     btst #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DD         NOPARMO %00001011110001dd011bbbbb  dsp_reg_imm5       +     btst #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101111010ddd011bbbbb  dsp_reg_imm5       +     btst #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101111011ddd011bbbbb  dsp_reg_imm5       +     btst #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101111100ddd011bbbbb  dsp_reg_imm5       +     btst #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101111111ddd011bbbbb  dsp_reg_imm5             btst #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+do      M_DSPEA    C_DSPABS24   NOPARMO %0000011001mmmrrr0s000000  dsp_ea_abs16       +     DO X:ea,expr / DO Y:ea,expr mmmrrr=ea, s=(X=0, Y=1), expr=16bit in extension word\r
+-       M_DSPAA    C_DSPABS24   NOPARMO %0000011000aaaaaa0s000000  dsp_ea_abs16       +     DO X:aa,expr / DO Y:aa,expr aaaaaa=aa, s=(X=0, Y=1), expr=16bit in extension word\r
+-       C_DSPIM    C_DSPABS24   NOPARMO %00000110iiiiiiii1000hhhh  dsp_imm12_abs16    +     DO #xxx,expr hhhhiiiiiiii=12bit immediate, expr=16bit in extension word\r
+-       M_ALU24    C_DSPABS24   NOPARMO %0000011011000ddd00000000  dsp_alu24_abs16    +     DO S,expr x0, x1, y0, y1\r
+-       C_DDD      C_DSPABS24   NOPARMO %0000011011001ddd00000000  dsp_reg_abs16      +     DO S,expr DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_TTT      C_DSPABS24   NOPARMO %0000011011010ddd00000000  dsp_reg_abs16      +     DO S,expr TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_NNN      C_DSPABS24   NOPARMO %0000011011011ddd00000000  dsp_reg_abs16      +     DO S,expr NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_FFF      C_DSPABS24   NOPARMO %0000011011100ddd00000000  dsp_reg_abs16      +     DO S,expr FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_GGG      C_DSPABS24   NOPARMO %0000011011111ddd00000000  dsp_reg_abs16            DO S,expr GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+rep     C_DSPIM    M_AM_NONE    NOPARMO %00000110iiiiiiii1010hhhh  dsp_imm12          +     rep #xx\r
+-       M_DSPEA    M_AM_NONE    NOPARMO %0000011001mmmrrr0s100000  dsp_ea             +     rep x:ea / y:ea\r
+-       M_DSPAA    M_AM_NONE    NOPARMO %0000011000aaaaaa0s100000  dsp_ea             +     rep x:aa / y:aa\r
+-       M_ALU24    M_AM_NONE    NOPARMO %0000011011000ddd00100000  dsp_alu24          +     rep S,expr x0, x1, y0, y1\r
+-       C_DDD      M_AM_NONE    NOPARMO %0000011011001ddd00100000  dsp_reg            +     rep S DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_TTT      M_AM_NONE    NOPARMO %0000011011010ddd00100000  dsp_reg            +     rep S TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_NNN      M_AM_NONE    NOPARMO %0000011011011ddd00100000  dsp_reg            +     rep S NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_FFF      M_AM_NONE    NOPARMO %0000011011100ddd00100000  dsp_reg            +     rep S FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_GGG      M_AM_NONE    NOPARMO %0000011011111ddd00100000  dsp_reg                  rep S GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+jsclr   C_DSPIM    M_DSPEA      NOPARMO %0000101101mmmrrr1s0bbbbb  dsp_ea_imm5_abs16  +     JSCLR #n,X:ea,xxxx / #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101100aaaaaa1s0bbbbb  dsp_ea_imm5_abs16  +     JSCLR #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101110pppppp1s0bbbbb  dsp_ea_imm5_abs16  +     JSCLR #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1)\r
+-       C_DSPIM    C_DD         NOPARMO %00001011110001dd000bbbbb  dsp_reg_imm5_abs16 +     JSCLR  #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101111001ddd000bbbbb  dsp_reg_imm5_abs16 +     JSCLR  #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101111010ddd000bbbbb  dsp_reg_imm5_abs16 +     JSCLR  #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101111011ddd000bbbbb  dsp_reg_imm5_abs16 +     JSCLR  #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101111100ddd000bbbbb  dsp_reg_imm5_abs16 +     JSCLR  #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101111101ddd000bbbbb  dsp_reg_imm5_abs16       JSCLR  #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+jset    C_DSPIM    M_DSPEA      NOPARMO %0000101001mmmrrr1s1bbbbb  dsp_ea_imm5_abs16  +     JSET  #n,X:ea,xxxx / #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101000aaaaaa1s1bbbbb  dsp_ea_imm5_abs16  +     JSET  #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101010pppppp1s1bbbbb  dsp_ea_imm5_abs16  +     JSET  #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1)\r
+-       C_DSPIM    C_DD         NOPARMO %00001010110001dd001bbbbb  dsp_reg_imm5_abs16 +     JSET  #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101011001ddd001bbbbb  dsp_reg_imm5_abs16 +     JSET  #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101011010ddd001bbbbb  dsp_reg_imm5_abs16 +     JSET  #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101011011ddd001bbbbb  dsp_reg_imm5_abs16 +     JSET  #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101011100ddd001bbbbb  dsp_reg_imm5_abs16 +     JSET  #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101011101ddd001bbbbb  dsp_reg_imm5_abs16       JSET  #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+jsset   C_DSPIM    M_DSPEA      NOPARMO %0000101101mmmrrr1s1bbbbb  dsp_ea_imm5_abs16  +     JSSET #n,X:ea,xxxx / JSSET #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101100aaaaaa1s1bbbbb  dsp_ea_imm5_abs16  +     JSSET #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101110pppppp1s1bbbbb  dsp_ea_imm5_abs16  +     JSSET #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1)\r
+-       C_DSPIM    C_DD         NOPARMO %00001011110001dd001bbbbb  dsp_reg_imm5_abs16 +     JSSET #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101111001ddd001bbbbb  dsp_reg_imm5_abs16 +     JSSET #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101111010ddd001bbbbb  dsp_reg_imm5_abs16 +     JSSET #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101111011ddd001bbbbb  dsp_reg_imm5_abs16 +     JSSET #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101111100ddd001bbbbb  dsp_reg_imm5_abs16 +     JSSET #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101111101ddd001bbbbb  dsp_reg_imm5_abs16       JSSET #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+jclr    C_DSPIM    M_DSPEA      NOPARMO %0000101001mmmrrr1s0bbbbb  dsp_ea_imm5_abs16  +     JCLR  #n,X:ea,xxxx / #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPAA      NOPARMO %0000101000aaaaaa1s0bbbbb  dsp_ea_imm5_abs16  +     JCLR  #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1)\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000101010pppppp1s0bbbbb  dsp_ea_imm5_abs16  +     JCLR  #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1)\r
+-       C_DSPIM    C_DD         NOPARMO %00001010110001dd000bbbbb  dsp_reg_imm5_abs16 +     JCLR  #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_DDD        NOPARMO %0000101011001ddd000bbbbb  dsp_reg_imm5_abs16 +     JCLR  #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_TTT        NOPARMO %0000101011010ddd000bbbbb  dsp_reg_imm5_abs16 +     JCLR  #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_NNN        NOPARMO %0000101011011ddd000bbbbb  dsp_reg_imm5_abs16 +     JCLR  #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_FFF        NOPARMO %0000101011100ddd000bbbbb  dsp_reg_imm5_abs16 +     JCLR  #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+-       C_DSPIM    C_GGG        NOPARMO %0000101011101ddd000bbbbb  dsp_reg_imm5_abs16       JCLR  #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings.\r
+lua     M_DSPEA    C_LUADST     NOPARMO %00000100010mmrrr0001dddd  dsp_ea_lua               mmrrr=ea (subset), dddd=(bit 3=(0=Rn, 1=Nn), bits 2-0=0-7)\r
+norm    M_DSPR     M_ACC56      NOPARMO %0000000111011rrr0001d101  dsp_ab_rn                norm Rn,D D=(a=0, b=1)\r
+move    M_AM_NONE  M_AM_NONE    PARMOVE %mmmmmmmmmmmmmmmm00000000  dsp_self\r
+movec   M_DSPIM8   C_MOVEC      NOPARMO %00000101iiiiiiii101ddddd  dsp_immmovec       +     move(c) #xx,d1\r
+-       M_DSPEA    C_MOVEC      NOPARMO %0000010111mmmrrr0s1ddddd  dsp_movec_ea       +     move(c) x:ea,d1 / y:ea,d1\r
+-       C_MOVEC    M_DSPEA      NOPARMO %0000010101mmmrrr0s1ddddd  dsp_movec_ea       +     move(c) s1,x:ea / s1,y:ea\r
+-       C_DSPIM    C_MOVEC      NOPARMO %0000010111110100001ddddd  dsp_movec_ea       +     move(c) #xxxx,d1\r
+-       M_DSPAA    C_MOVEC      NOPARMO %0000010110aaaaaa0s1ddddd  dsp_movec_aa       +     move(c) x:aa,d1 / y:aa,d1 \r
+-       C_MOVEC    M_DSPAA      NOPARMO %0000010100aaaaaa0s1ddddd  dsp_movec_aa       +     move(c) s1,x:aa / s1,y:aa\r
+-       C_MOVEC    M_ALU24      NOPARMO %0000010001000eee101ddddd  dsp_movec_reg      +     move(c) s1,d2 \r
+-       C_MOVEC    C_DDD        NOPARMO %0000010001001eee101ddddd  dsp_movec_reg      +     move(c) s1,d2 \r
+-       C_MOVEC    C_TTT        NOPARMO %0000010001010eee101ddddd  dsp_movec_reg      +     move(c) s1,d2 \r
+-       C_MOVEC    C_NNN        NOPARMO %0000010001011eee101ddddd  dsp_movec_reg      +     move(c) s1,d2 \r
+-       C_MOVEC    C_FFF        NOPARMO %0000010001100eee101ddddd  dsp_movec_reg      +     move(c) s1,d2 \r
+-       C_MOVEC    C_GGG        NOPARMO %0000010001111eee101ddddd  dsp_movec_reg      +     move(c) s1,d2 \r
+-       M_ALU24    C_MOVEC      NOPARMO %0000010011000eee101ddddd  dsp_movec_reg      +     move(c) s2,d1\r
+-       C_DDD      C_MOVEC      NOPARMO %0000010011001eee101ddddd  dsp_movec_reg      +     move(c) s2,d1\r
+-       C_TTT      C_MOVEC      NOPARMO %0000010011010eee101ddddd  dsp_movec_reg      +     move(c) s2,d1\r
+-       C_NNN      C_MOVEC      NOPARMO %0000010011011eee101ddddd  dsp_movec_reg      +     move(c) s2,d1\r
+-       C_FFF      C_MOVEC      NOPARMO %0000010011100eee101ddddd  dsp_movec_reg      +     move(c) s2,d1\r
+-       C_GGG      C_MOVEC      NOPARMO %0000010011111eee101ddddd  dsp_movec_reg            move(c) s2,d1\r
+movem   M_ALU24    M_DSPEA      NOPARMO %0000011101mmmrrr10000ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       C_DDD      M_DSPEA      NOPARMO %0000011101mmmrrr10001ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       C_TTT      M_DSPEA      NOPARMO %0000011101mmmrrr10010ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       C_NNN      M_DSPEA      NOPARMO %0000011101mmmrrr10011ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       C_FFF      M_DSPEA      NOPARMO %0000011101mmmrrr10100ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       C_GGG      M_DSPEA      NOPARMO %0000011101mmmrrr10111ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_DSPEA    M_ALU24      NOPARMO %0000011111mmmrrr10000ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_DSPEA    C_DDD        NOPARMO %0000011111mmmrrr10001ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_DSPEA    C_TTT        NOPARMO %0000011111mmmrrr10010ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_DSPEA    C_NNN        NOPARMO %0000011111mmmrrr10011ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_DSPEA    C_FFF        NOPARMO %0000011111mmmrrr10100ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_DSPEA    C_GGG        NOPARMO %0000011111mmmrrr10111ddd  dsp_movem_ea       +     move(m) s,p:ea / p:ea,d\r
+-       M_ALU24    M_DSPAA      NOPARMO %0000011100aaaaaa00000ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       C_DDD      M_DSPAA      NOPARMO %0000011100aaaaaa00001ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       C_TTT      M_DSPAA      NOPARMO %0000011100aaaaaa00010ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       C_NNN      M_DSPAA      NOPARMO %0000011100aaaaaa00011ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       C_FFF      M_DSPAA      NOPARMO %0000011100aaaaaa00100ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       C_GGG      M_DSPAA      NOPARMO %0000011100aaaaaa00111ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       M_DSPAA    M_ALU24      NOPARMO %0000011110aaaaaa00000ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       M_DSPAA    C_DDD        NOPARMO %0000011110aaaaaa00001ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       M_DSPAA    C_TTT        NOPARMO %0000011110aaaaaa00010ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       M_DSPAA    C_NNN        NOPARMO %0000011110aaaaaa00011ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       M_DSPAA    C_FFF        NOPARMO %0000011110aaaaaa00100ddd  dsp_movem_aa       +     move(m) s,p:aa / p:aa,d\r
+-       M_DSPAA    C_GGG        NOPARMO %0000011110aaaaaa00111ddd  dsp_movem_aa             move(m) s,p:aa / p:aa,d\r
+mac     M_ALU24    M_ALU24      PARMOVE %mmmmmmmmmmmmmmmm1qqqdk10  dsp_mult                 mac -+s1,s2,d / mac -+s2,s1,d\r
+macr    M_ALU24    M_ALU24      PARMOVE %mmmmmmmmmmmmmmmm1qqqdk11  dsp_mult                 macr -+s1,s2,d / macr -+s2,s1,d\r
+mpy     M_ALU24    M_ALU24      PARMOVE %mmmmmmmmmmmmmmmm1qqqdk00  dsp_mult                 mpy -+s1,d2,d / -+s2,s1,d\r
+mpyr    M_ALU24    M_ALU24      PARMOVE %mmmmmmmmmmmmmmmm1qqqdk01  dsp_mult                 mpyr -+s1,d2,d / -+s2,s1,d\r
+movep   M_DSPEA    M_DSPPP      NOPARMO %0000100s11mmmrrr1spppppp  dsp_movep_ea       +     movep p:ea,x:pp / p:ea,y:pp \r
+-       M_DSPAA    M_DSPPP      NOPARMO %0000100s11mmmrrr1spppppp  dsp_movep_ea       +     movep p:aa,x:pp / p:aa,y:pp \r
+-       M_DSPPP    M_DSPEA      NOPARMO %0000100s01mmmrrr1spppppp  dsp_movep_ea       +     x:pp,p:ea / y:pp,p:ea\r
+-       M_DSPPP    M_DSPPP      NOPARMO %0000100s01mmmrrr1spppppp  dsp_movep_ea       +     x:pp,p:ea / y:pp,p:ea\r
+-       M_DSPPP    M_DSPAA      NOPARMO %0000100s01mmmrrr1spppppp  dsp_movep_ea       +     x:pp,p:aa / y:pp,p:aa\r
+-       C_DSPIM    M_DSPPP      NOPARMO %0000100s111101001spppppp  dsp_movep_ea       +     #xxxxxx,x:pp / #xxxxxx,y:pp\r
+-       C_DSPIM    M_DSPEA      NOPARMO %0000100s111101001spppppp  dsp_movep_ea       +     #xxxxxx,x:pp / #xxxxxx,y:pp\r
+-       M_ALU24    M_DSPPP      NOPARMO %0000100s11000ddd0spppppp  dsp_movep_reg      +     movep s,x:pp / s,y:pp\r
+-       C_DDD      M_DSPPP      NOPARMO %0000100s11001ddd0spppppp  dsp_movep_reg      +     movep s,x:pp / s,y:pp\r
+-       C_TTT      M_DSPPP      NOPARMO %0000100s11010ddd0spppppp  dsp_movep_reg      +     movep s,x:pp / s,y:pp\r
+-       C_NNN      M_DSPPP      NOPARMO %0000100s11011ddd0spppppp  dsp_movep_reg      +     movep s,x:pp / s,y:pp\r
+-       C_FFF      M_DSPPP      NOPARMO %0000100s11100ddd0spppppp  dsp_movep_reg      +     movep s,x:pp / s,y:pp\r
+-       C_GGG      M_DSPPP      NOPARMO %0000100s11111ddd0spppppp  dsp_movep_reg      +     movep s,x:pp / s,y:pp\r
+-       M_DSPPP    M_ALU24      NOPARMO %0000100s01000ddd0spppppp  dsp_movep_reg      +     movep x:pp,d / y:pp,d\r
+-       M_DSPPP    C_DDD        NOPARMO %0000100s01001ddd0spppppp  dsp_movep_reg      +     movep x:pp,d / y:pp,d\r
+-       M_DSPPP    C_TTT        NOPARMO %0000100s01010ddd0spppppp  dsp_movep_reg      +     movep x:pp,d / y:pp,d\r
+-       M_DSPPP    C_NNN        NOPARMO %0000100s01011ddd0spppppp  dsp_movep_reg      +     movep x:pp,d / y:pp,d\r
+-       M_DSPPP    C_FFF        NOPARMO %0000100s01100ddd0spppppp  dsp_movep_reg      +     movep x:pp,d / y:pp,d\r
+-       M_DSPPP    C_GGG        NOPARMO %0000100s01111ddd0spppppp  dsp_movep_reg            movep x:pp,d / y:pp,d\r
+debug  M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001000000000  dsp_self\r
+debugcc M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000000  dsp_self\r
+debughs        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000000  dsp_self\r
+debugcs        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001000  dsp_self\r
+debuglo        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001000  dsp_self\r
+debugec        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000101  dsp_self\r
+debugeq        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001010  dsp_self\r
+debuges        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001101  dsp_self\r
+debugge        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000001  dsp_self\r
+debuggt        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000111  dsp_self\r
+debuglc        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000110  dsp_self\r
+debugle        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001111  dsp_self\r
+debugls        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001110  dsp_self\r
+debuglt        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001001  dsp_self\r
+debugmi        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001011  dsp_self\r
+debugne        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000010  dsp_self\r
+debugnr        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100001100  dsp_self\r
+debugpl        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000011  dsp_self\r
+debugnn        M_AM_NONE  M_AM_NONE    NOPARMO %000000000000001100000100  dsp_self\r
+\r
+\r
diff --git a/dsp56k_amode.c b/dsp56k_amode.c
new file mode 100644 (file)
index 0000000..c5644cc
--- /dev/null
@@ -0,0 +1,2806 @@
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// AMODE.C - DSP 56001 Addressing Modes
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source utilised with the kind permission of Landon Dyer
+//
+
+#include "dsp56k_amode.h"
+#include "error.h"
+#include "token.h"
+#include "expr.h"
+#include "rmac.h"
+#include "procln.h"
+#include "sect.h"
+#include "math.h"
+
+#define DEF_KW
+#include "kwtab.h"
+#define DEF_MN
+#include "mntab.h"
+
+// Address-mode information
+int nmodes;                                            // Number of addr'ing modes found
+int dsp_am0;                                   // Addressing mode
+int dsp_a0reg;                                 // Register
+TOKEN dsp_a0expr[EXPRSIZE];            // Expression
+uint64_t dsp_a0exval;                  // Expression's value
+WORD dsp_a0exattr;                             // Expression's attribute
+LONG dsp_a0memspace;                   // Addressing mode's memory space (P, X, Y)
+SYM * dsp_a0esym;                              // External symbol involved in expr
+
+int dsp_am1;                                   // Addressing mode
+int dsp_a1reg;                                 // Register
+TOKEN dsp_a1expr[EXPRSIZE];            // Expression
+uint64_t dsp_a1exval;                  // Expression's value
+WORD dsp_a1exattr;                             // Expression's attribute
+LONG dsp_a1memspace;                   // Addressing mode's memory space (P, X, Y)
+SYM * dsp_a1esym;                              // External symbol involved in expr
+
+int dsp_am2;                                   // Addressing mode
+int dsp_a2reg;                                 // Register
+TOKEN dsp_a2expr[EXPRSIZE];            // Expression
+uint64_t dsp_a2exval;                  // Expression's value
+WORD dsp_a2exattr;                             // Expression's attribute
+SYM * dsp_a2esym;                              // External symbol involved in expr
+
+int dsp_am3;                                   // Addressing mode
+int dsp_a3reg;                                 // Register
+TOKEN dsp_a3expr[EXPRSIZE];            // Expression
+uint64_t dsp_a3exval;                  // Expression's value
+WORD dsp_a3exattr;                             // Expression's attribute
+SYM * dsp_a3esym;                              // External symbol involved in expr
+
+TOKEN dspImmedEXPR[EXPRSIZE];  // Expression
+uint64_t dspImmedEXVAL;                        // Expression's value
+WORD  dspImmedEXATTR;                  // Expression's attribute
+SYM * dspImmedESYM;                            // External symbol involved in expr
+int  deposit_extra_ea;                 // Optional effective address extension
+TOKEN dspaaEXPR[EXPRSIZE];             // Expression
+uint64_t dspaaEXVAL;                   // Expression's value
+WORD  dspaaEXATTR;                             // Expression's attribute
+SYM * dspaaESYM;                               // External symbol involved in expr
+
+int dsp_k;                          // Multiplications sign
+
+static inline LONG checkea(const uint32_t termchar, const int strings);
+
+// ea checking error strings put into a table because I'm not sure there's an easy way to do otherwise
+// (the messages start getting differerent in many places so it will get awkward to code those in)
+// (I'd rather burn some RAM in order to have more helpful error messages than the other way round)
+
+#define X_ERRORS 0
+#define Y_ERRORS 1
+#define L_ERRORS 2
+#define P_ERRORS 3
+
+const char *ea_errors[][12] = {
+    // X:
+    {
+        "unrecognised X: parallel move syntax: expected '(' after 'X:-'",                                       // 0
+        "unrecognised X: parallel move syntax: expected ')' after 'X:-(Rn'",                                    // 1
+        "unrecognised X: parallel move syntax: expected R0-R7 after 'X:-('",                                    // 2
+        "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn+'",                                  // 3
+        "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn+Nn)'",     // 4
+        "unrecognised X: parallel move syntax: expected ')' after 'X:(Rn+Nn'",                                  // 5
+        "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)+Nn'",     // 6
+        "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)+'",                                 // 7
+        "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)-Nn'",     // 8
+        "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)-'",                                 // 9
+        "unrecognised X: parallel move syntax: expected '+', '-' or ',' after 'X:(Rn)'",                        // 10
+        "unrecognised X: parallel move syntax: expected '+' or ')' after 'X:(Rn'",                              // 11
+    },
+    // Y:
+    {
+        "unrecognised Y: parallel move syntax: expected '(' after 'Y:-'",                                       // 0
+        "unrecognised Y: parallel move syntax: expected ')' after 'Y:-(Rn'",                                    // 1
+        "unrecognised Y: parallel move syntax: expected R0-R7 after 'Y:-('",                                    // 2
+        "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn+'",                                  // 3
+        "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn+Nn)'",     // 4
+        "unrecognised Y: parallel move syntax: expected ')' after 'Y:(Rn+Nn'",                                  // 5
+        "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)+Nn'",     // 6
+        "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)+'",                                 // 7
+        "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)-Nn'",     // 8
+        "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)-'",                                 // 9
+        "unrecognised Y: parallel move syntax: expected '+', '-' or ',' after 'Y:(Rn)'",                        // 10
+        "unrecognised Y: parallel move syntax: expected '+' or ')' after 'Y:(Rn'",                              // 11
+    },
+    // L:
+    {
+        "unrecognised L: parallel move syntax: expected '(' after 'L:-'",                                       // 0
+        "unrecognised L: parallel move syntax: expected ')' after 'L:-(Rn'",                                    // 1
+        "unrecognised L: parallel move syntax: expected R0-R7 after 'L:-('",                                    // 2
+        "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn+'",                                  // 3
+        "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn+Nn)'",     // 4
+        "unrecognised L: parallel move syntax: expected ')' after 'L:(Rn+Nn'",                                  // 5
+        "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)+Nn'",     // 6
+        "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)+'",                                 // 7
+        "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)-Nn'",     // 8
+        "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)-'",                                 // 9
+        "unrecognised L: parallel move syntax: expected '+', '-' or ',' after 'L:(Rn)'",                        // 10
+        "unrecognised L: parallel move syntax: expected '+' or ')' after 'L:(Rn'",                              // 11
+    },
+    // P:
+    {
+        "unrecognised P: effective address syntax: expected '(' after 'P:-'",                                       // 0
+        "unrecognised P: effective address syntax: expected ')' after 'P:-(Rn'",                                    // 1
+        "unrecognised P: effective address syntax: expected R0-R7 after 'P:-('",                                    // 2
+        "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn+'",                                  // 3
+        "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn+Nn)'",     // 4
+        "unrecognised P: effective address syntax: expected ')' after 'P:(Rn+Nn'",                                  // 5
+        "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)+Nn'",     // 6
+        "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)+'",                                 // 7
+        "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)-Nn'",     // 8
+        "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)-'",                                 // 9
+        "unrecognised P: effective address syntax: expected '+', '-' or ',' after 'P:(Rn)'",                        // 10
+        "unrecognised P: effective address syntax: expected '+' or ')' after 'P:(Rn'",                              // 11
+    }
+};
+
+enum
+{
+    NUM_NORMAL = 0,
+    NUM_FORCE_LONG = 1,
+    NUM_FORCE_SHORT = 2
+};
+
+//
+// Parse a single addressing mode
+//
+static inline int dsp_parmode(int *am, int *areg, TOKEN * AnEXPR, uint64_t * AnEXVAL, WORD * AnEXATTR, SYM ** AnESYM, LONG *memspace, LONG *perspace, const int operand)
+{
+    if (*tok == KW_A || *tok == KW_B)
+    {
+        *am = M_ACC56;
+        *areg = *tok++;
+        return OK;
+    }
+    else if (*tok == '#')
+    {
+        tok++;
+
+        if (*tok == '<')
+        {
+            // Immediate Short Addressing Mode Force Operator
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+            if (*AnEXVAL > 0xfff && *AnEXVAL<-4096)
+                return error("immediate short addressing mode forced but address is bigger than $fff");
+            if ((int32_t)*AnEXVAL <= 0xff && (int32_t)*AnEXVAL>-0x100)
+            {
+                *am = M_DSPIM8;
+                return OK;
+            }
+            *am = M_DSPIM12;
+            return OK;
+        }
+        else if (*tok == '>')
+        {
+            // Immediate Long Addressing Mode Force Operator
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+            if ((int32_t)*AnEXVAL > 0xffffff || (int32_t)*AnEXVAL < -0xffffff)
+                return error("long immediate is bigger than $ffffff");
+            *am = M_DSPIM;
+            return OK;
+        }
+
+        if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+            return ERROR;
+
+        if (*AnEXATTR & DEFINED)
+        {
+                       if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
+                       {
+                               *AnEXVAL &= 0xff;
+                               *am = M_DSPIM8;
+                       }
+            else if (*AnEXVAL < 0x1000)
+                *am = M_DSPIM12;
+            else
+                *am = M_DSPIM;
+        }
+        else
+        {
+            // We have no clue what size our immediate will be
+            // so we have to assume the worst
+            *am = M_DSPIM;
+        }
+        return OK;
+    }
+    else if (*tok >= KW_X0 && *tok <= KW_Y1)
+    {
+        *am = M_ALU24;
+        *areg = *tok++;
+        return OK;
+    }
+    else if (*tok == KW_X && *(tok + 1) == ':')
+    {
+        tok = tok + 2;
+        if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+        {
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+                       if (*AnEXATTR & DEFINED)
+                       {
+                               if (*AnEXVAL > 0xffffff)
+                                       return error("long address is bigger than $ffffff");
+                               *memspace = 0 << 6;     // Mark we're on X memory space
+
+                               // Check if value is between $ffc0 and $ffff, AKA X:pp
+                               {
+                                       uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
+                                       if ((temp >= 0xffffffc0                      /* Check for 32bit sign extended number */
+                                               && ((int32_t)*AnEXVAL<0))                /* Check if 32bit signed number is negative*/
+                                               ||(*AnEXVAL<0xffff && *AnEXVAL>=0x8000)) /* Check if 16bit number is negative*/
+                                       {
+                                               *AnEXVAL = temp;
+                                               *am = M_DSPPP;
+                                               *memspace = 0 << 6;          // Mark we're on X memory space
+                                               *perspace = 0 << 16;         // Mark we're on X peripheral space
+                                               *areg = *AnEXVAL & 0x3f;     // Since this is only going to get used in dsp_ea_imm5...
+                                               return OK;
+                                       }
+
+                               }
+
+                               // If the symbol/expression is defined then check for valid range.
+                               // Otherwise the value had better fit or Fixups will bark!
+                               if (*AnEXVAL > 0x3f)
+                               {
+                                       *am = M_DSPEA;
+                                       *areg = DSP_EA_ABS;
+                               }
+                               else
+                               {
+                                       *am = M_DSPAA;
+                               }
+                       }
+                       else
+                       {
+                               // Assume the worst
+                               *memspace = 0 << 6;     // Mark we're on X memory space
+                               *am = M_DSPEA;
+                               *areg = DSP_EA_ABS;
+                       }
+            return OK;
+        }
+        else if (*tok == '<')
+        {
+            // X:aa
+            // Short Addressing Mode Force Operator in the case of '<'
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+
+                       // If the symbol/expression is defined then check for valid range.
+                       // Otherwise the value had better fit or Fixups will bark!
+                       if (*AnEXATTR & DEFINED)
+                       {
+                               if (*AnEXVAL > 0x3f)
+                                       return error("short addressing mode forced but address is bigger than $3f");
+                       }
+            else
+            {
+                // Mark it as a fixup
+                deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
+            }
+            *am = M_DSPAA;
+            *memspace = 0 << 6;     // Mark we're on X memory space
+            *areg = (int)*AnEXVAL;     // Since this is only going to get used in dsp_ea_imm5...
+            return OK;
+        }
+               else if (*tok == '>')
+               {
+                       // Long Addressing Mode Force Operator
+                       tok++;
+
+                       if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+                       {
+                               if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                                       return ERROR;
+                               if (*AnEXATTR&DEFINED)
+                               {
+                                       if (*AnEXVAL > 0xffffff)
+                                               return error("long address is bigger than $ffffff");
+                                       *memspace = 0 << 6;     // Mark we're on X memory space
+
+                                       *am = M_DSPEA;
+                                       *areg = DSP_EA_ABS;
+                               }
+                               else
+                               {
+                                       // Assume the worst
+                                       *memspace = 0 << 6;     // Mark we're on X memory space
+                                       *am = M_DSPEA;
+                                       *areg = DSP_EA_ABS;
+                               }
+                               return OK;
+                       }
+               }
+        else if (*tok == SHL)  // '<<'
+        {
+            // I/O Short Addressing Mode Force Operator
+            // X:pp
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+
+                       // If the symbol/expression is defined then check for valid range.
+                       // Otherwise the value had better fit or Fixups will bark!
+                       if (*AnEXATTR & DEFINED)
+                       {
+                               *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
+                               if (*AnEXVAL < 0xffffffc0)
+                                       return error("I/O Short Addressing Mode addresses must be between $ffc0 and $ffff");
+                       }
+            *am = M_DSPPP;
+            *memspace = 0 << 6;          // Mark we're on X memory space
+            *perspace = 0 << 16;         // Mark we're on X peripheral space
+            *areg = *AnEXVAL & 0x3f;     // Since this is only going to get used in dsp_ea_imm5...
+            return OK;
+        }
+
+        if ((*areg = checkea(0, X_ERRORS)) != ERROR)
+        {
+            // TODO: what if we need M_DSPAA here????
+            *memspace = 0 << 6;     // Mark we're on X memory space
+            *am = M_DSPEA;
+            return OK;
+        }
+        else
+            return ERROR;
+
+    }
+    else if (*tok == KW_Y && *(tok + 1) == ':')
+    {
+        tok = tok + 2;
+
+        if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+        {
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+            if (*AnEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+            *memspace = 1 << 6;     // Mark we're on Y memory space
+
+                       // Check if value is between $ffc0 and $ffff, AKA Y:pp
+                       {
+                               uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
+                               if ((temp >= 0xffffffc0                         /* Check for 32bit sign extended number */
+                                       && ((int32_t)*AnEXVAL<0))                   /* Check if 32bit signed number is negative*/
+                                       || (*AnEXVAL<0xffff && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
+                               {
+                                       *AnEXVAL = temp;
+                                       *am = M_DSPPP;
+                                       *perspace = 1 << 16;         // Mark we're on X peripheral space
+                                       *areg = *AnEXVAL & 0x3f;     // Since this is only going to get used in dsp_ea_imm5...
+                                       return OK;
+                               }
+
+                       }
+
+                       // If the symbol/expression is defined then check for valid range.
+                       // Otherwise the value had better fit or Fixups will bark!
+                       if (*AnEXATTR & DEFINED)
+                       {
+                               if (*AnEXVAL > 0x3f)
+                               {
+                                       *am = M_DSPEA;
+                                       *areg = DSP_EA_ABS;
+                               }
+                               else
+                               {
+                                       *am = M_DSPAA;
+                               }
+                       }
+                       else
+                       {
+                               *am = M_DSPEA;
+                               *areg = DSP_EA_ABS;
+                       }
+
+            return OK;
+        }
+        else if (*tok == '<')
+        {
+            // Y:aa
+            // Short Addressing Mode Force Operator in the case of '<'
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+
+                       // If the symbol/expression is defined then check for valid range.
+                       // Otherwise the value had better fit or Fixups will bark!
+                       if (*AnEXATTR & DEFINED)
+                       {
+                               if (*AnEXVAL > 0x3f)
+                               {
+                                       warn("short addressing mode forced but address is bigger than $3f - switching to long");
+                                       *am = M_DSPEA;
+                                       *memspace = 1 << 6;     // Mark we're on Y memory space
+                                       *areg = DSP_EA_ABS;
+                                       return OK;
+                               }
+                       }
+            else
+            {
+                // Mark it as a fixup
+                deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
+            }
+
+            *am = M_DSPAA;
+            *memspace = 1 << 6;     // Mark we're on Y memory space
+            *areg = (int)*AnEXVAL;      // Since this is only going to get used in dsp_ea_imm5...
+            return OK;
+        }
+        else if (*tok == '>')
+        {
+            // Long Addressing Mode Force Operator
+                       tok++;
+
+                       if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+                       {
+                               if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                                       return ERROR;
+                               if (*AnEXATTR&DEFINED)
+                               {
+                                       if (*AnEXVAL > 0xffffff)
+                                               return error("long address is bigger than $ffffff");
+                                       *memspace = 1 << 6;     // Mark we're on Y memory space
+
+                                       *am = M_DSPEA;
+                                       *areg = DSP_EA_ABS;
+                               }
+                               else
+                               {
+                                       // Assume the worst
+                                       *memspace = 1 << 6;     // Mark we're on Y memory space
+                                       *am = M_DSPEA;
+                                       *areg = DSP_EA_ABS;
+                               }
+                               return OK;
+                       }
+               }
+        else if (*tok == SHL)  // '<<'
+        {
+            // I/O Short Addressing Mode Force Operator
+            // Y:pp
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+
+                       // If the symbol/expression is defined then check for valid range.
+                       // Otherwise the value had better fit or Fixups will bark!
+                       if (*AnEXATTR & DEFINED)
+                       {
+                               *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
+                               if (*AnEXVAL < 0xffffffc0)
+                                       return error("I/O Short Addressing Mode addresses must be between $ffe0 and $1f");
+                       }
+               *am = M_DSPPP;
+            *memspace = 1 << 6;          // Mark we're on Y memory space
+            *perspace = 1 << 16;         // Mark we're on Y peripheral space
+            *areg = *AnEXVAL & 0x3f;     // Since this is only going to get used in dsp_ea_imm5...
+            return OK;
+        }
+
+        if ((*areg = checkea(0, X_ERRORS)) != ERROR)
+        {
+            *memspace = 1 << 6;     // Mark we're on Y memory space
+            *am = M_DSPEA;
+            return OK;
+        }
+        else
+            return ERROR;
+        // TODO: add absolute address checks
+
+    }
+    else if (*tok >= KW_X&&*tok <= KW_Y)
+    {
+        *am = M_INP48;
+        *areg = *tok++;
+        return OK;
+    }
+    else if (*tok >= KW_M0 && *tok <= KW_M7)
+    {
+        *am = M_DSPM;
+        *areg = (*tok++) & 7;
+        return OK;
+    }
+    else if (*tok >= KW_R0 && *tok <= KW_R7)
+    {
+        *am = M_DSPR;
+        *areg = (*tok++) - KW_R0;
+        return OK;
+    }
+    else if (*tok >= KW_N0 && *tok <= KW_N7)
+    {
+        *am = M_DSPN;
+        *areg = (*tok++) & 7;
+        return OK;
+    }
+    else if (*tok == KW_A0 || *tok == KW_A1 || *tok == KW_B0 || *tok == KW_B1)
+    {
+        *am = M_ACC24;
+        *areg = *tok++;
+        return OK;
+    }
+    else if (*tok == KW_A2 || *tok == KW_B2)
+    {
+        *am = M_ACC8;
+        *areg = *tok++;
+        return OK;
+    }
+    else if (*tok == '-' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
+    {
+        // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
+        tok++;
+
+        // Check to see if this is the first operand
+        if (operand != 0)
+            return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
+
+        *am = M_ALU24;
+        *areg = *tok++;
+        dsp_k = 1 << 2;
+        return OK;
+    }
+    else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
+    {
+        // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
+        tok++;
+
+        // Check to see if this is the first operand
+        if (operand != 0)
+            return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
+
+        *am = M_ALU24;
+        *areg = *tok++;
+        dsp_k = 0 << 2;
+        return OK;
+    }
+    else if (*tok == '(' || *tok == '-')
+    {
+        // Could be either an expression or ea mode
+        if (*tok + 1 == SYMBOL)
+        {
+            tok++;
+
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+
+            *am = M_DSPIM;
+            return OK;
+        }
+        if ((*areg = checkea(0, P_ERRORS)) != ERROR)
+        {
+            *am = M_DSPEA;
+            return OK;
+        }
+        else
+            return ERROR;
+        // TODO: add absolute address checks
+        return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
+    }
+    else if (*tok == KW_P && *(tok + 1) == ':')
+    {
+        tok = tok + 2;
+               if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+        {
+            // Address
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+            if (*AnEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+            if (*AnEXVAL > 0x3f)
+            {
+                *am = M_DSPEA;
+                *areg = DSP_EA_ABS;
+            }
+            else
+            {
+                *areg = (int)*AnEXVAL;     // Lame, but what the hell
+                *am = M_DSPAA;
+            }
+            return OK;
+        }
+        else if (*tok == '<')
+        {
+            // X:aa
+            // Short Addressing Mode Force Operator in the case of '<'
+            tok++;
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+            if (*AnEXVAL > 0x3f)
+                return error("short addressing mode forced but address is bigger than $3f");
+            *am = M_DSPAA;
+            *areg = (int)*AnEXVAL;     // Since this is only going to get used in dsp_ea_imm5...
+            return OK;
+        }
+        else if (*tok == '>')
+        {
+            // Long Addressing Mode Force Operator
+            tok++;
+            // Immediate Short Addressing Mode Force Operator
+            if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+                return ERROR;
+            if (*AnEXATTR & DEFINED)
+            {
+                if (*AnEXVAL > 0xffffff)
+                    return error("long address is bigger than $ffffff");
+            }
+            *am = M_DSPEA;
+            *areg = DSP_EA_ABS;
+            return OK;
+        }
+
+        if ((*areg = checkea(0, P_ERRORS)) != ERROR)
+        {
+            *am = M_DSPEA;
+            return OK;
+        }
+        else
+            return ERROR;
+
+    }
+    else if (*tok == SHL)
+    {
+        // I/O Short Addressing Mode Force Operator
+        tok++;
+        if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+            return ERROR;
+        if (*AnEXVAL > 0xfff)
+            return error("I/O short addressing mode forced but address is bigger than $fff");
+        *am = M_DSPABS06;
+        return OK;
+    }
+    else if (*tok == '<')
+    {
+        // Short Addressing Mode Force Operator
+        tok++;
+        if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+            return ERROR;
+        if (*AnEXATTR & DEFINED)
+        {
+            if (*AnEXVAL > 0xfff)
+                return error("short addressing mode forced but address is bigger than $fff");
+        }
+        *am = M_DSPABS12;
+        return OK;
+    }
+    else if (*tok == '>')
+    {
+        // Long Addressing Mode Force Operator
+        tok++;
+        // Immediate Short Addressing Mode Force Operator
+        if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+            return ERROR;
+        if (*AnEXATTR & DEFINED)
+        {
+            if (*AnEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+        }
+        *am = M_DSPEA;
+        *areg = DSP_EA_ABS;
+        return OK;
+    }
+
+    else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
+    {
+        *areg = *tok++;
+        *am = M_DSPPCU;
+        return OK;
+    }
+    // expr
+    else
+    {
+        if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
+            return ERROR;
+
+        // We'll store M_DSPEA_ABS in areg and if we have
+        // any extra info, it'll go in am
+        if (*AnEXATTR & DEFINED)
+        {
+            *areg = DSP_EA_ABS;
+            if (*AnEXVAL < 0x1000)
+                *am = M_DSPABS12;
+            else if (*AnEXVAL < 0x10000)
+                *am = M_DSPABS16;
+            else if (*AnEXVAL < 0x1000000)
+                *am = M_DSPABS24;
+            else
+                return error("address must be smaller than $1000000");
+            return OK;
+        }
+        else
+        {
+            // Well, we have no opinion on the expression's size, so let's assume the worst
+            *areg = DSP_EA_ABS;
+            *am = M_DSPABS24;
+            return OK;
+        }
+    }
+    return error("internal assembler error: Please report this error message: 'reached the end of dsp_parmode' with the line of code that caused it. Thanks, and sorry for the inconvenience");   // Something bad happened
+}
+
+//
+// Parse all addressing modes except parallel moves
+//
+int dsp_amode(int maxea)
+{
+    LONG dummy;
+    // Initialize global return values
+    nmodes = dsp_a0reg = dsp_a1reg = 0;
+    dsp_am0 = dsp_am1 = M_AM_NONE;
+    dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
+    dsp_a0exval = 0;
+    dsp_a1exval = 0;
+    dsp_a0exattr = dsp_a1exattr = 0;
+    dsp_a0esym = dsp_a1esym = (SYM *)NULL;
+    dsp_a0memspace = dsp_a1memspace = -1;
+    dsp_a0perspace = dsp_a1perspace = -1;
+    dsp_k = 0;
+
+    // If at EOL, then no addr modes at all
+    if (*tok == EOL)
+        return 0;
+
+    if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
+        return ERROR;
+
+
+    // 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 (*tok != ',')
+    {
+        if (dsp_k != 0)
+            return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
+
+        return 1;
+    }
+
+    // Eat the comma
+    tok++;
+
+    // Parse second addressing mode
+    if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
+        return ERROR;
+
+    if (maxea == 2 || *tok == EOL)
+    {
+        if (dsp_k != 0)
+            return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
+
+        nmodes = 2;
+        return 2;
+    }
+
+    if (*tok == ',')
+    {
+        // Only MAC-like or jsset/clr/tst/chg instructions here
+        tok++;
+        if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
+            return ERROR;
+        if (maxea == 3)
+            return 3;
+        if (*tok != EOL)
+            return error(extra_stuff);
+        nmodes = 3;
+        return 3;
+
+    }
+
+    // Only Tcc instructions here, and then only those that accept 4 operands
+
+    if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
+        return ERROR;
+
+    if (*tok++ != ',')
+        return error("expected 4 parameters");
+
+    if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
+        return ERROR;
+
+    if (*tok == EOL)
+    {
+        if (dsp_k != 0)
+            return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
+
+        nmodes = 4;
+        return 4;
+    }
+    else
+    {
+        // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
+        return error(extra_stuff);
+    }
+
+    return error("internal assembler error: Please report this error message: 'reached the end of dsp_amode' with the line of code that caused it. Thanks, and sorry for the inconvenience");   //Something bad happened
+
+}
+
+
+//
+// Helper function which gives us the encoding of a DSP register
+//
+static inline int SDreg(int reg)
+{
+    if (reg >= KW_X0 && reg <= KW_N7)
+        return reg & 0xff;
+    else if (reg >= KW_A0&&reg <= KW_A2)
+        return (8 >> (reg & 7)) | 8;
+    else //if (reg>=KW_R0&&reg<=KW_R7)
+        return reg - KW_R0 + 16;
+    // Handy map for the above:
+    // (values are of course taken from keytab)
+    // Register | Value | Return value
+    // x0      | 260   | 4
+    // x1      | 261   | 5
+    // y0      | 262   | 6
+    // y1      | 263   | 7
+    // b0      | 265   | 8
+    // b2      | 267   | 9
+    // b1      | 269   | 10
+    // a       | 270   | 14
+    // b       | 271   | 15
+    // n0      | 280   | 24
+    // n1      | 281   | 25
+    // n2      | 282   | 26
+    // n3      | 283   | 27
+    // n4      | 284   | 28
+    // n5      | 285   | 29
+    // n6      | 286   | 30
+    // n7      | 287   | 31
+    // a0          | 136   | 0
+    // a1          | 137   | 1
+    // a2      | 138   | 2
+    // r0          | 151   | 16
+    // r1          | 152   | 17
+    // r2          | 153   | 18
+    // r3          | 154   | 19
+    // r4          | 155   | 20
+    // r5          | 156   | 21
+    // r6          | 157   | 22
+    // r7          | 158   | 23
+}
+
+
+//
+// Check for X:Y: parallel mode syntax
+//
+static inline LONG check_x_y(LONG ea1, LONG S1)
+{
+    LONG inst;
+    LONG eax_temp, eay_temp;
+    LONG D1, D2, S2, ea2;
+    LONG K_D1, K_D2;
+    LONG w = 1 << 7;           // S1=0, D1=1<<14
+    if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
+        (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
+    {
+
+        switch (ea1 & 0x38)
+        {
+        case DSP_EA_POSTINC: ea1 = (ea1&(~0x38)) | 0x8;break;
+        case DSP_EA_POSTINC1: ea1 = (ea1&(~0x38)) | 0x18;break;
+        case DSP_EA_POSTDEC1: ea1 = (ea1&(~0x38)) | 0x10;break;
+        case DSP_EA_NOUPD: ea1 = (ea1&(~0x38)) | 0x00;break;
+        }
+
+        if (S1 == 0)
+        {
+            // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
+            // Check for D1
+            switch (K_D1 = *tok++)
+            {
+            case KW_X0: D1 = 0 << 10; break;
+            case KW_X1: D1 = 1 << 10; break;
+            case KW_A:  D1 = 2 << 10; break;
+            case KW_B:  D1 = 3 << 10; break;
+            default:    return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
+            }
+        }
+        else
+        {
+            // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
+            w = 0;
+            switch (S1)
+            {
+            case 4:  D1 = 0 << 10; break;
+            case 5:  D1 = 1 << 10; break;
+            case 14: D1 = 2 << 10; break;
+            case 15: D1 = 3 << 10; break;
+            default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
+            }
+        }
+
+        if (*tok == KW_Y)
+        {
+            tok++;
+            // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
+            if (*tok++ != ':')
+                return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
+            if (*tok++ == '(')
+            {
+                if (*tok >= KW_R0 && *tok <= KW_R7)
+                {
+                    ea2 = (*tok++ - KW_R0);
+                    if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
+                        return error("unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea Y:eay,D2'");
+                }
+                else
+                    return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
+                // If eax register is r0-r3 then eay register is r4-r7.
+                // Encode that to 2 bits (i.e. eay value is 0-3)
+                eax_temp = (ea2 & 3) << 5;  // Store register temporarily
+                if (*tok++ != ')')
+                    return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
+                if (*tok == '+')
+                {
+                    tok++;
+                    if (*tok == ',')
+                    {
+                        // (Rn)+
+                        ea2 = 3 << 12;
+                        tok++;
+                    }
+                    else if (*tok >= KW_N0 && *tok <= KW_N7)
+                    {
+                        // (Rn)+Nn
+                        if ((*tok++ & 7) != ea2)
+                            return error("unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea Y:(Rn)+Nn,D')");
+                        ea2 = 1 << 12;
+                        if (*tok++ != ',')
+                            return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
+                    }
+                    else
+                        return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
+
+                }
+                else if (*tok == '-')
+                {
+                    // (Rn)-
+                    ea2 = 2 << 12;
+                    tok++;
+                    if (*tok++ != ',')
+                        return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
+                }
+                else if (*tok++ == ',')
+                {
+                    // (Rn)
+                    ea2 = 0 << 12;
+                }
+                else
+                    return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
+
+                ea2 |= eax_temp; // OR eay back from temp
+
+                switch (K_D2 = *tok++)
+                {
+                case KW_Y0: D2 = 0 << 8; break;
+                case KW_Y1: D2 = 1 << 8; break;
+                case KW_A:  D2 = 2 << 8; break;
+                case KW_B:  D2 = 3 << 8; break;
+                default:    return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
+                }
+
+                if (*tok != EOL)
+                    return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
+
+                if (S1 == 0)
+                    if (K_D1 == K_D2)
+                        return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
+
+                inst = B16(11000000, 00000000) | w;
+                inst |= ea1 | D1 | ea2 | D2;
+                return inst;
+            }
+            else
+                return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
+        }
+        else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
+        {
+            // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
+            switch (*tok++)
+            {
+            case KW_Y0: S2 = 0 << 8; break;
+            case KW_Y1: S2 = 1 << 8; break;
+            case KW_A:  S2 = 2 << 8; break;
+            case KW_B:  S2 = 3 << 8; break;
+            default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
+            }
+
+            if (*tok++ != ',')
+                return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
+
+            if (*tok++ == KW_Y)
+            {
+                // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
+                if (*tok++ != ':')
+                    return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
+                if (*tok++ == '(')
+                {
+                    if (*tok >= KW_R0 && *tok <= KW_R7)
+                    {
+                        ea2 = (*tok++ - KW_R0);
+                        if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
+                            return error("unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea S2,Y:eay'");
+                    }
+                    else
+                        return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
+                    // If eax register is r0-r3 then eay register is r4-r7.
+                    // Encode that to 2 bits (i.e. eay value is 0-3)
+                    eay_temp = (ea2 & 3) << 5; //Store register temporarily
+                    if (*tok++ != ')')
+                        return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
+                    if (*tok == '+')
+                    {
+                        tok++;
+                        if (*tok == EOL)
+                            // (Rn)+
+                            ea2 = 3 << 12;
+                        else if (*tok >= KW_N0 && *tok <= KW_N7)
+                        {
+                            // (Rn)+Nn
+                            if ((*tok++ & 7) != ea2)
+                                return error("unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn')");
+                            ea2 = 1 << 12;
+                            if (*tok != EOL)
+                                return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
+                        }
+                        else
+                            return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
+
+                    }
+                    else if (*tok == '-')
+                    {
+                        // (Rn)-
+                        ea2 = 2 << 12;
+                        tok++;
+                        if (*tok != EOL)
+                            return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
+                    }
+                    else if (*tok == EOL)
+                    {
+                        // (Rn)
+                        ea2 = 0 << 12;
+                    }
+                    else
+                        return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
+
+                    ea2 |= eay_temp; //OR eay back from temp
+
+                    inst = B16(10000000, 00000000) | w;
+                    inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
+                    return inst;
+                }
+                else
+                    return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
+
+            }
+            else
+                return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
+        }
+        else
+            return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
+
+
+    }
+    return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
+}
+
+//
+// Parse X: addressing space parallel moves
+//
+static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
+{
+    int immreg;                                        // Immediate register destination
+    LONG S2, D1, D2;                   // Source and Destinations
+    LONG ea1;                                  // ea bitfields
+    uint32_t termchar = ',';   // Termination character for ea checks
+    int force_imm = NUM_NORMAL;        // Holds forced immediate value (i.e. '<' or '>')
+    ea1 = -1;                                  // initialise e1 (useful for some code paths)
+    if (W == 0)
+        termchar = EOL;
+    if (*tok == '-')
+    {
+        if (tok[1] == CONST || tok[1] == FCONST)
+        {
+            tok++;
+            dspImmedEXVAL = *tok++;
+            goto x_check_immed;
+        }
+        // This could be either -(Rn), -aa or -ea. Check for immediate first
+        if (tok[1] == SYMBOL)
+        {
+            if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
+            {
+                if (S1 != 0)
+                {
+                x_checkea_right:
+
+                    // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B', 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
+                    if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
+                    {
+                        // 'A,X:ea X0,A'
+                        if (ea1 == DSP_EA_ABS)
+                            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                        if (S1 != 14)
+                            return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
+                        if (ea1 == -1)
+                            return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
+                        if (ea1 == B8(00110100))
+                            return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
+                        inst = B16(00001000, 00000000) | ea1 | (0 << 8);
+                        return inst;
+                    }
+                    else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
+                    {
+                        // 'B,X:ea X0,B'
+                        if (ea1 == DSP_EA_ABS)
+                            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                        if (S1 != 15)
+                            return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
+                        if (ea1 == -1)
+                            return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
+                        if (ea1 == B8(00110100))
+                            return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
+                        inst = B16(00001001, 00000000) | ea1 | (1 << 8);
+                        return inst;
+                    }
+                    else if (*tok == KW_A || *tok == KW_B)
+                    {
+                        // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
+
+                        switch (S1)
+                        {
+                        case 4:  D1 = 0 << 10; break;
+                        case 5:  D1 = 1 << 10; break;
+                        case 14: D1 = 2 << 10; break;
+                        case 15: D1 = 3 << 10; break;
+                        default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
+                        }
+
+                        if (tok[1] == ',' && tok[2] == KW_Y)
+                        {
+                            // 'S1,X:eax S2,Y:eay'
+                            return check_x_y(ea1, S1);
+                        }
+
+                        // 'S1,X:ea S2,D2'
+                        if (ea1 == DSP_EA_ABS)
+                            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+                        switch (*tok++)
+                        {
+                        case KW_A: S2 = 0 << 9; break;
+                        case KW_B: S2 = 1 << 9; break;
+                        default:   return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
+                        }
+                        if (*tok++ != ',')
+                            return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
+
+                        if (*tok == KW_Y0 || *tok == KW_Y1)
+                        {
+                            if (*tok++ == KW_Y0)
+                                D2 = 0 << 8;
+                            else
+                                D2 = 1 << 8;
+
+                            if (*tok != EOL)
+                                return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
+
+                            inst = B16(00010000, 00000000) | (0 << 7);
+                            inst |= ea1 | D1 | S2 | D2;
+                            return inst;
+                        }
+                        else
+                            return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
+
+                    }
+                    else if (*tok == KW_Y)
+                    {
+                        // 'S1,X:eax Y:eay,D2'
+                        return check_x_y(ea1, S1);
+                    }
+                    else if (*tok == KW_Y0 || *tok == KW_Y1)
+                    {
+                        // 'S1,X:eax S2,Y:eay'
+                        return check_x_y(ea1, S1);
+                    }
+                    else
+                        return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
+                }
+                else
+                {
+                    // Only check for aa if we have a defined number in our hands or we've
+                    // been asked to use a short number format. The former case we'll just test
+                    // it to see if it's small enough. The later - it's the programmer's call
+                    // so he'd better have a small address or the fixups will bite him/her in the arse!
+                    if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
+                    {
+
+                        // It's an immediate, so ea or eax is probably an absolute address
+                        // (unless it's aa if the immediate is small enough)
+                        // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
+                    x_check_immed:
+                        // Check for aa (which is 6 bits zero extended)
+                        if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
+                        {
+                            if (W == 1)
+                            {
+                                // It might be X:aa but we're not 100% sure yet.
+                                // If it is, the only possible syntax here is 'X:aa,D'.
+                                // So check ahead to see if EOL follows D, then we're good to go.
+                                if (*tok == ',' && ((*(tok + 1) >= KW_X0 && *(tok + 1) <= KW_N7) || (*(tok + 1) >= KW_R0 && *(tok + 1) <= KW_R7) || (*(tok + 1) >= KW_A0 && *(tok + 1) <= KW_A2)) && *(tok + 2) == EOL)
+                                {
+                                    // Yup, we're good to go - 'X:aa,D' it is
+                                    tok++;
+                                    immreg = SDreg(*tok++);
+                                    inst = inst | (uint32_t)dspImmedEXVAL;
+                                    inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
+                                    inst |= 1 << 7; // W
+                                    return inst;
+                                }
+                            }
+                            else
+                            {
+                                if (*tok == EOL)
+                                {
+                                    // 'S,X:aa'
+                                    inst = inst | (uint32_t)dspImmedEXVAL;
+                                    inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
+                                    return inst;
+                                }
+                                else
+                                {
+                                    // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
+                                    // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
+                                    ea1 = DSP_EA_ABS;
+                                    deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                                    goto x_checkea_right;
+                                }
+                            }
+                        }
+                    }
+
+                    // Well, that settles it - we do have an ea in our hands
+                    if (W == 1)
+                    {
+                        // 'X:ea,D' [... S2,d2]
+                        if (*tok++ != ',')
+                            return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
+                        if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
+                        {
+                            D1 = SDreg(*tok++);
+                            if (*tok == EOL)
+                            {
+                                // 'X:ea,D'
+                                inst = inst | B8(01000000) | (1 << 7);
+                                inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
+                                inst |= ea1;
+                                if (ea1 == DSP_EA_ABS)
+                                    deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                                return inst;
+                            }
+                            else
+                            {
+                                // 'X:ea,D1 S2,D2'
+                                if (*tok == KW_A || *tok == KW_B)
+                                {
+                                    S2 = SDreg(*tok++);
+                                    if (*tok++ != ',')
+                                        return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
+                                    if (*tok == KW_Y0 || *tok == KW_Y1)
+                                    {
+                                        D2 = SDreg(*tok++);
+                                        if (*tok != EOL)
+                                            return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
+                                        inst = B16(00010000, 00000000) | (1 << 7);
+                                        inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
+                                        inst |= (S2 & 1) << 9;
+                                        inst |= (D2 & 1) << 8;
+                                        inst |= ea1;
+                                        return inst;
+                                    }
+                                    else
+                                        return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
+                                }
+                                else
+                                    return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
+                            }
+                        }
+                        else
+                            return error("unrecognised X: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'X:ea,'");
+                    }
+                    else
+                    {
+                        if (*tok == EOL)
+                        {
+                            // 'S,X:ea'
+                            inst = inst | B8(01000000) | (0 << 7);
+                            inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
+                            inst |= ea1;
+                            if (ea1 == DSP_EA_ABS)
+                                deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                            return inst;
+                        }
+                        else
+                        {
+                            // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
+                            // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
+                            goto x_checkea_right;
+                        }
+                    }
+
+                }
+            }
+        }
+        else
+        {
+            // It's not an immediate, check for '-(Rn)'
+            ea1 = checkea(termchar, X_ERRORS);
+
+            if (ea1 == ERROR)
+                return ERROR;
+
+            goto x_gotea1;
+
+        }
+    }
+    else if (*tok == '#')
+    {
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        // Okay so we have immediate data - mark it down
+        ea1 = DSP_EA_IMM;
+        // Now, proceed to the main code for this branch
+        goto x_gotea1;
+    }
+    else if (*tok == '(')
+    {
+        // Maybe we got an expression here, check for it
+        if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
+        {
+            // Evaluate the expression and go to immediate code path
+            expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
+            goto x_check_immed;
+        }
+
+        // Nope, let's check for ea then
+        ea1 = checkea(termchar, X_ERRORS);
+        if (ea1 == ERROR)
+            return ERROR;
+
+    x_gotea1:
+        if (W == 1)
+        {
+            if (*tok++ != ',')
+                return error("Comma expected after 'X:(Rn)')");
+
+            // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
+            // If it is, the only possible syntax here is 'X:ea,D'.
+            // So check ahead to see if EOL follows D, then we're good to go.
+            if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
+            {
+                //'X:ea,D'
+                D1 = SDreg(*tok++);
+
+                inst = inst | B8(01000000) | (1 << 7);
+                inst |= ea1;
+                inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
+                return inst;
+            }
+        }
+        else
+        {
+            if (*tok == EOL)
+            {
+                //'S,X:ea'
+                inst = inst | B8(01000000) | (0 << 7);
+                inst |= ea1;
+                inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
+                return inst;
+            }
+            else
+            {
+                goto x_checkea_right;
+            }
+        }
+        // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
+        // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
+        if ((*tok == KW_X0 || *tok == KW_X1 || *tok == KW_A || *tok == KW_B) && (*(tok + 1) == KW_A || *(tok + 1) == KW_B) && (*(tok + 2) == ',') && (*(tok + 3) == KW_Y0 || (*(tok + 3) == KW_Y1)))
+        {
+            // 'X:ea,D1 S2,D2'
+            // Check if D1 is x0, x1, a or b
+            switch (*tok++)
+            {
+            case KW_X0: D1 = 0 << 10; break;
+            case KW_X1: D1 = 1 << 10; break;
+            case KW_A:  D1 = 2 << 10; break;
+            case KW_B:  D1 = 3 << 10; break;
+            default:    return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
+            }
+
+            switch (*tok++)
+            {
+            case KW_A: S2 = 0 << 9; break;
+            case KW_B: S2 = 1 << 9; break;
+            default:   return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
+            }
+
+            if (*tok++ != ',')
+                return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
+
+            if (*tok == KW_Y0 || *tok == KW_Y1)
+            {
+                if (*tok++ == KW_Y0)
+                    D2 = 0 << 8;
+                else
+                    D2 = 1 << 8;
+
+                if (*tok != EOL)
+                    return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
+
+                inst = B16(00010000, 00000000) | (W << 7);
+                inst |= ea1 | D1 | S2 | D2;
+                return inst;
+            }
+            else
+                return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
+
+        }
+
+        // Check to see if we got eax (which is a subset of ea)
+        if (check_for_x_y)
+        {
+            if ((inst = check_x_y(ea1, 0)) != 0)
+                return inst;
+            else
+            {
+                // Rewind pointer as it might be an expression and check for it
+                tok--;
+                if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
+                    return ERROR;
+                // Yes, we have an expression, so we now check for
+                // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
+                goto x_check_immed;
+            }
+        }
+    }
+    else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+    {
+        // Check for immediate address
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+
+        // We set ea1 here - if it's aa instead of ea
+        // then it won't be used anyway
+        ea1 = DSP_EA_ABS;
+        if (!(dspImmedEXATTR&DEFINED))
+        {
+            force_imm = NUM_FORCE_LONG;
+            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+        }
+
+        goto x_check_immed;
+    }
+    else if (*tok == '>')
+    {
+        // Check for immediate address forced long
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        if (dspImmedEXATTR & DEFINED)
+            if (dspImmedEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+
+        deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+        force_imm = NUM_FORCE_LONG;
+        ea1 = DSP_EA_ABS;
+        goto x_check_immed;
+    }
+    else if (*tok == '<')
+    {
+        // Check for immediate address forced short
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        force_imm = NUM_FORCE_SHORT;
+        if (dspImmedEXATTR & DEFINED)
+        {
+            if (dspImmedEXVAL > 0x3f)
+            {
+                warn("short addressing mode forced but address is bigger than $3f - switching to long");
+                force_imm = NUM_FORCE_LONG;
+                deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                ea1 = DSP_EA_ABS;
+            }
+        }
+        else
+        {
+            // This might end up as something like 'move Y:<adr,register'
+            // so let's mark it as an extra aa fixup here.
+            // Note: we are branching to x_check_immed without a
+            // defined dspImmed so it's going to be 0. It probably
+            // doesn't harm anything.
+            deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
+        }
+
+        goto x_check_immed;
+    }
+    return error("unknown x: addressing mode");
+}
+
+
+//
+// Parse Y: addressing space parallel moves
+//
+static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
+{
+    int immreg;                                        // Immediate register destination
+    LONG D2;                                   // Destination
+    LONG ea1;                                  // ea bitfields
+    int force_imm = NUM_NORMAL;        // Holds forced immediate value (i.e. '<' or '>')
+    if (*tok == '-')
+    {
+        if (tok[1] == CONST || tok[1] == FCONST)
+        {
+            tok++;
+            dspImmedEXVAL = *tok++;
+            goto y_check_immed;
+        }
+        // This could be either -(Rn), -aa or -ea. Check for immediate first
+               if (*tok == SYMBOL || tok[1] == SYMBOL)
+               {
+                       if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
+                       {
+                               // Only check for aa if we have a defined number in our hands or we've
+                               // been asked to use a short number format. The former case we'll just test
+                               // it to see if it's small enough. The later - it's the programmer's call
+                               // so he'd better have a small address or the fixups will bite him/her in the arse!
+                               if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
+                               {
+                                       // It's an immediate, so ea is probably an absolute address
+                                       // (unless it's aa if the immediate is small enough)
+                                       // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
+                               y_check_immed:
+                                       // Check for aa (which is 6 bits zero extended)
+                                       if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
+                                       {
+                                               // It might be Y:aa but we're not 100% sure yet.
+                                               // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
+                                               // So check ahead to see if EOL follows D, then we're good to go.
+                                               if (*tok == EOL && S1 != 0)
+                                               {
+                                                       // 'S,Y:aa'
+                                                       inst = B16(01001000, 00000000);
+                                                       inst |= dspImmedEXVAL;
+                                                       inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
+                                                       return inst;
+                                               }
+                                               if (*tok == ',' && ((*(tok + 1) >= KW_X0 && *(tok + 1) <= KW_N7) || (*(tok + 1) >= KW_R0 && *(tok + 1) <= KW_R7) || (*(tok + 1) >= KW_A0 && *(tok + 1) <= KW_A2)) && *(tok + 2) == EOL)
+                                               {
+                                                       // Yup, we're good to go - 'Y:aa,D' it is
+                                                       tok++;
+                                                       immreg = SDreg(*tok++);
+                                                       inst |= dspImmedEXVAL;
+                                                       inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
+                                                       return inst;
+                                               }
+                                       }
+                               }
+                               // Well, that settles it - we do have a ea in our hands
+                               if (*tok == EOL && S1 != 0)
+                               {
+                                       // 'S,Y:ea'
+                                       inst = B16(01001000, 01110000);
+                                       inst |= ea1;
+                                       inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
+                                       if (ea1 == DSP_EA_ABS)
+                                               deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                                       return inst;
+                               }
+                               if (*tok++ != ',')
+                                       return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
+                               if (D1 == 0 && S1 == 0)
+                               {
+                                       // 'Y:ea,D'
+                                       if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
+                                       {
+                                               D1 = SDreg(*tok++);
+                                               if (*tok != EOL)
+                                                       return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
+                                               inst |= B16(00000000, 01110000);
+                                               inst |= ea1;
+                                               inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
+                                               if (ea1 == DSP_EA_ABS)
+                                                       deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                                               return inst;
+                                       }
+                                       else
+                                               return error("unrecognised Y: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'Y:ea,'");
+                               }
+                               else
+                               {
+                                       // 'S1,D1 Y:ea,D2'
+                                       if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
+                                       {
+                                               D2 = SDreg(*tok++);
+                                               inst |= ea1;
+                                               inst |= 1 << 7;
+                                               inst |= (S1 & 1) << 11;
+                                               inst |= (D1 & 1) << 10;
+                                               inst |= (D2 & 8) << (9 - 3);
+                                               inst |= (D2 & 1) << 8;
+                                               return inst;
+                                       }
+                                       else
+                                               return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
+                               }
+                       }
+                       else
+                               return ERROR;
+               }
+        else
+        {
+            // It's not an immediate, check for '-(Rn)'
+            ea1 = checkea(',', Y_ERRORS);
+
+            if (ea1 == ERROR)
+                return ERROR;
+
+            goto y_gotea1;
+
+        }
+    }
+    else if (*tok == '#')
+    {
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        // Okay so we have immediate data - mark it down
+        ea1 = DSP_EA_IMM;
+        // Now, proceed to the main code for this branch
+        goto y_gotea1;
+    }
+    else if (*tok == '(')
+    {
+        // Maybe we got an expression here, check for it
+        if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
+        {
+            // Evaluate the expression and go to immediate code path
+            expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
+            goto y_check_immed;
+        }
+
+        // Nope, let's check for ea then
+        if (S1 == 0 || (S1 != 0 && D1 != 0))
+            ea1 = checkea(',', Y_ERRORS);
+        else
+            ea1 = checkea(EOL, Y_ERRORS);
+
+        if (ea1 == ERROR)
+            return ERROR;
+
+    y_gotea1:
+        if (S1 != 0 && *tok == EOL)
+        {
+            // 'S,Y:ea'
+            inst = B16(01001000, 01000000);
+            inst |= ea1;
+            inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
+            return inst;
+        }
+        else if (S1 != 0 && D1 != 0 && S2 == 0)
+        {
+            // 'S1,D1 Y:ea,D2'
+            switch (S1)
+            {
+            case 14: S1 = 0 << 11; break; // A
+            case 15: S1 = 1 << 11; break; // B
+            default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
+            }
+            switch (D1)
+            {
+            case 4: D1 = 0 << 10; break; // X0
+            case 5: D1 = 1 << 10; break; // X1
+            default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
+            }
+            if (*tok++ != ',')
+                return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
+            switch (*tok++)
+            {
+            case KW_Y0: D2 = 0 << 8; break;
+            case KW_Y1: D2 = 1 << 8; break;
+            case KW_A:  D2 = 2 << 8; break;
+            case KW_B:  D2 = 3 << 8; break;
+            default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
+            }
+            inst = B16(00010000, 11000000);
+            inst |= S1 | D1 | D2;
+            inst |= ea1;
+            return inst;
+        }
+        if (*tok++ != ',')
+            return error("Comma expected after 'Y:(Rn)')");
+        // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
+        // If it is, the only possible syntax here is 'Y:ea,D'.
+        // So check ahead to see if EOL follows D, then we're good to go.
+        if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
+        {
+            //'Y:ea,D'
+            D1 = SDreg(*tok++);
+            inst |= B16(00000000, 01000000);
+            inst |= ea1;
+            inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
+            return inst;
+        }
+    }
+    else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+    {
+        // Check for immediate address
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+
+        // Yes, we have an expression, so we now check for
+        // 'Y:ea,D' or 'Y:aa,D'
+        ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
+        if (!(dspImmedEXATTR&DEFINED))
+        {
+            force_imm = NUM_FORCE_LONG;
+            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+        }
+
+        goto y_check_immed;
+    }
+    else if (*tok == '>')
+    {
+        // Check for immediate address forced long
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        if (dspImmedEXATTR & DEFINED)
+            if (dspImmedEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+
+        deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+        force_imm = NUM_FORCE_LONG;
+        ea1 = DSP_EA_ABS;
+        goto y_check_immed;
+    }
+    else if (*tok == '<')
+    {
+        tok++;
+        if (S1 != 0 && D1 != 0)
+        {
+            // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
+            // there's no Y:aa mode here, so we'll force long
+            warn("forced short addressing in R:Y mode is not allowed - switching to long");
+
+            if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+                return ERROR;
+
+            ea1 = DSP_EA_ABS;
+
+            force_imm = NUM_FORCE_LONG;
+            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+            goto y_check_immed;
+        }
+        else
+        {
+            // Check for immediate address forced short
+            ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
+
+            if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+                return ERROR;
+            force_imm = NUM_FORCE_SHORT;
+            if (dspImmedEXATTR & DEFINED)
+            {
+                if (dspImmedEXVAL > 0xfff)
+                {
+                    warn("short addressing mode forced but address is bigger than $fff - switching to long");
+                    ea1 = DSP_EA_ABS;
+                    force_imm = NUM_FORCE_LONG;
+                    deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                }
+            }
+            else
+            {
+                // This might end up as something like 'move Y:<adr,register'
+                // so let's mark it as an extra aa fixup here.
+                // Note: we are branching to y_check_immed without a
+                // defined dspImmed so it's going to be 0. It probably
+                // doesn't harm anything.
+                deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
+            }
+
+            goto y_check_immed;
+        }
+    }
+
+    return error("unrecognised Y: parallel move syntax");
+}
+
+
+//
+// Parse L: addressing space parallel moves
+//
+static inline LONG parse_l(const int W, LONG inst, LONG S1)
+{
+    int immreg;                                        // Immediate register destination
+    LONG D1;                                   // Source and Destinations
+    LONG ea1;                                  // ea bitfields
+    int force_imm = NUM_NORMAL;        // Holds forced immediate value (i.e. '<' or '>')
+    if (*tok == '-')
+    {
+        if (*tok == CONST || tok[1] == FCONST)
+        {
+            tok++;
+            dspImmedEXVAL = *tok++;
+            goto l_check_immed;
+        }
+        // This could be either -(Rn), -aa or -ea. Check for immediate first
+        // Maybe we got an expression here, check for it
+        if (*tok == SYMBOL || tok[1] == SYMBOL)
+        {
+            // Evaluate the expression and go to immediate code path
+            if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
+            {
+                // Only check for aa if we have a defined number in our hands or we've
+                // been asked to use a short number format. The former case we'll just test
+                // it to see if it's small enough. The later - it's the programmer's call
+                // so he'd better have a small address or the fixups will bite him/her in the arse!
+                if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
+                {
+                    // It's an immediate, so ea is probably an absolute address
+                    // (unless it's aa if the immediate is small enough)
+                    // 'L:ea,D' or 'L:aa,D'
+                l_check_immed:
+                    // Check for aa (which is 6 bits zero extended)
+                    if (*tok == EOL)
+                    {
+                        // 'S,L:aa'
+                        if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
+                        {
+                            // 'S,L:aa'
+                            if (S1 == KW_A)
+                                S1 = 4;
+                            else if (S1 == KW_B)
+                                S1 = 5;
+                            else
+                                S1 &= 7;
+
+                            inst = B16(01000000, 00000000);
+                            inst |= dspImmedEXVAL;
+                            inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
+                            return inst;
+                        }
+                        else
+                        {
+                            // 'S,L:ea'
+                            if (S1 == KW_A)
+                                S1 = 4;
+                            else if (S1 == KW_B)
+                                S1 = 5;
+                            else
+                                S1 &= 7;
+
+                            if (ea1 == DSP_EA_ABS)
+                                deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+                            inst |= B16(01000000, 01110000);
+                            inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
+                            inst |= ea1;
+                            return inst;
+                        }
+
+                    }
+                    if (*tok++ != ',')
+                        return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
+                    // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
+                    if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
+                        return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
+
+                    if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
+                    {
+                        // 'L:aa,D'
+                        l_aa:
+                        immreg = *tok++;
+                        if (immreg == KW_A)
+                            immreg = 4;
+                        else if (immreg == KW_B)
+                            immreg = 5;
+                        else
+                            immreg &= 7;
+
+                        if (*tok != EOL)
+                            return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
+
+                        inst &= B16(11111111, 10111111);
+                        inst |= dspImmedEXVAL;
+                        inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
+                        return inst;
+                    }
+                }
+
+                if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
+                {
+                    // Hang on, we've got a L:<aa here, let's do that instead
+                    goto l_aa;
+                }
+
+                // Well, that settles it - we do have a ea in our hands
+                // 'L:ea,D'
+                D1 = *tok++;
+                if (D1 == KW_A)
+                    D1 = 4;
+                else if (D1 == KW_B)
+                    D1 = 5;
+                else
+                    D1 &= 7;
+
+                if (*tok != EOL)
+                    return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
+
+                inst |= B16(00000000, 00110000);
+                inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
+                return inst;
+            }
+        }
+        else
+        {
+            //It's not an immediate, check for '-(Rn)'
+            ea1 = checkea(',', L_ERRORS);
+
+            if (ea1 == ERROR)
+                return ERROR;
+
+            goto l_gotea1;
+
+        }
+    }
+    else if (*tok == '(')
+    {
+        // Maybe we got an expression here, check for it
+        if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
+        {
+            // Evaluate the expression and go to immediate code path
+            expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
+            goto l_check_immed;
+        }
+
+        //Nope, let's check for ea then
+        if (S1 == 0)
+            ea1 = checkea(',', L_ERRORS);
+        else
+            ea1 = checkea(EOL, L_ERRORS);
+
+        if (ea1 == ERROR)
+            return ERROR;
+
+    l_gotea1:
+        if (*tok == EOL)
+        {
+            // 'S,L:ea'
+            inst = B16(01000000, 01000000);
+            if (S1 == KW_A)
+                S1 = 4;
+            else if (S1 == KW_B)
+                S1 = 5;
+            else
+                S1 &= 7;
+
+            inst |= ea1;
+            inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
+            return inst;
+        }
+        else if (*tok++ != ',')
+            return error("Comma expected after 'L:(Rn)')");
+
+        // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
+        // If it is, the only possible syntax here is 'L:ea,D'.
+        // So check ahead to see if EOL follows D, then we're good to go.
+        if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
+        {
+            //'L:ea,D'
+            D1 = *tok++;
+            if (D1 == KW_A)
+                D1 = 4;
+            else if (D1 == KW_B)
+                D1 = 5;
+            else
+                D1 &= 7;
+
+            inst |= ea1;
+            inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
+            return inst;
+        }
+    }
+    else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+    {
+        // Check for immediate address
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+
+        // We set ea1 here - if it's aa instead of ea
+        // then it won't be used anyway
+        ea1 = DSP_EA_ABS;
+        if (!(dspImmedEXATTR & DEFINED))
+        {
+            force_imm = NUM_FORCE_LONG;
+            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+        }
+               else if (dspImmedEXVAL > 0x3f)
+               {
+                       // Definitely no aa material, so it's going to be a long
+                       // Mark that we need to deposit an extra word
+                       deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+               }
+
+        // Yes, we have an expression, so we now check for
+        // 'L:ea,D' or 'L:aa,D'
+        goto l_check_immed;
+    }
+    else if (*tok == '>')
+    {
+        // Check for immediate address forced long
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        if (dspImmedEXATTR & DEFINED)
+            if (dspImmedEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+
+        deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+        force_imm = NUM_FORCE_LONG;
+        goto l_check_immed;
+    }
+    else if (*tok == '<')
+    {
+        // Check for immediate address forced short
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        if (dspImmedEXATTR & DEFINED)
+        {
+            if (dspImmedEXVAL > 0xfff)
+                return error("short addressing mode forced but address is bigger than $fff");
+        }
+        else
+        {
+            // This might end up as something like 'move Y:<adr,register'
+            // so let's mark it as an extra aa fixup here.
+            // Note: we are branching to l_check_immed without a
+            // defined dspImmed so it's going to be 0. It probably
+            // doesn't harm anything.
+            deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
+        }
+
+        force_imm = NUM_FORCE_SHORT;
+        goto l_check_immed;
+    }
+
+    return error("internal assembler error: Please report this error message: 'reached the end of parse_l' with the line of code that caused it. Thanks, and sorry for the inconvenience");
+}
+
+
+//
+// Checks for all ea cases where indexed addressing is concenred
+//
+static inline LONG checkea(const uint32_t termchar, const int strings)
+{
+    LONG ea;
+    if (*tok == '-')
+    {
+        // -(Rn)
+        tok++;
+        if (*tok++ != '(')
+            return error(ea_errors[strings][0]);
+        if (*tok >= KW_R0 && *tok <= KW_R7)
+        {
+            // We got '-(Rn' so mark it down
+            ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
+            if (*tok++ != ')')
+                return error(ea_errors[strings][1]);
+            // Now, proceed to the main code for this branch
+            return ea;
+        }
+        else
+            return error(ea_errors[strings][2]);
+    }
+    else if (*tok == '(')
+    {
+        // Checking for ea of type (Rn)
+        tok++;
+        if (*tok >= KW_R0 && *tok <= KW_R7)
+        {
+            // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
+            ea = *tok++ - KW_R0;
+            if (*tok == '+')
+            {
+                // '(Rn+Nn)'
+                tok++;
+                if (*tok < KW_N0 || *tok > KW_N7)
+                    return error(ea_errors[strings][3]);
+                if ((*tok++ & 7) != ea)
+                    return error(ea_errors[strings][4]);
+                ea |= DSP_EA_INDEX;
+                if (*tok++ != ')')
+                    return error(ea_errors[strings][5]);
+                return ea;
+            }
+            else if (*tok == ')')
+            {
+                // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
+                tok++;
+                if (*tok == '+')
+                {
+                    tok++;
+                    if (termchar == ',')
+                    {
+                        if (*tok == ',')
+                        {
+                            // (Rn)+
+                            ea |= DSP_EA_POSTINC1;
+                            return ea;
+                        }
+                        else if (*tok >= KW_N0 && *tok <= KW_N7)
+                        {
+                            // (Rn)+Nn
+                            if ((*tok++ & 7) != ea)
+                                return error(ea_errors[strings][6]);
+                            ea |= DSP_EA_POSTINC;
+                            return ea;
+                        }
+                        else
+                            return error(ea_errors[strings][7]);
+                    }
+                    else
+                    {
+                        if (*tok >= KW_N0 && *tok <= KW_N7)
+                        {
+                            // (Rn)+Nn
+                            if ((*tok++ & 7) != ea)
+                                return error(ea_errors[strings][6]);
+                            ea |= DSP_EA_POSTINC;
+                            return ea;
+                        }
+                        else
+                        {
+                            // (Rn)+
+                            ea |= DSP_EA_POSTINC1;
+                            return ea;
+                        }
+                    }
+                }
+                else if (*tok == '-')
+                {
+                    tok++;
+                    if (termchar == ',')
+                    {
+                        if (*tok == ',')
+                        {
+                            // (Rn)-
+                            ea |= DSP_EA_POSTDEC1;
+                            return ea;
+                        }
+                        else if (*tok >= KW_N0 && *tok <= KW_N7)
+                        {
+                            // (Rn)-Nn
+                            if ((*tok++ & 7) != ea)
+                                return error(ea_errors[strings][8]);
+                            ea |= DSP_EA_POSTDEC;
+                            return ea;
+                        }
+                        else
+                            return error(ea_errors[strings][9]);
+                    }
+                    else
+                    {
+                        if (*tok >= KW_N0 && *tok <= KW_N7)
+                        {
+                            // (Rn)-Nn
+                            if ((*tok++ & 7) != ea)
+                                return error(ea_errors[strings][8]);
+                            ea |= DSP_EA_POSTDEC;
+                            return ea;
+                        }
+                        else
+                        {
+                            // (Rn)-
+                            ea |= DSP_EA_POSTDEC1;
+                            return ea;
+                        }
+                    }
+                }
+                else if (termchar == ',')
+                {
+                    if (*tok == ',')
+                    {
+                        // (Rn)
+                        ea |= DSP_EA_NOUPD;
+                        return ea;
+                    }
+                    else
+                        return error(ea_errors[strings][10]);
+                }
+                else
+                {
+                    // (Rn)
+                    ea |= DSP_EA_NOUPD;
+                    return ea;
+                }
+            }
+            else
+                return error(ea_errors[strings][11]);
+        }
+    }
+    return error("internal assembler error: Please report this error message: 'reached the end of checkea' with the line of code that caused it. Thanks, and sorry for the inconvenience");
+}
+
+
+//
+// Checks for all ea cases, i.e. all addressing modes that checkea handles
+// plus immediate addresses included forced short/long ones.
+// In other words this is a superset of checkea (and in fact calls checkea).
+//
+LONG checkea_full(const uint32_t termchar, const int strings)
+{
+    LONG ea1;
+
+    if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
+    {
+        // Check for immediate address
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+
+        deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+        // Yes, we have an expression
+        return DSP_EA_ABS;
+    }
+    else if (*tok == '>')
+    {
+        // Check for immediate address forced long
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        if (dspImmedEXATTR & DEFINED)
+            if (dspImmedEXVAL > 0xffffff)
+                return error("long address is bigger than $ffffff");
+
+        deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+        // Yes, we have an expression
+        return DSP_EA_ABS;
+    }
+    else if (*tok == '<')
+    {
+        // Check for immediate address forced short
+        tok++;
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+        if (dspImmedEXATTR & DEFINED)
+            if (dspImmedEXVAL > 0xfff)
+                return error("short addressing mode forced but address is bigger than $fff");
+
+        // Yes, we have an expression
+        return DSP_EA_ABS;
+    }
+    else
+    {
+        ea1 = checkea(termchar, strings);
+        if (ea1 == ERROR)
+            return ERROR;
+        else
+            return ea1;
+    }
+
+}
+
+//
+// Main routine to check parallel move modes.
+// It's quite complex so it's split into a few procedures (in fact most of the above ones).
+// A big effort was made so this can be managable and not too hacky, however one look at
+// the 56001 manual regarding parallel moves and you'll know that this is not an easy
+// problem to deal with!
+// dest=destination register from the main opcode. This must not be the same as D1 or D2
+// and that even goes for stuff like dest=A, D1=A0/1/2!!!
+//
+LONG parmoves(WORD dest)
+{
+    int force_imm;          // Addressing mode force operator
+    int immreg;             // Immediate register destination
+    LONG inst;              // 16 bit bitfield that has the parallel move opcode
+    LONG S1, S2, D1, D2;    // Source and Destinations
+    LONG ea1;                          // ea bitfields
+
+    if (*tok == EOL)
+    {
+        // No parallel move
+        return B16(00100000, 00000000);
+    }
+    if (*tok == '#')
+    {
+        // '#xxxxxx,D', '#xx,D'
+        tok++;
+        force_imm = NUM_NORMAL;
+        if (*tok == '>')
+        {
+            force_imm = NUM_FORCE_LONG;
+            tok++;
+        }
+        else if (*tok == '<')
+        {
+            force_imm = NUM_FORCE_SHORT;
+            tok++;
+        }
+
+        if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+            return ERROR;
+
+        if (*tok++ != ',')
+            return error("expected comma");
+
+        if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
+            return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
+        immreg = SDreg(*tok++);
+
+        if (*tok == EOL)
+        {
+            if (!(dspImmedEXATTR & FLOAT))
+            {
+                if (dspImmedEXATTR & DEFINED)
+                {
+                    // From I parallel move:
+                    // "If the destination register D is X0, X1, Y0, Y1, A, or B, the 8-bit immediate short operand
+                    // is interpreted as a signed fraction and is stored in the specified destination register.
+                    // That is, the 8 - bit data is stored in the eight MS bits of the destination operand, and the
+                    // remaining bits of the destination operand D are zeroed."
+                    // The funny bit is that Motorola assembler can parse something like 'move #$FF0000,b' into an
+                    // I (immediate short move) - so let's do that as well then...
+                    if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
+                    {
+                        if ((dspImmedEXVAL & 0xffff) == 0)
+                        {
+                            dspImmedEXVAL >>= 16;
+                        }
+                    }
+                    if (force_imm == NUM_FORCE_SHORT)
+                    {
+                        if (dspImmedEXVAL<0xff && (int32_t)dspImmedEXVAL>-0x100)
+                        {
+                            // '#xx,D'
+                            // value fits in 8 bits - immediate move
+                            inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
+                            return inst;
+                        }
+                        else
+                        {
+                            warn("forced short immediate value doesn't fit in 8 bits - switching to long");
+                            force_imm = NUM_FORCE_LONG;
+                        }
+                    }
+                    if (force_imm == NUM_FORCE_LONG)
+                    {
+                        // '#xxxxxx,D'
+                        // it can either be
+                        // X or Y Data move. I don't think it matters much
+                        // which of the two it will be, so let's use X.
+                    deposit_immediate_long_with_register:
+                        inst = B16(01000000, 11110100);
+                        inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
+                        deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                        return inst;
+                    }
+                    if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
+                    {
+                        // value fits in 8 bits - immediate move
+                    deposit_immediate_short_with_register:
+                        inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
+                        return inst;
+                    }
+                    else
+                    {
+                        // value doesn't fit in 8 bits, so it can either be
+                        // X or Y Data move. I don't think it matters much
+                        // which of the two it will be, so let's use X:.
+                        // TODO: if we're just goto'ing perhaps the logic can be simplified
+                        goto deposit_immediate_long_with_register;
+                    }
+                }
+                else
+                {
+                    if (force_imm != NUM_FORCE_SHORT)
+                    {
+                        // '#xxxxxx,D'
+                        // TODO: if we're just goto'ing perhaps the logic can be simplified
+                        goto deposit_immediate_long_with_register;
+                    }
+                    else
+                    {
+                        // '#xx,D' - I mode
+                        // No visibility of the number so let's add a fixup for this
+                        AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
+                        inst = B16(00100000, 00000000);
+                        inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
+                        return inst;
+                    }
+
+                }
+            }
+            else
+            {
+                // Float constant
+                if (dspImmedEXATTR & DEFINED)
+                {
+
+                    double f = *(double *)&dspImmedEXVAL;
+                    // Check direct.c for ossom comments regarding conversion!
+                    dspImmedEXVAL = ((uint32_t)(int32_t)round(f*(1 << 23))) & 0xffffff;
+                    double g;
+                    g = f*(1 << 23);
+                    g = round(g);
+
+                    if ((dspImmedEXVAL & 0xffff) == 0)
+                    {
+                        // Value's 16 lower bits are not set so the value can fit in a single byte
+                        // (check parallel I move quoted above)
+                        warn("Immediate value fits inside 8 bits, so using instruction short format");
+                        dspImmedEXVAL >>= 16;
+                        goto deposit_immediate_short_with_register;
+                    }
+
+                    if (force_imm == NUM_FORCE_SHORT)
+                    {
+                        if ((dspImmedEXVAL & 0xffff) != 0)
+                        {
+                            warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
+                            goto deposit_immediate_long_with_register;
+                        }
+                        return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
+                    }
+                    // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
+                    goto deposit_immediate_long_with_register;
+                }
+                else
+                {
+                    if (force_imm == NUM_FORCE_SHORT)
+                    {
+                                               goto deposit_immediate_short_with_register;
+                    }
+                    else
+                    {
+                        // Just deposit a float fixup
+                        AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
+                        inst = B16(00100000, 00000000);
+                        inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
+                        return inst;
+                    }
+                }
+            }
+        }
+        else
+        {
+            // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
+
+            switch (immreg)
+            {
+            case 4: D1 = 0 << 10;break;  // X0
+            case 5: D1 = 1 << 10;break;  // X1
+            case 14: D1 = 2 << 10;break; // A
+            case 15: D1 = 3 << 10;break; // B
+            default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
+            }
+
+            switch (*tok++)
+            {
+            case KW_A: S2 = 0 << 9; break;
+            case KW_B: S2 = 1 << 9; break;
+            default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
+            }
+
+            if (*tok++ != ',')
+                return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
+
+            switch (*tok++)
+            {
+            case KW_Y0: D2 = 0 << 8; break;
+            case KW_Y1: D2 = 1 << 8; break;
+            default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
+            }
+
+            if (*tok != EOL)
+                return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
+
+            inst = B16(00010000, 10110100) | D1 | S2 | D2;
+            deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+            return inst;
+        }
+    }
+    else if (*tok == KW_X)
+    {
+               if (tok[1] == ',')
+                       // Hey look, it's just the register X and not the addressing mode - fall through to general case
+                       goto parse_everything_else;
+
+               tok++;
+
+               if (*tok++ != ':')
+            return error("expected ':' after 'X' in parallel move (i.e. X:)");
+
+               // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
+               return parse_x(1, B16(01000000, 00000000), 0, 1);
+    }
+    else if (*tok == KW_Y)
+    {
+               if (tok[1] == ',')
+                       // Hey look, it's just the register y and not the addressing mode - fall through to general case
+                       goto parse_everything_else;
+
+               tok++;
+               if (*tok++ != ':')
+            return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
+
+               // 'Y:ea,D' or 'Y:aa,D'
+        return parse_y(B16(01001000, 10000000), 0, 0, 0);
+    }
+    else if (*tok == KW_L)
+    {
+        // 'L:ea,D' or 'L:aa,D'
+        tok++;
+        if (*tok++ != ':')
+            return error("expected ':' after 'L' in parallel move (i.e. L:)");
+
+        return parse_l(1, B16(01000000, 11000000), 0);
+    }
+    else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2) || (*tok >= KW_A10 && *tok <= KW_BA))
+    {
+        // Everything else - brace for impact!
+        // R:   'S,D'
+        // X:   'S,X:ea' 'S,X:aa'
+        // X:R  'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
+        // Y:   'S,Y:ea' 'S,Y:aa'
+        // R:Y: 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 #xxxxxx,D2' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
+        // L:   'S,L:ea' 'S,L:aa'
+               LONG L_S1;
+parse_everything_else:
+               L_S1 = *tok++;
+               S1 = SDreg(L_S1);
+
+        if (*tok++ != ',')
+            return error("Comma expected after 'S')");
+
+        if (*tok == KW_X)
+        {
+            // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
+            // 'A,X:ea X0,A' 'B,X:ea X0,B'
+            tok++;
+            if (*tok++ != ':')
+                return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
+            return parse_x(0, B16(01000000, 00000000), S1, 1);
+        }
+        else if (*tok == KW_Y)
+        {
+            // 'S,Y:ea' 'S,Y:aa'
+            tok++;
+            if (*tok++ != ':')
+                return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
+            return parse_y(B16(0000000, 00000000), S1, 0, 0);
+        }
+        else if (*tok == KW_L)
+        {
+            // 'S,L:ea' 'S,L:aa'
+            tok++;
+            if (*tok++ != ':')
+                return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
+            return parse_l(1, B16(00000000, 00000000), L_S1);
+        }
+        else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
+        {
+            // 'S,D'
+            // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
+            // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
+            D1 = SDreg(*tok++);
+            if (*tok == EOL)
+            {
+                // R 'S,D'
+                inst = B16(00100000, 00000000);
+                inst |= (S1 << 5) | (D1);
+                return inst;
+            }
+            else if (*tok == KW_Y)
+            {
+                // 'S1,D1 Y:ea,D2'
+                tok++;
+                if (*tok++ != ':')
+                    return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
+                return parse_y(B16(00010000, 01000000), S1, D1, 0);
+
+            }
+            else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
+            {
+                // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
+                S2 = SDreg(*tok++);
+                if (S1 == 6 && D1 == 14 && S2 == 14)
+                {
+                    // 'Y0,A A,Y:ea'
+                    if (*tok++ != ',')
+                        return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
+                    if (*tok++ != KW_Y)
+                        return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
+                    if (*tok++ != ':')
+                        return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
+                    ea1 = checkea_full(EOL, Y_ERRORS);
+                    if (ea1 == ERROR)
+                        return ERROR;
+                    inst = B16(00001000, 10000000);
+                    inst |= 0 << 8;
+                    inst |= ea1;
+                    return inst;
+                }
+                else if (S1 == 6 && D1 == 15 && S2 == 15)
+                {
+                    // 'Y0,B B,Y:ea'
+                    if (*tok++ != ',')
+                        return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
+                    if (*tok++ != KW_Y)
+                        return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
+                    if (*tok++ != ':')
+                        return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
+                    ea1 = checkea_full(EOL, Y_ERRORS);
+                    if (ea1 == ERROR)
+                        return ERROR;
+                    inst = B16(00001000, 10000000);
+                    inst |= 1 << 8;
+                    inst |= ea1;
+                    return inst;
+                }
+                else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
+                {
+                    //'S1,D1 S2,Y:ea'
+                    if (*tok++ != ',')
+                        return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
+                    if (*tok++ != KW_Y)
+                        return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
+                    if (*tok++ != ':')
+                        return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
+                    ea1 = checkea_full(EOL, Y_ERRORS);
+                    if (ea1 == ERROR)
+                        return ERROR;
+                    inst = B16(00010000, 01000000);
+                    inst |= (S1 & 1) << 11;
+                    inst |= (D1 & 1) << 10;
+                    inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
+                    inst |= ea1;
+                    return inst;
+                }
+                else
+                    return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
+                // Check for Y:
+            }
+            else if (*tok == '#')
+            {
+                // R:Y: 'S1,D1 #xxxxxx,D2'
+                tok++;
+                if (*tok == '>')
+                {
+                    // Well, forcing an immediate to be 24 bits is legal here
+                    // but then it's the only available option so my guess is that this
+                    // is simply superfluous. So let's just eat the character
+                    tok++;
+                }
+                if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
+                    return ERROR;
+                if (dspImmedEXATTR & DEFINED)
+                    if (dspImmedEXVAL > 0xffffff)
+                        return error("immediate is bigger than $ffffff");
+                deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+                if (*tok++ != ',')
+                    return error("Comma expected after 'S1,D1 #xxxxxx')");
+                // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
+                switch (*tok++)
+                {
+                case KW_Y0: D2 = 0 << 8; break;
+                case KW_Y1: D2 = 1 << 8; break;
+                case KW_A:  D2 = 2 << 8; break;
+                case KW_B:  D2 = 3 << 8; break;
+                default:    return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
+                }
+
+                if (S1 == 14 || S1 == 15)
+                {
+                    if (D1 == 4 || D1 == 5)
+                    {
+                        inst = B16(00010000, 11110100);
+                        inst |= (S1 & 1) << 11;
+                        inst |= (D1 & 1) << 10;
+                        inst |= D2;
+                        dspImmedEXVAL = dspaaEXVAL;
+                        return inst;
+                    }
+                    else
+                        return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
+                }
+                else
+                    return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
+            }
+            else
+                return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
+        }
+        else
+            return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
+    }
+    else if (*tok == '(')
+    {
+        // U: 'ea'
+        // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
+        tok++;
+        if (*tok >= KW_R0 && *tok <= KW_R7)
+        {
+            ea1 = (*tok++ - KW_R0);
+        }
+        else
+            return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
+        if (*tok++ != ')')
+            return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
+        if (*tok == '+')
+        {
+            tok++;
+            if (*tok == EOL)
+                // (Rn)+
+                ea1 |= 3 << 3;
+            else if (*tok >= KW_N0 && *tok <= KW_N7)
+            {
+                // (Rn)+Nn
+                if ((*tok++ & 7) != ea1)
+                    return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
+                ea1 |= 1 << 3;
+                if (*tok != EOL)
+                    return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
+            }
+            else
+                return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
+
+        }
+        else if (*tok == '-')
+        {
+            tok++;
+            if (*tok == EOL)
+            {
+                // (Rn)-
+                ea1 |= 2 << 3;
+                tok++;
+            }
+            else if (*tok >= KW_N0 && *tok <= KW_N7)
+            {
+                // (Rn)-Nn
+                if ((*tok++ & 7) != ea1)
+                    return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
+                ea1 |= 0 << 3;
+                if (*tok != EOL)
+                    return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
+            }
+        }
+
+        inst = B16(00100000, 01000000);
+        inst |= ea1;
+        return inst;
+    }
+    else
+        return error("extra (unexpected) text found");
+
+    return OK;
+}
+
diff --git a/dsp56k_amode.h b/dsp56k_amode.h
new file mode 100644 (file)
index 0000000..03ae962
--- /dev/null
@@ -0,0 +1,149 @@
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DSP56K_AMODE.H - Addressing Modes for Motorola DSP56001
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source utilised with the kind permission of Landon Dyer
+//
+
+#ifndef __DSP56K_AMODE_H__
+#define __DSP56K_AMODE_H__
+
+#include "rmac.h"
+#include "amode.h"
+
+// Addressing-mode masks
+
+#define M_ACC56      0x00000001L       // Accumulators A=A2:A1:A0 and B=B2:B1:B0
+#define M_ACC48      0x00000002L       // Accumulators AB=A1:B1, BA=B1:A1, A10=A1:A0, B10=B1:B0
+#define M_ACC24      0x00000004L       // Accumulators A0, A1, B0 and B1
+#define M_ACC8       0x00000008L       // Accumulators A2 and B2
+#define M_INP48      0x00000010L       // Input registers X=X1:X0 and Y=Y1:Y0
+#define M_ALU24      0x00000020L       // Data ALU input registers X1, X0, Y1, Y0
+#define M_DSPIM      0x00000040L       // #data
+#define M_DSPIM12    0x00000080L       // #data
+//#define M_DSPIM24    0x0000010       // #data
+#define M_DSPPCU     0x00000200L       // Program control unit registers PC, MR, CCR, SR, OMR, LA, LC, SP, SS, SSH, SSL
+#define M_DSPEA      0x00000400L       // Effective addressing modes (Rn)-Nn, (Rn)+Nn, (Rn)-, (Rn)+, (Rn), (Rn+Nn), -(Rn), <absolute address>
+#define M_DSPAA      0x00000800L       // 6-bit Absolute Short Address
+#define M_DSPPP      0x00001000L       // 6-bit I/O Short Address
+#define M_DSPM       0x00002000L       // Modifier registers M0-M7
+#define M_DSPR       0x00004000L       // Address registers R0-R7
+#define M_DSPN       0x00008000L       // Address offset registers N0-N7
+#define M_DSPABS12   0x00010000L       // xxx.12bit
+#define M_DSPABS24   0x00020000L       // xxx.24bit
+#define M_DSPABS06   0x00040000L       // xxx.6bit
+#define M_DSPABS16   0x00080000L       // xxx.16bit
+#define M_DSPIM8     0x00100000L       // #data
+
+#define M_ALL48 (M_ACC56|M_INP48|M_ALU24)   // Input registers X=X1:X0, Y=Y1:Y0, A=A2:A1:A0, B=B2:B1:B0, X0, X1, Y0, Y1
+
+#define C_DD    (M_ALU24)                   // 4 registers in data ALU: x0, x1, y0, y1
+#define C_DDD   (M_ACC56|M_ACC24|M_ACC8)    // 8 accumulators in data ALU: a0, b0, a2, b2, a1, b1, a, b
+#define C_LLL   (M_ACC56|M_ACC48|M_INP48)   // 8 extended-precision registers in data ALU: a10, b10, x, y, a, b, ab, ba
+#define C_FFF   (M_DSPM)                    // 8 address modifier registers in address ALU:  m0-m7
+#define C_NNN   (M_DSPN)                    // 8 address offset registers in address ALU: n0-n7
+#define C_TTT   (M_DSPR)                    // 8 address registers in address: r0-r7
+#define C_GGG   (M_DSPPCU)                  // 8 program controller registers: sr, omr, sp, ssh, la, lc
+#define C_A18   (M_ALU24|C_DDD|C_LLL|C_FFF|C_NNN|C_TTT|C_GGG)   // All of the above registers
+
+#define C_DSPABS24     (M_DSPABS06|M_DSPABS12|M_DSPABS16|M_DSPABS24)   // Everything up to 24-bit addresses
+#define C_DSPABSEA     (C_DSPABS24|M_DSPEA)                                                    // All absolute addresses and all other ea addressing modes
+#define C_DSPABS16  (M_DSPABS06|M_DSPABS12|M_DSPABS16)                         // Everything up to 16-bit addresses
+#define C_LUADST    (M_DSPR|M_DSPN)                                                                    // Mask for LUA instruction destination
+#define C_MOVEC     (M_DSPM|M_DSPPCU)                                                          // M0-M7 and SR, OMR, LA, LC, SP, SS, SSH, SSL
+#define C_DSPIM                (M_DSPIM8 | M_DSPIM | M_DSPIM12)                                // All the immmediate sizes we want to alias
+
+// Xn Input Register X1 or X0 (24 Bits)
+// Yn Input Register Y1 or Y0 (24 Bits)
+// An Accumulator Registers A2, A1, A0 (A2 \97 8 Bits, A1 and A0 \97 24 Bits)
+// Bn Accumulator Registers B2, B1, B0 (B2 \97 8 Bits, B1 and B0 \97 24 Bits)
+// X Input Register X = X1: X0 (48 Bits)
+// Y Input Register Y = Y1: Y0 (48 Bits)
+// A Accumulator A = A2: A1: A0 (56 Bits)*
+// B Accumulator B = B2: B1: B0 (56 BIts)*
+// AB Accumulators A and B = A1: B1 (48 Bits)*
+// BA Accumulators B and A = B1: A1 (48 Bits)*
+// A10 Accumulator A = A1: A0 (48 Bits)
+// B10 Accumulator B= B1:B0 (48 bits)
+
+// Attribute masks
+#define PARMOVE      0x00000001L
+#define NOPARMO      0x00000000L
+
+// DSP EA modes
+
+#define DSP_EA_POSTDEC  B8(00000000)
+#define DSP_EA_POSTINC  B8(00001000)
+#define DSP_EA_POSTDEC1 B8(00010000)
+#define DSP_EA_POSTINC1 B8(00011000)
+#define DSP_EA_NOUPD    B8(00100000)
+#define DSP_EA_INDEX    B8(00101000)
+#define DSP_EA_PREDEC1  B8(00111000)
+#define DSP_EA_ABS      B8(00110000)
+#define DSP_EA_IMM      B8(00110100)
+
+
+// Mnemonic table structure
+#define MNTABDSP  struct _mntabdsp
+MNTABDSP {
+       LONG mn0, mn1;                          // Addressing modes
+       WORD mnattr;                            // Attributes (PARMOVE, ...)
+       LONG mninst;                            // Instruction mask
+       WORD mncont;                            // Continuation (or -1)
+       int (* mnfunc)(LONG);           // Mnemonic builder
+};
+
+// Addressing mode variables, output of dsp_amode()
+int dsp_am0;                                   // Addressing mode
+int dsp_a0reg;                                 // Register
+int dsp_am1;                                   // Addressing mode
+int dsp_a1reg;                                 // Register
+int dsp_am2;                                   // Addressing mode
+int dsp_a2reg;                                 // Register
+int dsp_am3;                                   // Addressing mode
+int dsp_a3reg;                                 // Register
+
+TOKEN dsp_a0expr[EXPRSIZE];            // Expression
+uint64_t dsp_a0exval;                  // Expression's value
+WORD dsp_a0exattr;                             // Expression's attribute
+SYM * dsp_a0esym;                              // External symbol involved in expr
+LONG dsp_a0memspace;                   // Addressing mode's memory space (P, X, Y)
+LONG dsp_a0perspace;                   // Peripheral space (X, Y - used in movep)
+TOKEN dsp_a1expr[EXPRSIZE];            // Expression
+uint64_t dsp_a1exval;                  // Expression's value
+WORD dsp_a1exattr;                             // Expression's attribute
+SYM * dsp_a1esym;                              // External symbol involved in expr
+LONG dsp_a1memspace;                   // Addressing mode's memory space (P, X, Y)
+LONG dsp_a1perspace;                   // Peripheral space (X, Y - used in movep)
+TOKEN dsp_a2expr[EXPRSIZE];            // Expression
+uint64_t dsp_a2exval;                  // Expression's value
+WORD dsp_a2exattr;                             // Expression's attribute
+SYM * dsp_a2esym;                              // External symbol involved in expr
+TOKEN dsp_a3expr[EXPRSIZE];            // Expression
+uint64_t dsp_a3exval;                  // Expression's value
+WORD dsp_a3exattr;                             // Expression's attribute
+SYM * dsp_a3esym;                              // External symbol involved in expr
+int dsp_k;                                             // Multiplications sign
+TOKEN dspImmedEXPR[EXPRSIZE];  // Expression
+uint64_t dspImmedEXVAL;                        // Expression's value
+WORD  dspImmedEXATTR;                  // Expression's attribute
+SYM * dspImmedESYM;                            // External symbol involved in expr
+int  deposit_extra_ea;                 // Optional effective address extension
+
+
+// Extra ea deposit modes
+enum
+{
+       DEPOSIT_EXTRA_WORD  = 1,
+       DEPOSIT_EXTRA_FIXUP = 2,
+};
+
+
+// Prototypes
+int dsp_amode(int maxea);
+LONG parmoves(WORD dest);
+int dsp_tcc4(LONG inst);
+
+#endif // __DSP56K_AMODE_H__
+
diff --git a/dsp56k_mach.c b/dsp56k_mach.c
new file mode 100644 (file)
index 0000000..20fc07a
--- /dev/null
@@ -0,0 +1,1460 @@
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DSP56L_MACH.C - Code Generation for Motorola DSP56001
+// 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 "dsp56k_mach.h"
+#include "direct.h"
+#include "dsp56k.h"
+#include "error.h"
+#include "rmac.h"
+#include "sect.h"
+#include "token.h"
+
+#define DEF_KW
+#include "kwtab.h"
+
+
+// Globals
+unsigned int dsp_orgaddr;      // DSP 56001 ORG address
+unsigned int dsp_orgseg;       // DSP 56001 ORG segment
+
+
+// Fucntion prototypes
+int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
+int dsp_ab(LONG);
+int dsp_baab(LONG inst);
+int dsp_acc48(LONG inst);
+int dsp_self(LONG inst);
+int dsp_xyab(LONG inst);
+int dsp_x0y0ab(LONG inst);
+int dsp_immcr(LONG inst);
+int dsp_immmovec(LONG inst);
+int dsp_imm12(LONG inst);
+int dsp_tcc2(LONG inst);
+int dsp_tcc4(LONG inst);
+int dsp_ea(LONG inst);
+int dsp_ea_imm5(LONG inst);
+int dsp_abs12(LONG inst);
+int dsp_reg_imm5(LONG inst);
+int dsp_ea_abs16(LONG inst);
+int dsp_reg_abs16(LONG inst);
+int dsp_imm12_abs16(LONG inst);
+int dsp_alu24_abs16(LONG inst);
+int dsp_reg(LONG inst);
+int dsp_alu24(LONG inst);
+int dsp_reg_imm5_abs16(LONG inst);
+int dsp_ea_imm5_abs16(LONG inst);
+int dsp_ea_lua(LONG inst);
+int dsp_ab_rn(LONG inst);
+int dsp_movec_ea(LONG inst);
+int dsp_movec_aa(LONG inst);
+int dsp_movec_reg(LONG inst);
+int dsp_mult(LONG inst);
+int dsp_movem_ea(LONG inst);
+int dsp_movem_aa(LONG inst);
+int dsp_movep_ea(LONG inst);
+int dsp_movep_reg(LONG inst);
+
+
+// Common error messages
+
+
+// Include code tables
+MNTABDSP dsp56k_machtab[] = {
+   { 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0x0000, 0, (int (*)(LONG))m_badmode }, // 0
+   #include "dsp56ktab.h"
+   {  0L,  0L, 0x0000, 0x0000, 0, (int (*)(LONG))m_unimp   }                   // Last entry
+};
+
+
+static inline int dsp_extra_ea()
+{
+       if (deposit_extra_ea == DEPOSIT_EXTRA_WORD)
+       {
+               if (!(dspImmedEXATTR&FLOAT))
+               {
+                       if (dspImmedEXATTR & DEFINED)
+                       {
+                               D_dsp(dspImmedEXVAL);
+                       }
+                       else
+                       {
+                               // TODO: what if it's an address and not an immediate? Does it matter at all?
+                               AddFixup(FU_DSPIMM24, sloc, dspImmedEXPR);
+                               D_dsp(0);
+                       }
+               }
+               else
+               {
+                       if (dspImmedEXATTR & DEFINED)
+                       {
+                               D_dsp(dspImmedEXVAL);
+                       }
+                       else
+                       {
+                               // TODO: what if it's an address and not an immediate? Does it matter at all?
+                               AddFixup(FU_DSPIMMFL24, sloc, dspImmedEXPR);
+                               D_dsp(0);
+                       }
+               }
+       }
+       else if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
+       {
+               // Probably superfluous check (we're not likely to land here with a
+               // known aa) but oh well
+               if (!(dspImmedEXATTR & DEFINED))
+               {
+                       // Since we already deposited the word to be fixup'd we need to
+                       // subtract 1 from sloc
+                       chptr -= 3;
+                       AddFixup(FU_DSPADR06, sloc - 1, dspImmedEXPR);
+                       chptr += 3;
+               }
+       }
+
+       return OK;
+}
+
+
+int dsp_ab(LONG inst)
+{
+       inst |= (dsp_a0reg & 1) << 3;
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+       return OK;
+}
+
+
+int dsp_baab(LONG inst)
+{
+       if (dsp_a0reg == dsp_a1reg)
+               return error("source and destination registers must not be the same");
+
+       inst |= ((dsp_a0reg + 1) & 1) << 3;
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+
+       return OK;
+}
+
+
+int dsp_acc48(LONG inst)
+{
+       if (dsp_a0reg == dsp_a1reg)
+               return error("source and destination registers must not be the same");
+
+       inst |= (dsp_a1reg & 1) << 3;
+
+       switch (dsp_a0reg)
+       {
+       case KW_X:  inst |= 2 << 4; break;
+       case KW_Y:  inst |= 3 << 4; break;
+       case KW_X0: inst |= 4 << 4;break;
+       case KW_Y0: inst |= 5 << 4;break;
+       case KW_X1: inst |= 6 << 4;break;
+       case KW_Y1: inst |= 7 << 4;break;
+       default: return error("dsp_acc48: shouldn't reach here!");
+       }
+
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+
+       return OK;
+}
+
+
+int dsp_self(LONG inst)
+{
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+
+       return OK;
+}
+
+
+int dsp_xyab(LONG inst)
+{
+       if (dsp_a0reg == dsp_a1reg)
+               return error("source and destination registers must not be the same");
+
+       inst |= (dsp_a0reg & 1) << 4;
+       inst |= (dsp_a1reg & 1) << 3;
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+
+       return OK;
+}
+
+
+int dsp_x0y0ab(LONG inst)
+{
+       if (dsp_a0reg == dsp_a1reg)
+               return error("source and destination registers must not be the same");
+
+       int inverse = (dsp_a0reg & 3);
+       inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1);
+       inst |= inverse << 4;
+       inst |= (dsp_a1reg & 1) << 3;
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+
+       return OK;
+}
+
+
+int dsp_immcr(LONG inst)
+{
+       switch (dsp_a1reg)
+       {
+       case KW_CCR: inst |= 1; break;
+       case KW_MR:inst |= 0; break;
+       case KW_OMR:inst |= 2; break;
+       default: return error("invalid destination register (only ccr, mr, omr allowed");
+       }
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               inst |= dsp_a0exval << 8;
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPIMM8, sloc, dsp_a0expr);
+               D_dsp(inst);
+       }
+
+       return OK;
+}
+
+
+int dsp_immmovec(LONG inst)
+{
+       switch (dsp_a1reg)
+       {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+       case 7:      inst |= dsp_a1reg; break; // M0-M7
+       case KW_SR:  inst |= 25; break;
+       case KW_OMR: inst |= 26; break;
+       case KW_SP:  inst |= 27; break;
+       case KW_SSH: inst |= 28; break;
+       case KW_SSL: inst |= 29; break;
+       case KW_LA:  inst |= 30; break;
+       case KW_LC:  inst |= 31; break;
+       default: return error("invalid destination register (only m0-m7, SR, OMR, SP, SSH, SSL, LA, LC allowed");
+       }
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               inst |= (dsp_a0exval & 0xff) << 8;
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPIMM8, sloc, dsp_a0expr);
+               D_dsp(inst);
+       }
+
+       return OK;
+}
+
+
+int dsp_imm12(LONG inst)
+{
+       if (dsp_a0exattr & DEFINED)
+       {
+               if ((dsp_am0 & (M_DSPIM12 | M_DSPIM8)) == 0)
+                       return error("immediate out of range ($000-$fff)");
+               inst |= ((dsp_a0exval & 0x0ff) << 8) | ((dsp_a0exval & 0xf00) >> 8);
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPIMM12, sloc, dsp_a0expr);
+               D_dsp(inst);
+       }
+
+       return OK;
+}
+
+
+// Tcc instructions with 2 operands (48bit)
+int dsp_tcc2(LONG inst)
+{
+       if (dsp_a0reg == dsp_a1reg)
+               return error("First pair of source and destination registers must not be the same");
+
+       int inverse;
+       inverse = (dsp_a0reg & 7);
+       inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1) | (inverse & 4);
+       inst |= inverse << 4;
+       inst |= ((dsp_a1reg) & 1) << 3;
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+// Tcc instructions with 4 operands
+int dsp_tcc4(LONG inst)
+{
+       if (dsp_a0reg == dsp_a1reg)
+               return error("First pair of source and destination registers must not be the same");
+
+       if (dsp_am2 != M_DSPR || dsp_am3 != M_DSPR)
+               return error("Second pair of source and destination registers must be R0-R7");
+
+       if (dsp_am0 == M_ACC56 && dsp_am1 == M_ACC56)
+       {
+               inst |= ((dsp_a0reg + 1) & 1) << 3;
+       }
+       else
+       {
+               int inverse;
+               inverse = (dsp_a0reg & 7);
+               inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1) | (inverse & 4);
+               inst |= inverse << 4;
+               inst |= ((dsp_a1reg) & 1) << 3;
+       }
+
+       inst |= 1 << 16;
+       inst |= (dsp_a2reg << 8) | (dsp_a3reg);
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+// Just store ea
+int dsp_ea(LONG inst)
+{
+       inst |= dsp_a0reg << 8;
+
+       if (dsp_a0memspace != -1)
+               inst |= dsp_a0memspace;
+
+       if (dsp_am0 == M_DSPAA)
+               inst |= ((dsp_a0exval & 0x3f) << 8);
+
+       D_dsp(inst);
+
+       if (dsp_a0reg == DSP_EA_ABS)
+       {
+               if (dsp_a0exattr & DEFINED)
+               {
+                       D_dsp(dsp_a0exval);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR24, sloc, dsp_a0expr);
+                       D_dsp(0);
+               }
+       }
+
+       return OK;
+}
+
+
+// Store ea and 5-bit constant
+int dsp_ea_imm5(LONG inst)
+{
+       if (dsp_a1memspace == -1)
+               return error("Only X: or Y: memory space allowed");
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               int v = (int)dsp_a0exval;
+
+               if (v < 0 || v > 23)
+                       return error("immediate value must be between 0 and 23");
+
+               if (dsp_a1reg == DSP_EA_ABS)
+               {
+                       inst |= (v | dsp_a1memspace | (dsp_a1reg << 8));
+               }
+               else
+               {
+                       inst |= ((dsp_a1exval & 0x3F) << 8) | v | dsp_a1memspace | (dsp_a1reg << 8);
+               }
+
+               D_dsp(inst);
+
+               if (dsp_a1reg == DSP_EA_ABS)
+               {
+                       if (dsp_a1exattr & DEFINED)
+                       {
+                               D_dsp(dsp_a1exval);
+                       }
+                       else
+                       {
+                               AddFixup(FU_DSPADR24, sloc, dsp_a1expr);
+                               D_dsp(0);
+                       }
+               }
+       }
+       else
+       {
+               if (dsp_a1reg == DSP_EA_ABS)
+               {
+                       inst |= dsp_a1memspace | (dsp_a1reg << 8);
+               }
+               else
+               {
+                       inst |= ((dsp_a1exval & 0x3F) << 8) | dsp_a1memspace | (dsp_a1reg << 8);
+               }
+
+               AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
+               D_dsp(inst);
+
+               if (dsp_a1reg == DSP_EA_ABS)
+               {
+                       if (dsp_a1exattr & DEFINED)
+                       {
+                               D_dsp(dsp_a1exval);
+                       }
+                       else
+                       {
+                               AddFixup(FU_DSPADR24, sloc, dsp_a1expr);
+                               D_dsp(0);
+                       }
+               }
+       }
+
+       return OK;
+}
+
+
+// Processes the input register according to table A-18 of the Motorola DSP
+// manual and returns the correct encoding.
+// Note: returns only the 3 lower bits of the table. The rest is handled in
+//       dsp56ktab.
+static inline LONG tab_A18(int *am, int *reg)
+{
+       switch (*am)
+       {
+       case M_ALU24:
+               return (*reg & 7);
+       case M_DSPM:
+       case M_DSPN:
+       case M_DSPR:
+               return *reg;
+               break;
+       case M_ACC56:
+       case M_ACC24:
+       case M_ACC8:
+               if (*reg == KW_A1)
+                       return 4;
+               else
+                       return (*reg & 7);
+
+               break;
+       case M_DSPPCU:
+               switch (*reg)
+               {
+               case KW_SR:  return 1; break;
+               case KW_OMR: return 2; break;
+               case KW_SP:  return 3; break;
+               case KW_SSH: return 4; break;
+               case KW_SSL: return 5; break;
+               case KW_LA:  return 6; break;
+               case KW_LC:  return 7; break;
+               default:
+                       return error("specified control register not allowed as destination");
+                       break;
+               }
+
+               break;
+       default:
+               return error("reached at the end of tab_A18 - shouldn't happen!");
+       }
+}
+
+
+// Store register (table A-18 in the motorola manual) and 5-bit constant
+int dsp_reg_imm5(LONG inst)
+{
+       LONG reg;
+
+       if ((reg = tab_A18(&dsp_am1, &dsp_a1reg)) == ERROR)
+               return ERROR;
+
+       inst |= (reg << 8);
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               int v = (int)dsp_a0exval;
+
+               if (v < 0 || v > 23)
+                       return error("immediate value must be between 0 and 23");
+
+               inst |= v;
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
+               D_dsp(inst);
+       }
+
+       return OK;
+}
+
+
+// Store 12-bit address
+int dsp_abs12(LONG inst)
+{
+       if (dsp_a0exattr & DEFINED)
+       {
+               int v = (int)dsp_a0exval;
+
+               if (v < 0 || v > 0xFFF)
+                       return error("immediate out of range ($000-$FFF)");
+
+               inst |= v;
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPADR12, sloc, dsp_a0expr);
+               D_dsp(inst);
+       }
+
+       return OK;
+}
+
+
+// Manipulate expr to append a '-1'. Used specifically for DO.
+void append_minus_1(TOKEN * expr)
+{
+       // Find where the end of expression is
+       while (*expr != ENDEXPR)
+       {
+               if (*expr == SYMBOL || *expr == CONST || *expr == FCONST)
+                       expr++;
+               else if (*expr == ACONST)
+                       expr += 3;
+
+               expr++;
+       }
+
+       // Overwrite ENDEXPR and append '-1'
+       *expr++ = CONST;
+       uint64_t *expr64 = (uint64_t *)expr;
+       *expr64++ = 1;
+       expr = (uint32_t *)expr64;
+       *expr++ = '-';
+       *expr = ENDEXPR;
+}
+
+
+// Store a 12bit immediate and 16bit address.
+// Note: This function is specifically handling DO. DO has a requirement of
+//       storing the address of a label minus 1! Quoting the manual:
+//       "Note: The assembler calculates the end-of-loop address to be loaded
+//        into LA (the absolute address extension word) by evaluating the end
+//        -of-loop expression <expr> and subtracting one. This is done to
+//        accommodate the case where the last word in the DO loop is a two-word
+//        instruction. Thus, the end-of-loop expression <expr> in the source
+//        code must represent the address of the instruction AFTER the last
+//        instruction in the loop as shown in the example."
+//       This is fine if we know the address already, but a problem when we
+//       don't.
+int dsp_imm12_abs16(LONG inst)
+{
+       if (dsp_a0exattr & DEFINED)
+       {
+               if ((dsp_am0 & (M_DSPIM12 | M_DSPIM8)) == 0)
+                       return error("immediate out of range ($000-$FFF)");
+
+               inst |= ((dsp_a0exval & 0x0FF) << 8) | ((dsp_a0exval & 0xF00) >> 8);
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPIMM12, sloc, dsp_a0expr);
+               D_dsp(inst);
+       }
+
+       if (dsp_a1exattr & DEFINED)
+       {
+               D_dsp((a1exval - 1));
+       }
+       else
+       {
+               append_minus_1(dsp_a1expr);
+               AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
+               D_dsp(0);
+       }
+
+       return OK;
+}
+
+
+// Just store ea and 16bit address
+// Note: this function is specifically handling DO.
+// The same notes as dsp_imm12_abs16 apply here.
+int dsp_ea_abs16(LONG inst)
+{
+       if ((dsp_a0reg == DSP_EA_ABS && dsp_a0memspace == -1) || dsp_a1reg == DSP_EA_IMM)
+               return error("immediate values > 31 or absolute values not allowed");
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               if (dsp_a0exval > 31)
+                       return error("absolute address (aa) bigger than $1F");
+
+               inst |= dsp_a0exval << 8;
+       }
+
+       inst |= dsp_a0reg << 8;
+
+       if (dsp_a0memspace == -1)
+               return error("only X:, Y: address spaces allowed");
+
+       if ((deposit_extra_ea == DEPOSIT_EXTRA_FIXUP) || (dsp_a0reg == DSP_EA_ABS && dsp_am0 == M_DSPEA))
+       {
+               // Change instruction to aa instead of ea. TODO: check if this is true
+               // for all cases
+               inst = 0x060000;
+               inst |= dsp_a0memspace;
+
+               // Probably superfluous check (we're not likely to land here with a
+               // known aa) but oh well
+               if (!(dsp_a0exattr & DEFINED))
+               {
+                       AddFixup(FU_DSPADR06, sloc, dsp_a0expr);
+                       D_dsp(inst);
+               }
+               else
+               {
+                       D_dsp(inst);
+               }
+       }
+       else
+       {
+               inst |= dsp_a0memspace;
+               D_dsp(inst);
+       }
+
+       if (dsp_a1exattr & DEFINED)
+       {
+               D_dsp((dsp_a1exval - 1));
+       }
+       else
+       {
+               append_minus_1(dsp_a1expr);
+               AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
+               D_dsp(0);
+       }
+
+       return OK;
+}
+
+
+// Store register (table A-18 in the motorola manual) 5-bit constant and 16bit address
+// Note: this function is specifically handling DO.
+// The same notes as dsp_imm12_abs16 apply here.
+int dsp_reg_abs16(LONG inst)
+{
+       LONG reg;
+
+       if ((reg = tab_A18(&dsp_am0, &dsp_a0reg)) == ERROR)
+               return ERROR;
+
+       inst |= reg << 8;
+
+       if (dsp_a1exattr & DEFINED)
+       {
+               int v = (int)dsp_a1exval - 1;
+               D_dsp(inst);
+               D_dsp(v);
+       }
+       else
+       {
+               D_dsp(inst);
+               append_minus_1(dsp_a1expr);
+               AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
+               D_dsp(0);
+       }
+
+       return OK;
+}
+
+
+// Store ALU24 register and 16bit address
+// Note: this function is specifically handling DO.
+// The same notes as dsp_imm12_abs16 apply here.
+int dsp_alu24_abs16(LONG inst)
+{
+       inst |= (dsp_a0reg & 7) << 8;
+
+       if (dsp_a1exattr & DEFINED)
+       {
+               int v = (int)dsp_a1exval - 1;
+               D_dsp(inst);
+               D_dsp(v);
+       }
+       else
+       {
+               D_dsp(inst);
+               append_minus_1(dsp_a1expr);
+               AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
+               D_dsp(0);
+       }
+
+       return OK;
+}
+
+
+// Store register (table A-18 in the motorola manual)
+int dsp_reg(LONG inst)
+{
+       LONG reg;
+
+       if ((reg = tab_A18(&dsp_am0, &dsp_a0reg)) == ERROR)
+               return ERROR;
+
+       inst |= reg << 8;
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+int dsp_alu24(LONG inst)
+{
+       inst |= (dsp_a0reg & 7) << 8;
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+// Store register (table A-18 in the motorola manual) and 5-bit constant
+int dsp_reg_imm5_abs16(LONG inst)
+{
+       LONG reg;
+
+       // First, check that we have at best an 16bit absolute address in
+       // operand 3 since we don't check that anywhere else
+       if (dsp_a2exattr & DEFINED)
+       {
+               if ((dsp_am2 & C_DSPABS16) == 0)
+                       return error("expected 16-bit address as third operand.");
+       }
+
+       if ((reg = tab_A18(&dsp_am1, &dsp_a1reg)) == ERROR)
+               return ERROR;
+
+       inst |= reg << 8;
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               int v = (int)dsp_a0exval;
+
+               if (v < 0 || v > 23)
+                       return error("immediate value must be between 0 and 23");
+
+               inst |= v;
+               D_dsp(inst);
+
+               if (dsp_a2exattr & DEFINED)
+               {
+                       int v = (int)dsp_a2exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
+                       D_dsp(0);
+               }
+       }
+       else
+       {
+               AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
+               D_dsp(inst);
+
+               if (dsp_a2exattr & DEFINED)
+               {
+                       int v = (int)dsp_a2exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
+                       D_dsp(0);
+               }
+       }
+
+       return OK;
+}
+
+
+// Store ea, 5-bit constant and 16-bit address in the extension word
+int dsp_ea_imm5_abs16(LONG inst)
+{
+       // First, check that we have at best an 16bit absolute address in
+       // operand 3 since we don't check that anywhere else
+       if (dsp_a2exattr&DEFINED)
+       {
+               if ((dsp_am2&C_DSPABS16) == 0)
+                       return error("expected 16-bit address as third operand.");
+       }
+
+       if (dsp_a1memspace == -1)
+               return error("Only X: or Y: memory space allowed");
+
+       if (dsp_am1 == M_DSPAA)
+       {
+               if (dsp_a1exattr & DEFINED)
+                       inst |= (dsp_a1exval & 0x3F) << 8;
+               else
+                       AddFixup(FU_DSPADR06, sloc, dsp_a1expr);
+       }
+
+       if (dsp_am1 == M_DSPPP)
+       {
+               if (dsp_a1exattr & DEFINED)
+                       inst |= (dsp_a1exval & 0x3f) << 8;
+               else
+                       AddFixup(FU_DSPPP06, sloc, dsp_a1expr);
+       }
+
+       if (dsp_a0exattr & DEFINED)
+       {
+               int v = (int)dsp_a0exval;
+
+               if (v < 0 || v > 23)
+                       return error("immediate value must be between 0 and 23");
+
+               inst |= (dsp_a1reg << 8) | v | dsp_a1memspace;
+               D_dsp(inst);
+
+               if (dsp_a2exattr & DEFINED)
+               {
+                       int v = (int)dsp_a2exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
+                       D_dsp(0);
+               }
+       }
+       else
+       {
+               inst |= (dsp_a1reg << 8) | dsp_a1memspace;
+               AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
+               D_dsp(inst);
+
+               if (dsp_a2exattr & DEFINED)
+               {
+                       int v = (int)dsp_a2exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
+                       D_dsp(0);
+               }
+       }
+
+       return OK;
+}
+
+
+int dsp_ea_lua(LONG inst)
+{
+       int am = dsp_a0reg & 0x38;
+
+       if (am != DSP_EA_POSTDEC && am != DSP_EA_POSTINC &&
+               am != DSP_EA_POSTDEC1 && am != DSP_EA_POSTINC1)
+               return error("addressing mode not allowed");
+
+       inst |= dsp_a0reg << 8;
+
+       if (dsp_am1 == M_DSPN)
+               inst |= 1 << 3;
+
+       inst |= dsp_a1reg;
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+int dsp_ab_rn(LONG inst)
+{
+       inst |= (dsp_a1reg & 1) << 3;
+       inst |= (dsp_a0reg) << 8;
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+int dsp_movec_ea(LONG inst)
+{
+       int ea = dsp_a1reg;
+       int memspace = dsp_a1memspace;
+       WORD exattr = dsp_a1exattr;
+       LONG exval = (uint32_t)dsp_a1exval;
+       TOKEN * expr = dsp_a1expr;
+       int reg = dsp_a0reg;
+       int am = dsp_am0;
+       int reg2 = dsp_a1reg;
+
+       if (dsp_am0 == M_DSPEA || (dsp_am0 & C_DSPIM))
+       {
+               ea = dsp_a0reg;
+               exattr = dsp_a0exattr;
+               exval = (uint32_t)dsp_a0exval;
+               memspace = dsp_a0memspace;
+               expr = dsp_a0expr;
+               reg = dsp_a1reg;
+               reg2 = dsp_a0reg;
+               am = dsp_am1;
+       }
+
+       // Abort if unsupported registers are requested
+       if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
+               return error("illegal registers for instruction.");
+
+       if (dsp_am0 & C_DSPIM)
+               memspace = 0;
+
+       if (memspace == -1)
+               return error("only x: or y: memory spaces allowed.");
+
+       // No memspace required when loading an immediate
+       if (dsp_am0 & C_DSPIM)
+               memspace = 0;
+
+       reg = tab_A18(&am, &reg);
+       inst |= (ea << 8) | memspace | reg;
+
+       if (am == M_DSPPCU)
+               inst |= 3 << 3;
+
+       D_dsp(inst);
+
+       if (reg2 == DSP_EA_ABS || (dsp_am0 & C_DSPIM))
+       {
+               if (exattr & DEFINED)
+               {
+                       int v = exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       if (dsp_am0 == M_DSPIM)
+                       {
+                               AddFixup(FU_DSPIMM24, sloc, expr);
+                               D_dsp(0);
+                       }
+                       else
+                       {
+                               AddFixup(FU_DSPADR24, sloc, expr);
+                               D_dsp(0);
+                       }
+               }
+       }
+
+       return OK;
+}
+
+
+int dsp_movec_aa(LONG inst)
+{
+       int ea = dsp_a1reg;
+       int memspace = dsp_a1memspace;
+       WORD exattr = dsp_a1exattr;
+       LONG exval = (uint32_t)dsp_a1exval;
+       TOKEN * expr = dsp_a1expr;
+       int reg = dsp_a0reg;
+       int am = dsp_am0;
+       int reg2 = dsp_a1reg;
+
+       if (dsp_am0 == M_DSPAA)
+       {
+               ea = dsp_a0reg;
+               exattr = dsp_a0exattr;
+               exval = (uint32_t)dsp_a0exval;
+               memspace = dsp_a0memspace;
+               expr = dsp_a0expr;
+               reg = dsp_a1reg;
+               reg2 = dsp_a0reg;
+               am = dsp_am1;
+       }
+
+       // Abort if unsupported registers are requested
+       if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
+               return error("PC, MR, CCR are illegal registers for this instruction.");
+
+       if (memspace == -1)
+               return error("only x: or y: memory spaces allowed.");
+
+       reg = tab_A18(&am, &reg);
+       inst |= (ea << 8) | memspace | reg;
+
+       if (am == M_DSPPCU)
+               inst |= 3 << 3;
+
+       if (exattr & DEFINED)
+       {
+               inst |= exval << 8;
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPADR06, sloc, expr);
+               D_dsp(inst);
+       }
+
+       return OK;
+}
+
+
+int dsp_movec_reg(LONG inst)
+{
+       int am0 = dsp_am0;
+       int am1 = dsp_am1;
+
+       // Abort if unsupported registers are requested
+       if (dsp_a0reg == KW_PC || dsp_a0reg == KW_MR || dsp_a0reg == KW_CCR ||
+               dsp_a1reg == KW_PC || dsp_a1reg == KW_MR || dsp_a1reg == KW_CCR)
+               return error("PC, MR, CCR are illegal registers for this instruction.");
+
+       int reg1 = tab_A18(&dsp_am0, &dsp_a0reg);
+       int reg2 = tab_A18(&dsp_am1, &dsp_a1reg);
+
+       if (inst & (1 << 15))
+       {
+               // S1,D2
+       }
+       else
+       {
+               // S2,D1
+               int temp = am0;
+               am0 = am1;
+               am1 = temp;
+               temp = reg1;
+               reg1 = reg2;
+               reg2 = temp;
+       }
+
+       switch (am0)
+       {
+       case M_ALU24:  reg1 |= 0x00; break;
+       case M_ACC8:
+       case M_ACC24:  reg1 |= 0x08; break;
+       case M_ACC56:  reg1 |= 0x0E; break;
+       case M_DSPR:   reg1 |= 0x10; break;
+       case M_DSPN:   reg1 |= 0x18; break;
+       case M_DSPM:   reg1 |= 0x20; break;
+       case M_DSPPCU: reg1 |= 0x38; break;
+       default:
+               return error("reached the end of dsp_movec_reg case 1 - should not happen!");
+       }
+
+       switch (am1)
+       {
+       case M_DSPM:   reg2 |= 0x00; break;
+       case M_DSPPCU: reg2 |= 0x18; break;
+       default:
+               return error("reached the end of dsp_movec_reg case 2 - should not happen!");
+       }
+
+       inst |= (reg1 << 8) | reg2;
+       D_dsp(inst);
+
+       return OK;
+}
+
+
+int dsp_mult(LONG inst)
+{
+       if (dsp_am2 != M_ACC56)
+               return error("only A or B allowed as third operand.");
+
+       switch (((dsp_a0reg & 3) << 2) + (dsp_a1reg & 3))
+       {
+       case (0 << 2) + 0: inst |= 0 << 4; break; // x0 x0
+       case (2 << 2) + 2: inst |= 1 << 4; break; // y0 y0
+       case (1 << 2) + 0: inst |= 2 << 4; break; // x1 x0
+       case (0 << 2) + 1: inst |= 2 << 4; break; // x0 x1
+       case (3 << 2) + 2: inst |= 3 << 4; break; // y1 y0
+       case (2 << 2) + 3: inst |= 3 << 4; break; // y0 y1
+       case (0 << 2) + 3: inst |= 4 << 4; break; // x0 y1
+       case (3 << 2) + 0: inst |= 4 << 4; break; // y1 x0
+       case (2 << 2) + 0: inst |= 5 << 4; break; // y0 x0
+       case (0 << 2) + 2: inst |= 5 << 4; break; // x0 y0
+       case (1 << 2) + 2: inst |= 6 << 4; break; // x1 y0
+       case (2 << 2) + 1: inst |= 6 << 4; break; // y0 x1
+       case (3 << 2) + 1: inst |= 7 << 4; break; // y1 x1
+       case (1 << 2) + 3: inst |= 7 << 4; break; // x1 y1
+       default:
+               return error("x0/y0/x1/y1 combination not allowed for multiplication.");
+       }
+
+       if (dsp_a2reg == KW_B)
+               inst |= 1 << 3;
+
+       inst |= dsp_k;
+       D_dsp(inst);
+       dsp_extra_ea();         // Deposit effective address if needed
+
+       return OK;
+}
+
+
+int dsp_movem_ea(LONG inst)
+{
+       int ea = dsp_a1reg;
+       int memspace = dsp_a0memspace;
+       WORD exattr = dsp_a1exattr;
+       LONG exval = (uint32_t)dsp_a1exval;
+       TOKEN * expr = dsp_a1expr;
+       int reg = dsp_a0reg;
+       int am = dsp_am0;
+       int reg2 = dsp_a1reg;
+
+       if (dsp_am0 == M_DSPEA || dsp_am0 == M_DSPIM)
+       {
+               ea = dsp_a0reg;
+               exattr = dsp_a0exattr;
+               exval = (uint32_t)dsp_a0exval;
+               memspace = dsp_a0memspace;
+               expr = dsp_a0expr;
+               reg = dsp_a1reg;
+               reg2 = dsp_a0reg;
+               am = dsp_am1;
+               inst |= 1 << 15;
+       }
+
+       // Abort if unsupported registers are requested
+       if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
+               return error("illegal registers for instruction.");
+
+       if (memspace != -1)
+               return error("only p: memory space allowed.");
+
+       reg = tab_A18(&am, &reg);
+       inst |= (ea << 8) | reg;
+
+       if (am == M_DSPPCU)
+               inst |= 3 << 3;
+
+       D_dsp(inst);
+
+       if (reg2 == DSP_EA_ABS || dsp_am0 == M_DSPIM)
+       {
+               if (exattr & DEFINED)
+               {
+                       int v = exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       if (dsp_am0 == M_DSPIM)
+                       {
+                               AddFixup(FU_DSPIMM24, sloc, expr);
+                               D_dsp(0);
+                       }
+                       else
+                       {
+                               AddFixup(FU_DSPADR24, sloc, expr);
+                               D_dsp(0);
+                       }
+               }
+       }
+
+       return OK;
+}
+
+
+int dsp_movem_aa(LONG inst)
+{
+       int ea = dsp_a1reg;
+       int memspace = dsp_a1memspace;
+       WORD exattr = dsp_a1exattr;
+       LONG exval = (uint32_t)dsp_a1exval;
+       TOKEN * expr = dsp_a1expr;
+       int reg = dsp_a0reg;
+       int am = dsp_am0;
+       int reg2 = dsp_a1reg;
+
+       if (dsp_am0 == M_DSPAA)
+       {
+               ea = dsp_a0reg;
+               exattr = dsp_a0exattr;
+               exval = (uint32_t)dsp_a0exval;
+               memspace = dsp_a0memspace;
+               expr = dsp_a0expr;
+               reg = dsp_a1reg;
+               reg2 = dsp_a0reg;
+               am = dsp_am1;
+       }
+
+       // Abort if unsupported registers are requested
+       if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
+               return error("PC, MR, CCR are illegal registers for this instruction.");
+
+       if (memspace != -1)
+               return error("only p: memory space allowed.");
+
+       reg = tab_A18(&am, &reg);
+       inst |= (ea << 8) | reg;
+
+       if (am == M_DSPPCU)
+               inst |= 3 << 3;
+
+       if (exattr & DEFINED)
+       {
+               inst |= exval << 8;
+               D_dsp(inst);
+       }
+       else
+       {
+               AddFixup(FU_DSPADR06, sloc, expr);
+               D_dsp(inst);
+       }
+
+    return OK;
+}
+
+
+int dsp_movep_ea(LONG inst)
+{
+       // movep doesn't allow any aa modes but we might detect this during amode
+       // detection. No worries, just change it to ea with extra address instead
+       if (dsp_am0 == M_DSPAA)
+       {
+               dsp_a0reg = DSP_EA_ABS;
+               dsp_a1reg = 0;
+       }
+       if (dsp_am1 == M_DSPAA)
+       {
+               dsp_a0reg = 0;
+               dsp_a1reg = DSP_EA_ABS;
+       }
+
+       // So we might encounter something like 'movep x:pp,x:pp' which we
+       // obviously flagged as M_DSPPP during ea parsing. In this case we give up
+       // and declare the second term as a classic absolute address (we chop off
+       // the high bits too) and let the routine treat is as such. At least that's
+       // what Motorola's assembler seems to be doing.
+       if (dsp_am0 == M_DSPPP && dsp_am1 == M_DSPPP)
+       {
+               dsp_am1 = DSP_EA_ABS;
+               dsp_a1reg = DSP_EA_ABS;
+               dsp_a1exval &= 0xFFFF;
+       }
+
+       // Assume first operand is :pp
+       int ea = dsp_a1reg;
+       int memspace = dsp_a1memspace;
+       int perspace = dsp_a0perspace;
+       WORD exattr = dsp_a1exattr;
+       WORD exattr2 = dsp_a0exattr;
+       LONG exval = (uint32_t)dsp_a1exval;
+       LONG exval2 = (uint32_t)dsp_a0exval;
+       TOKEN * expr = dsp_a1expr;
+       TOKEN * expr2 = dsp_a0expr;
+       int reg = dsp_a0reg;
+       int am = dsp_am0;
+       int reg2 = dsp_a1reg;
+
+       if (dsp_am1 == M_DSPPP)
+       {
+               ea = dsp_a0reg;
+               exattr = dsp_a0exattr;
+               exattr2 = dsp_a1exattr;
+               exval = (uint32_t)dsp_a0exval;
+               exval2 = (uint32_t)dsp_a1exval;
+               memspace = dsp_a0memspace;
+               perspace = dsp_a1perspace;
+               expr = dsp_a0expr;
+               expr2 = dsp_a1expr;
+               reg = dsp_a1reg;
+               reg2 = dsp_a0reg;
+               am = dsp_am1;
+       }
+
+       if (dsp_a0perspace == -1 && dsp_a1perspace == -1)
+       {
+               // Ok, so now we have to guess which of the two parameters is X:pp or
+               // Y:pp. This happened because we didn't get a << marker in any of the
+               // addressing modes
+               if (((dsp_a0exattr | dsp_a1exattr) & DEFINED) == 0)
+                       // You have got to be shitting me...
+                       // One way to deal with this (for example X:ea,X:pp / X:pp,X:ea
+                       // aliasing would be to check number ranges and see which one is
+                       // negative. ...unless one of the two isn't known during this phase
+                       return error("internal assembler error: could not deduce movep syntax");
+
+               if (dsp_a0exattr & DEFINED)
+               {
+                       if (dsp_a0exval >= 0xFFC0 && dsp_a0exval <= 0xFFFF)
+                       {
+                               // First operand is :pp - do nothing
+                               perspace = dsp_a0memspace << 10;
+                               // When the source contains a << then we bolt on the :pp
+                               // address during ea parsing, but since we couldn't recognise
+                               // the addressing mode in this case let's just insert it right
+                               // now...
+                               reg |= (dsp_a0exval & 0x3F);
+                       }
+               }
+
+               if (dsp_a1exattr & DEFINED)
+               {
+                       if (dsp_a1exval >= 0xFFC0 && dsp_a1exval <= 0xFFFF)
+                       {
+                               ea = dsp_a0reg;
+                               exattr = dsp_a0exattr;
+                               exval = (uint32_t)dsp_a0exval;
+                               memspace = dsp_a0memspace;
+                               perspace = dsp_a1memspace << 10;
+                               expr = dsp_a0expr;
+                               reg = dsp_a0reg;
+                               reg2 = dsp_a1reg;
+                               am = dsp_am1;
+                               // See above
+                               reg |= (dsp_a1exval & 0x3F);
+                       }
+               }
+
+               if (perspace == -1)
+                       // You have got to be shitting me (twice)...
+                       return error("internal assembler error: could not deduce movep syntax");
+       }
+
+       inst |= reg | (ea << 8) | perspace;       // reg contains memory space
+
+       if ((dsp_am0 & (M_DSPIM | M_DSPIM8 | M_DSPIM12)) == 0)
+       {
+               if (memspace == -1)
+               {
+                       inst &= ~(1 << 7);
+                       inst |= 1 << 6;
+               }
+               else
+                       inst |= memspace;
+       }
+
+       if (am == M_DSPPP)
+       {
+               if (exattr2&DEFINED)
+               {
+                       inst |= (exval2 & 0x3F);
+                       D_dsp(inst);
+               }
+               else
+               {
+                       AddFixup(FU_DSPIMM5, sloc, expr2);
+                       D_dsp(inst);
+               }
+       }
+       else
+       {
+               D_dsp(inst);
+       }
+
+       if (dsp_am0 & (M_DSPIM | M_DSPIM8 | M_DSPIM12))
+       {
+               if (dsp_a0exattr & DEFINED)
+               {
+                       int v = (int)dsp_a0exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR16, sloc, dsp_a0expr);
+                       D_dsp(0);
+               }
+       }
+       else if (reg2 == DSP_EA_ABS)
+       {
+               if (exattr & DEFINED)
+               {
+                       int v = exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR24, sloc, expr);
+                       D_dsp(0);
+               }
+       }
+
+       return OK;
+}
+
+
+int dsp_movep_reg(LONG inst)
+{
+       // Assume first operand is :pp
+       int ea = dsp_a0reg;
+       int memspace = dsp_a0memspace;
+       int perspace = dsp_a0perspace;
+       WORD exattr = dsp_a1exattr;
+       LONG exval = (uint32_t)dsp_a1exval;
+       TOKEN * expr = dsp_a1expr;
+       int reg = dsp_a0reg;
+       int am = dsp_am1;
+       int reg2 = dsp_a1reg;
+
+       if (dsp_am1 == M_DSPPP)
+       {
+               ea = dsp_a1reg;
+               exattr = dsp_a0exattr;
+               exval = (uint32_t)dsp_a0exval;
+               memspace = dsp_a1memspace;
+               perspace = dsp_a1perspace;
+               expr = dsp_a0expr;
+               reg = dsp_a1reg;
+               reg2 = dsp_a0reg;
+               am = dsp_am0;
+       }
+
+       // Abort if unsupported registers are requested
+       if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
+               return error("illegal registers for instruction.");
+
+       reg2 = tab_A18(&am, &reg2);
+       inst |= (reg2 << 8) | reg;
+
+       if (perspace == -1)
+               return error("only x: or y: memory space allowed.");
+       else
+               inst |= perspace;
+
+       D_dsp(inst);
+
+       if (reg2 == DSP_EA_ABS)
+       {
+               if (exattr & DEFINED)
+               {
+                       int v = exval;
+                       D_dsp(v);
+               }
+               else
+               {
+                       AddFixup(FU_DSPADR24, sloc, expr);
+                       D_dsp(0);
+               }
+       }
+
+       return OK;
+}
+
diff --git a/dsp56k_mach.h b/dsp56k_mach.h
new file mode 100644 (file)
index 0000000..593ff9a
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DSP56L_MACH.C - Code Generation for Motorola DSP56001
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source utilised with the kind permission of Landon Dyer
+//
+
+#ifndef __DSP56KMACH_H__
+#define __DSP56KMACH_H__
+
+#include "rmac.h"
+#include "dsp56k_amode.h"
+
+// Exported variables
+extern MNTABDSP dsp56k_machtab[];
+extern unsigned int dsp_orgaddr;
+extern unsigned int dsp_orgseg;
+
+// Exported functions
+extern int dsp_mult(LONG inst);
+
+#endif // __DSP56KMACH_H__
+
diff --git a/dsp56kgen.c b/dsp56kgen.c
new file mode 100644 (file)
index 0000000..3f263ad
--- /dev/null
@@ -0,0 +1,134 @@
+//
+// RMAC - Reboot's Macro Assembler for all Atari computers
+// 68KGEN.C - Tool to Generate 68000 Opcode Table
+// 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 <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+
+#define        EOS     '\0'
+
+int kwnum = 1;                 /* current op# for kwgen output */
+FILE * kfp;                            /* keyword file */
+int lineno = 0;
+
+// Function prototypes
+void error(char *, char *);
+void procln(int, char **);
+
+
+int main(int argc, char ** argv)
+{
+       char * namv[256];
+       char * s;
+       int namcnt;
+       char ln[256];
+
+       if ((argc == 2) && ((kfp = fopen(argv[1], "w")) == NULL))
+               error("Cannot create: %s", argv[1]);
+
+       while (fgets(ln, 256, stdin) != NULL)
+       {
+               lineno++;                       /* bump line# */
+
+               if (*ln == '#')         /* ignore comments */
+                       continue;
+
+               /*
+                *  Tokenize line (like the way "argc, argv" works)
+                *  and pass it to the parser.
+                */
+               namcnt = 0;
+               s = ln;
+
+               while (*s)
+               {
+                       if (isspace(*s))
+                               ++s;
+                       else
+                       {
+                               namv[namcnt++] = s;
+
+                               while (*s && !isspace(*s))
+                                       s++;
+
+                               if (isspace(*s))
+                                       *s++ = EOS;
+                       }
+               }
+
+               if (namcnt)
+                       procln(namcnt, namv);
+       }
+
+       return 0;
+}
+
+
+//
+// Parse line
+//
+void procln(int namc, char ** namv)
+{
+       int i, j;
+
+       // alias for previous entry
+       if (namc == 1)
+       {
+               fprintf(kfp, "%s\t%d\n", namv[0], kwnum - 1 + 2000);
+               return;
+       }
+
+       if (namc < 5)
+       {
+               fprintf(stderr, "%d: missing fields\n", lineno);
+               exit(1);
+       }
+
+       // output keyword name
+       if (*namv[0] != '-')
+               fprintf(kfp, "%s\t%d\n", namv[0], kwnum + 2000);
+
+       printf("/*%4d %-6s*/  {", kwnum, namv[0]);
+
+       printf("%s, %s, %s, ", namv[1], namv[2], namv[3]);
+
+       // enforce little fascist percent signs
+       if (*namv[4] == '%')
+       {
+               for(i=1, j=0; i<25; i++)
+               {
+                       j <<= 1;
+
+                       if (namv[4][i] == '1' || isupper(namv[4][i]))
+                               j++;
+               }
+
+               printf("0x%06x, ", j);
+       }
+       else
+               printf("%s, ", namv[4]);
+
+       if (namc >= 7 && *namv[6] == '+')
+               printf("%d, ", kwnum + 1);
+       else
+               printf("0, ");
+
+       printf("%s},\n", namv[5]);
+
+       kwnum++;
+}
+
+
+void error(char * s, char * s1)
+{
+       fprintf(stderr, s, s1);
+       fprintf(stderr, "\n");
+       exit(1);
+}
+
diff --git a/expr.c b/expr.c
index 4318aa7d6b98f871e9a93ea5e72d2bfebf7c7d52..6db7435dd205546e0afc4d25c3e018fcb1077301 100644 (file)
--- a/expr.c
+++ b/expr.c
@@ -36,7 +36,7 @@ char itokcl[] = {
        CR_STREQ, CR_MACDEF,
        CR_DATE, CR_TIME,
        CR_ABSCOUNT, 0,
-       '!', '~', UNMINUS, 0,                   // UNARY
+       '!', '~', UNMINUS, UNLT, UNGT, 0,       // UNARY
        '*', '/', '%', 0,                               // MULT
        '+', '-', 0,                                    // ADD
        SHL, SHR, 0,                                    // SHIFT
@@ -49,6 +49,7 @@ char itokcl[] = {
 
 const char missym_error[] = "missing symbol";
 const char str_error[] = "missing symbol or string";
+const char noflt_error[] = "operator not usable with float";
 
 // Convert expression to postfix
 static PTR evalTokenBuffer;            // Deposit tokens here (this is really a
@@ -125,23 +126,24 @@ int expr0(void)
 //
 int expr1(void)
 {
-       TOKEN t;
-       SYM * sy;
-       char * p, * p2;
+       char * p;
        WORD w;
-       int j;
 
        int class = tokenClass[*tok];
 
-       if (*tok == '-' || *tok == '+' || class == UNARY)
+       if (*tok == '-' || *tok == '+' || *tok == '<' || *tok == '>' || class == UNARY)
        {
-               t = *tok++;
+               TOKEN t = *tok++;
 
                if (expr2() != OK)
                        return ERROR;
 
                if (t == '-')
                        t = UNMINUS;
+               else if (t == '<')
+                       t = UNLT;
+               else if (t == '>')
+                       t = UNGT;
 
                // With leading + we don't have to deposit anything to the buffer
                // because there's no unary '+' nor we have to do anything about it
@@ -183,8 +185,9 @@ getsym:
                                return error(missym_error);
 
                        p = string[*tok++];
-                       j = (*p == '.' ? curenv : 0);
-                       w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
+                       int j = (*p == '.' ? curenv : 0);
+                       SYM * sy = lookup(p, LABEL, j);
+                       w = ((sy != NULL) && (sy->sattr & w ? 1 : 0));
                        *evalTokenBuffer.u32++ = CONST;
                        *evalTokenBuffer.u64++ = (uint64_t)w;
                        break;
@@ -201,7 +204,7 @@ getsym:
                        if (*tok != SYMBOL && *tok != STRING)
                                return error(str_error);
 
-                       p2 = string[tok[1]];
+                       char * p2 = string[tok[1]];
                        tok += 2;
 
                        w = (WORD)(!strcmp(p, p2));
@@ -222,9 +225,6 @@ getsym:
 //
 int expr2(void)
 {
-       char * p;
-       SYM * sy;
-       int j;
        PTR ptk;
 
        switch (*tok++)
@@ -242,9 +242,10 @@ int expr2(void)
                tok = ptk.u32;
                break;
        case SYMBOL:
-               p = string[*tok++];
-               j = (*p == '.' ? curenv : 0);
-               sy = lookup(p, LABEL, j);
+       {
+               char * p = string[*tok++];
+               int j = (*p == '.' ? curenv : 0);
+               SYM * sy = lookup(p, LABEL, j);
 
                if (sy == NULL)
                        sy = NewSymbol(p, LABEL, j);
@@ -264,6 +265,7 @@ int expr2(void)
                symbolPtr[symbolNum] = sy;
                symbolNum++;
                break;
+       }
        case STRING:
                *evalTokenBuffer.u32++ = CONST;
                *evalTokenBuffer.u64++ = str_value(string[*tok++]);
@@ -494,10 +496,15 @@ thrown away right here. What the hell is it for?
 
                        tok += 2;
                }
+               // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
+               else if (m6502)
+               {
+                       *evalTokenBuffer.u32++ = *tok++;
+               }
                else
                {
                        // Unknown type here... Alert the user!,
-                       error("undefined RISC register in expression");
+                       error("undefined RISC register in expression [token=$%X]", *tok);
                        // Prevent spurious error reporting...
                        tok++;
                        return ERROR;
@@ -691,6 +698,30 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
 
                        break;
 
+               case UNLT: // Unary < (get the low byte of a word)
+//printf("evexpr(): UNLT\n");
+                       if (*sattr & TDB)
+                               return error(seg_error);
+
+                       if (*sattr & FLOAT)
+                               return error(noflt_error);
+
+                       *sval = (int64_t)((*sval) & 0x00FF);
+                       *sattr = ABS | DEFINED;                 // Expr becomes absolute
+                       break;
+
+               case UNGT: // Unary > (get the high byte of a word)
+//printf("evexpr(): UNGT\n");
+                       if (*sattr & TDB)
+                               return error(seg_error);
+
+                       if (*sattr & FLOAT)
+                               return error(noflt_error);
+
+                       *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
+                       *sattr = ABS | DEFINED;                 // Expr becomes absolute
+                       break;
+
                case '!':
 //printf("evexpr(): !\n");
                        if (*sattr & TDB)
diff --git a/kwtab b/kw.tab
similarity index 73%
rename from kwtab
rename to kw.tab
index 249eb47b133219414a37eb91d354655b05dc5fa2..cde93378f5117d2ab440f06e97a8f172441252ab 100644 (file)
--- a/kwtab
+++ b/kw.tab
@@ -68,13 +68,6 @@ fp4     228
 fp5     229
 fp6     230
 fp7     231
-mr 272
-omr 273
-la 274
-lc 275
-ssh 276
-ssl 277
-ss 278
 
 .equ   61
 equ    61
@@ -128,4 +121,46 @@ time  120
 date  121
 abscount  122
 
+x0    260
+x1    261
+y0    262
+y1    263
+b0    265
+b2    267
+b1    269
+a     270
+b     271
+n0    280
+n1    281
+n2    282
+n3    283
+n4    284
+n5    285
+n6    286
+n7    287
+m0    288
+m1    289
+m2    290
+m3    291
+m4    292
+m5    293
+m6    294
+m7    295
 
+mr  304
+omr 305
+la  306
+lc  307
+ssh 308
+ssl 309
+ss  310
+
+l   302
+p   303
+
+a10 312
+b10 313
+x   314
+y   315
+ab  318
+ba  319
index a1ffcc84c3edd159c4cb97d7364d0f4f8dac728b..b69348fb22ec9225d983ce579e53f70265202669 100644 (file)
--- a/makefile
+++ b/makefile
@@ -1,6 +1,6 @@
 #
-# RMAC - Reboot's Macro Assembler for the Atari Jaguar
-# Copyright (C) 199x Landon Dyer, 2011 Reboot & Friends
+# RMAC - Reboot's Macro Assembler for all Atari computers
+# Copyright (C) 199x Landon Dyer, 2011-2018 Reboot & Friends
 # MAKEFILE for *nix
 #
 
@@ -20,22 +20,21 @@ STD := gnu99
 endif
 
 
-rm = /bin/rm -f
+RM = /bin/rm -f
 CC = $(CROSS)gcc
 HOSTCC = gcc
 
 #CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2 -MMD
 CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2
 
-SRCS = 6502.c amode.c debug.c direct.c eagen.c error.c expr.c fltpoint.c listing.c mach.c macro.c mark.c object.c op.c procln.c riscasm.c rmac.c sect.c symbol.c token.c
-
-OBJS = 6502.o amode.o debug.o direct.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o op.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
+OBJS = 6502.o amode.o debug.o direct.o dsp56k.o dsp56k_amode.o dsp56k_mach.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o op.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
 
 #
 # Build everything
 #
 
-all : mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h rmac
+#all: mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h dsp56ktab.h rmac
+all: rmac
        @echo
        @echo "Don't forget to bump the version number before commiting!"
        @echo
@@ -45,106 +44,48 @@ all : mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h rmac
 # definitions
 #
 
-mntab.h : mntab 68kmn kwgen
-       cat mntab 68kmn | ./kwgen mn >mntab.h
+68ktab.h 68k.tab: 68k.mch 68kgen
+       ./68kgen 68k.tab <68k.mch >68ktab.h
+
+dsp56ktab.h dsp56k.tab: dsp56k.mch dsp56kgen
+       ./dsp56kgen dsp56k.tab <dsp56k.mch >dsp56ktab.h
 
-68ktab.h 68kmn : 68ktab 68ktab 68kgen
-       ./68kgen 68kmn <68ktab >68ktab.h
 
+mntab.h: direct.tab 68k.tab kwgen
+       cat direct.tab 68k.tab | ./kwgen mn >mntab.h
 
-kwtab.h : kwtab kwgen
-       ./kwgen kw <kwtab >kwtab.h
+kwtab.h: kw.tab kwgen
+       ./kwgen kw <kw.tab >kwtab.h
 
-6502kw.h : 6502.tbl kwgen
-       ./kwgen mp <6502.tbl >6502kw.h
+6502kw.h: 6502.tab kwgen
+       ./kwgen mp <6502.tab >6502kw.h
 
-risckw.h : kwtab kwgen
-       ./kwgen mr <risctab >risckw.h
+risckw.h: risc.tab kwgen
+       ./kwgen mr <risc.tab >risckw.h
 
-opkw.h : op.tab kwgen
+opkw.h: op.tab kwgen
        ./kwgen mo <op.tab >opkw.h
 
+# Looks like this is not needed...
+dsp56kkw.h: dsp56k.tab kwgen
+       ./kwgen dsp <dsp56k.tab >dsp56kkw.h
+
 #
 # Build tools
 #
 
-kwgen.o : kwgen.c
-       $(HOSTCC) $(CFLAGS) -c kwgen.c
-
-kwgen : kwgen.o
-       $(HOSTCC) $(CFLAGS) -o kwgen kwgen.o
-
-68kgen.o : 68kgen.c
-       $(HOSTCC) $(CFLAGS) -c 68kgen.c
-
-68kgen : 68kgen.o
-       $(HOSTCC) $(CFLAGS) -o 68kgen 68kgen.o
+%gen: %gen.c
+       $(HOSTCC) $(CFLAGS) -c $<
+       $(HOSTCC) $(CFLAGS) -o $*gen $<
 
 #
 # Build RMAC executable
 #
 
-6502.o : 6502.c 6502.h
-       $(CC) $(CFLAGS) -c 6502.c
-
-amode.o : amode.c amode.h
-       $(CC) $(CFLAGS) -c amode.c
-
-debug.o : debug.c debug.h
-       $(CC) $(CFLAGS) -c debug.c
-
-direct.o : direct.c direct.h
-       $(CC) $(CFLAGS) -c direct.c
-
-eagen.o : eagen.c eagen.h eagen0.c
-       $(CC) $(CFLAGS) -c eagen.c
-
-error.o : error.c error.h
-       $(CC) $(CFLAGS) -c error.c
-
-expr.o : expr.c expr.h
-       $(CC) $(CFLAGS) -c expr.c
-
-fltpoint.o : fltpoint.c fltpoint.h
-       $(CC) $(CFLAGS) -c fltpoint.c
-
-listing.o : listing.c listing.h
-       $(CC) $(CFLAGS) -c listing.c
-
-mach.o : mach.c mach.h
-       $(CC) $(CFLAGS) -c mach.c
-
-macro.o : macro.c macro.h
-       $(CC) $(CFLAGS) -c macro.c
-
-mark.o : mark.c mark.h
-       $(CC) $(CFLAGS) -c mark.c
-
-object.o : object.c object.h
-       $(CC) $(CFLAGS) -c object.c
-
-op.o : op.c op.h
-       $(CC) $(CFLAGS) -c op.c
-
-procln.o : procln.c procln.h
-       $(CC) $(CFLAGS) -c procln.c
-
-riscasm.o : riscasm.c riscasm.h
-       $(CC) $(CFLAGS) -c riscasm.c
-
-rmac.o : rmac.c rmac.h
-       $(CC) $(CFLAGS) -c rmac.c
-
-sect.o : sect.c sect.h
-       $(CC) $(CFLAGS) -c sect.c
-
-symbol.o : symbol.c symbol.h
-       $(CC) $(CFLAGS) -c symbol.c
-
-token.o : token.c token.h
-       $(CC) $(CFLAGS) -c token.c
+%.o: %.c %.h
+       $(CC) $(CFLAGS) -c $<
 
-rmac : $(OBJS)
+rmac: $(OBJS)
        $(CC) $(CFLAGS) -o rmac $(OBJS) -lm
 
 #
@@ -152,30 +93,37 @@ rmac : $(OBJS)
 #
 
 clean:
-       $(rm) $(OBJS) kwgen.o 68kgen.o rmac kwgen 68kgen kwtab.h 68ktab.h mntab.h risckw.h 6502kw.h opkw.h
+       $(RM) $(OBJS) kwgen.o 68kgen.o rmac kwgen 68kgen 68k.tab kwtab.h 68ktab.h mntab.h risckw.h 6502kw.h opkw.h dsp56kgen dsp56kgen.o dsp56k.tab dsp56kkw.h dsp56ktab.h
 
 #
 # Dependencies
 #
 6502.o: 6502.c direct.h rmac.h symbol.h token.h expr.h error.h mach.h \
- procln.h riscasm.h sect.h
-68kgen.o: 68kgen.c
+ procln.h riscasm.h sect.h kwtab.h
+68kgen: 68kgen.c
 amode.o: amode.c amode.h rmac.h symbol.h error.h expr.h mach.h procln.h \
- token.h sect.h kwtab.h mntab.h parmode.h
+ token.h sect.h riscasm.h kwtab.h mntab.h parmode.h
 debug.o: debug.c debug.h rmac.h symbol.h amode.h direct.h token.h expr.h \
- mark.h sect.h
+ mark.h sect.h riscasm.h
 direct.o: direct.c direct.h rmac.h symbol.h token.h 6502.h amode.h \
  error.h expr.h fltpoint.h listing.h mach.h macro.h mark.h procln.h \
  riscasm.h sect.h kwtab.h
+dsp56k.o: dsp56k.c rmac.h symbol.h dsp56k.h sect.h riscasm.h
+dsp56k_amode.o: dsp56k_amode.c dsp56k_amode.h rmac.h symbol.h amode.h \
+ error.h token.h expr.h procln.h sect.h riscasm.h kwtab.h mntab.h
+dsp56k_mach.o: dsp56k_mach.c dsp56k_mach.h rmac.h symbol.h dsp56k_amode.h \
+ amode.h direct.h token.h dsp56k.h sect.h riscasm.h error.h kwtab.h \
+ dsp56ktab.h
+dsp56kgen: dsp56kgen.c
 eagen.o: eagen.c eagen.h rmac.h symbol.h amode.h error.h fltpoint.h \
  mach.h mark.h riscasm.h sect.h token.h eagen0.c
 error.o: error.c error.h rmac.h symbol.h listing.h token.h
 expr.o: expr.c expr.h rmac.h symbol.h direct.h token.h error.h listing.h \
  mach.h procln.h riscasm.h sect.h kwtab.h
 fltpoint.o: fltpoint.c fltpoint.h
-kwgen.o: kwgen.c
+kwgen: kwgen.c
 listing.o: listing.c listing.h rmac.h symbol.h error.h procln.h token.h \
- sect.h version.h
+ sect.h riscasm.h version.h
 mach.o: mach.c mach.h rmac.h symbol.h amode.h direct.h token.h eagen.h \
  error.h expr.h procln.h riscasm.h sect.h kwtab.h 68ktab.h
 macro.o: macro.c macro.h rmac.h symbol.h debug.h direct.h token.h error.h \
@@ -183,20 +131,20 @@ macro.o: macro.c macro.h rmac.h symbol.h debug.h direct.h token.h error.h \
 mark.o: mark.c mark.h rmac.h symbol.h error.h object.h riscasm.h sect.h
 object.o: object.c object.h rmac.h symbol.h 6502.h direct.h token.h \
  error.h mark.h riscasm.h sect.h
-op.o: op.c op.h rmac.h symbol.h direct.h token.h error.h expr.h \
- fltpoint.h mark.h procln.h riscasm.h sect.h
+op.o: op.c op.h direct.h rmac.h symbol.h token.h error.h expr.h \
+ fltpoint.h mark.h procln.h riscasm.h sect.h opkw.h
 procln.o: procln.c procln.h rmac.h symbol.h token.h 6502.h amode.h \
- direct.h error.h expr.h listing.h mach.h macro.h op.h riscasm.h sect.h \
- kwtab.h mntab.h risckw.h 6502kw.h opkw.h
+ direct.h dsp56kkw.h error.h expr.h listing.h mach.h macro.h op.h riscasm.h \
sect.h kwtab.h mntab.h risckw.h 6502kw.h opkw.h
 riscasm.o: riscasm.c riscasm.h rmac.h symbol.h amode.h direct.h token.h \
  error.h expr.h mark.h procln.h sect.h risckw.h kwtab.h
 rmac.o: rmac.c rmac.h symbol.h 6502.h debug.h direct.h token.h error.h \
  expr.h listing.h mark.h macro.h object.h procln.h riscasm.h sect.h \
  version.h
-sect.o: sect.c sect.h rmac.h symbol.h 6502.h direct.h token.h error.h \
- expr.h listing.h mach.h mark.h riscasm.h
+sect.o: sect.c sect.h rmac.h symbol.h riscasm.h 6502.h direct.h token.h \
+ error.h expr.h listing.h mach.h mark.h
 symbol.o: symbol.c symbol.h error.h rmac.h listing.h object.h procln.h \
  token.h
 token.o: token.c token.h rmac.h symbol.h direct.h error.h macro.h \
- procln.h sect.h kwtab.h
+ procln.h sect.h riscasm.h kwtab.h
 
index eb7428121e8b2b4d1cd44576afd0f8449c711d11..d7bf53c577044a5b5ee83659cbe6b8c697ef2712 100644 (file)
--- a/procln.c
+++ b/procln.c
@@ -10,6 +10,8 @@
 #include "6502.h"
 #include "amode.h"
 #include "direct.h"
+#include "dsp56k_amode.h"
+#include "dsp56k_mach.h"
 #include "error.h"
 #include "expr.h"
 #include "listing.h"
 #define DECL_MO                                        // Include OP keyword state machine tables
 #include "opkw.h"
 
+#define DEF_DSP                                        // Include DSP56K keywords definitions
+#define DECL_DSP                               // Include DSP56K keyword state machine tables
+#include "dsp56kkw.h"
+
+
 IFENT * ifent;                                 // Current ifent
 static IFENT ifent0;                   // Root ifent
 IFENT * f_ifent;                               // Freelist of ifents
@@ -696,6 +703,93 @@ When checking to see if it's already been equated, issue a warning.
                }
        }
 
+       // If we are in 56K mode and still in need of a mnemonic then search for one
+       if (dsp56001 && ((state < 0) || (state >= 1000)))
+       {
+               for(state=0, p=opname; state>=0;)
+               {
+                       j = dspbase[state] + (int)tolowertab[*p];
+
+                       // Reject, character doesn't match
+                       if (dspcheck[j] != state)
+                       {
+                               state = -1;                                     // No match
+                               break;
+                       }
+
+                       // Must accept or reject at EOS
+                       if (!*++p)
+                       {
+                               state = dspaccept[j];           // (-1 on no terminal match)
+                               break;
+                       }
+
+                       state = dsptab[j];
+               }
+
+               // Call DSP code generator if we found a mnemonic
+               if (state >= 2000)
+               {
+                       LONG parcode;
+                       int operands;
+                       MNTABDSP * md = &dsp56k_machtab[state - 2000];
+                       deposit_extra_ea = 0;   // Assume no extra word needed
+
+                       if (md->mnfunc == dsp_mult)
+                       {
+                               // Special case for multiplication instructions: they require
+                               // 3 operands
+                               if ((operands = dsp_amode(3)) == ERROR)
+                                       goto loop;
+                       }
+                       else if ((md->mnattr & PARMOVE) && md->mn0 != M_AM_NONE)
+                       {
+                               if (dsp_amode(2) == ERROR)
+                                       goto loop;
+                       }
+                       else if ((md->mnattr & PARMOVE) && md->mn0 == M_AM_NONE)
+                       {
+                               // Instructions that have parallel moves but use no operands
+                               // (probably only move). In this case, don't parse addressing
+                               // modes--just go straight to parallel parse
+                               dsp_am0 = dsp_am1 = M_AM_NONE;
+                       }
+                       else
+                       {
+                               // Non parallel move instructions can have up to 4 parameters
+                               // (well, only tcc instructions really)
+                               if ((operands = dsp_amode(4)) == ERROR)
+                                       goto loop;
+
+                               if (operands == 4)
+                               {
+                                       dsp_tcc4(md->mninst);
+                                       goto loop;
+                               }
+                       }
+
+                       if (md->mnattr & PARMOVE)
+                       {
+                               // Check for parallel moves
+                               if ((parcode = parmoves(dsp_a1reg)) == ERROR)
+                                       goto loop;
+                       }
+                       else
+                       {
+                               if (*tok != EOL)
+                                       error("parallel moves not allowed with this instruction");
+
+                               parcode = 0;
+                       }
+
+                       while ((dsp_am0 & md->mn0) == 0 || (dsp_am1 & md->mn1) == 0)
+                               md = &dsp56k_machtab[md->mncont];
+
+                       (*md->mnfunc)(md->mninst | (parcode << 8));
+                       goto loop;
+               }
+       }
+
        // Invoke macro or complain about bad mnemonic
        if (state < 0)
        {
@@ -760,16 +854,11 @@ When checking to see if it's already been equated, issue a warning.
        // Keep a backup of chptr (used for optimisations during codegen)
        chptr_opcode = chptr;
 
-       for(;;)
-       {
-               if ((m->mnattr & siz) && (amsk0 & m->mn0) != 0 && (amsk1 & m->mn1) != 0)
-               {
-                       (*m->mnfunc)(m->mninst, siz);
-                       goto loop;
-               }
-
+       while ((m->mnattr & siz) && (amsk0 & m->mn0) == 0 || (amsk1 & m->mn1) == 0)
                m = &machtab[m->mncont];
-       }
+
+       (*m->mnfunc)(m->mninst, siz);
+       goto loop;
 }
 
 
similarity index 100%
rename from risctab
rename to risc.tab
diff --git a/rmac.h b/rmac.h
index f282460176f9cdd1ed547ffd38d310245a7567f9..cf8aabc2d9521c962205a70784c24b41fb68ca28 100644 (file)
--- a/rmac.h
+++ b/rmac.h
@@ -219,7 +219,12 @@ PTR
 #define DATA         0x0002            // Relative to data
 #define BSS          0x0004            // Relative to BSS
 #define M6502        0x0008            // 6502/microprocessor (absolute)
+#define M56001P      0x0010            // DSP 56001 Program RAM
+#define M56001X      0x0020            // DSP 56001 X RAM
+#define M56001Y      0x0040            // DSP 56001 Y RAM
+#define M56001L      0x0080            // DSP 56001 L RAM
 #define TDB          (TEXT|DATA|BSS)   // Mask for text+data+bss
+#define M56KPXYL     (M56001P|M56001X|M56001Y|M56001L) // Mask for 56K stuff
 
 // Sizes
 #define SIZB         0x0001            // .b
diff --git a/sect.c b/sect.c
index 59f7977160b11dee3d3057e050f166f426bc74ea..b076ca6a313dddaa9db58087ab1aac65f34b63fb 100644 (file)
--- a/sect.c
+++ b/sect.c
@@ -91,12 +91,12 @@ void InitSection(void)
 //
 void MakeSection(int sno, uint16_t attr)
 {
-       SECT * p = &sect[sno];
-       p->scattr = attr;
-       p->sloc = 0;
-       p->orgaddr = 0;
-       p->scode = p->sfcode = NULL;
-       p->sfix = p->sffix = NULL;
+       SECT * sp = &sect[sno];
+       sp->scattr = attr;
+       sp->sloc = 0;
+       sp->orgaddr = 0;
+       sp->scode = sp->sfcode = NULL;
+       sp->sfix = sp->sffix = NULL;
 }
 
 
@@ -108,15 +108,15 @@ void SwitchSection(int sno)
 {
        CHUNK * cp;
        cursect = sno;
-       SECT * p = &sect[sno];
+       SECT * sp = &sect[sno];
 
        m6502 = (sno == M6502); // Set 6502-mode flag
 
        // Copy section vars
-       scattr = p->scattr;
-       sloc = p->sloc;
-       scode = p->scode;
-       orgaddr = p->orgaddr;
+       scattr = sp->scattr;
+       sloc = sp->sloc;
+       scode = sp->scode;
+       orgaddr = sp->orgaddr;
 
        // Copy code chunk vars
        if ((cp = scode) != NULL)
@@ -126,6 +126,12 @@ void SwitchSection(int sno)
                chptr = cp->chptr + ch_size;
 
                // For 6502 mode, add the last org'd address
+// Why?
+/*
+Because the way this is set up it treats the 6502 assembly space as a single 64K space (+ 16 bytes, for some reason) and just bobbles around inside that space and uses a stack of org "pointers" to show where the data ended up.
+
+This is a piss poor way to handle things, and for fucks sake, we can do better than this!
+*/
                if (m6502)
                        chptr = cp->chptr + orgaddr;
        }
@@ -139,11 +145,11 @@ void SwitchSection(int sno)
 //
 void SaveSection(void)
 {
-       SECT * p = &sect[cursect];
+       SECT * sp = &sect[cursect];
 
-       p->scattr = scattr;                             // Bailout section vars
-       p->sloc = sloc;
-       p->orgaddr = orgaddr;
+       sp->scattr = scattr;                    // Bailout section vars
+       sp->sloc = sloc;
+       sp->orgaddr = orgaddr;
 
        if (scode != NULL)                              // Bailout code chunk
                scode->ch_size = ch_size;
@@ -711,7 +717,6 @@ int ResolveFixups(int sno)
                                if (fup->orgaddr)
                                        addr = fup->orgaddr;
 
-
                                eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21);
                        }
                        else if (w & FU_OBJDATA)
diff --git a/sect.h b/sect.h
index 11ddfd4caf4e2b3cba51036b313d062bd5767f8c..83bc7b5a5736706cdbcd2f849e5e6b27ef1fbed3 100644 (file)
--- a/sect.h
+++ b/sect.h
@@ -10,6 +10,7 @@
 #define __SECT_H__
 
 #include "rmac.h"
+#include "riscasm.h"
 
 // Macros to deposit code in the current section (in Big Endian)
 #define D_byte(b)      {chcheck(1);*chptr++=(uint8_t)(b); sloc++; ch_size++; \
@@ -38,7 +39,7 @@
        sloc+=2; ch_size+=2;if(orgactive) orgaddr += 2;}
 
 // Macro for the 56001. Word size on this device is 24 bits wide. I hope that
-// orgaddr += 1 means that the addresses in the device reflect this.
+// orgaddr += 1 means that the addresses in the device reflect this. [A: Yes.]
 #define D_dsp(w)       {chcheck(3);*chptr++=(uint8_t)(w>>16); \
        *chptr++=(uint8_t)(w>>8); *chptr++=(uint8_t)w; \
        sloc+=1; ch_size += 3; if(orgactive) orgaddr += 1; \
@@ -77,6 +78,8 @@
 #define FU_BYTEH     0x0008            // Fixup 6502 high byte of immediate word
 #define FU_BYTEL     0x0009            // Fixup 6502 low byte of immediate word
 #define FU_QUAD      0x000A            // Fixup quad-word (8 bytes)
+#define FU_56001     0x000B            // Generic fixup code for all 56001 modes
+#define FU_56001_B   0x000C            // Generic fixup code for all 56001 modes (ggn: I have no shame)
 
 #define FU_SEXT      0x0010            // Ok to sign extend
 #define FU_PCREL     0x0020            // Subtract PC first
 #define FU_DONE      0x8000            // Fixup has been done
 
 // FPU fixups
-#define FU_FLOATSING 0x000B            // Fixup 32-bit float
-#define FU_FLOATDOUB 0x000C            // Fixup 64-bit float
-#define FU_FLOATEXT  0x000D            // Fixup 96-bit float
+#define FU_FLOATSING 0x000D            // Fixup 32-bit float
+#define FU_FLOATDOUB 0x000E            // Fixup 64-bit float
+#define FU_FLOATEXT  0x000F            // Fixup 96-bit float
 
 // OP fixups
 #define FU_OBJLINK   0x10000   // Fixup OL link addr (bits 24-42, drop last 3)
 #define FU_OBJDATA   0x20000   // Fixup OL data addr (bits 43-63, drop last 3)
 
+// DSP56001 fixups
+// TODO: Sadly we don't have any spare bits left inside a 16-bit word
+// so we use the 2nd nibble as control code and
+// stick $B or $C in the lower nibble - then it's picked up as
+// FU_56001 by the fixup routine and then a second switch
+// selects fixup mode. Since we now have 32 bits, we can fix this!
+// [N.B.: This isn't true anymore, we now have 32 bits! :-P]
+#define FU_DSPIMM5    0x090B   // Fixup  5-bit immediate
+#define FU_DSPADR12   0x0A0B   // Fixup 12-bit address
+#define FU_DSPADR24   0x0B0B   // Fixup 24-bit address
+#define FU_DSPADR16   0x0C0B   // Fixup 24-bit address
+#define FU_DSPIMM12   0x0D0B   // Fixup 12-bit immediate
+#define FU_DSPIMM24   0x0E0B   // Fixup 24-bit immediate
+#define FU_DSPIMM8    0x0F0B   // Fixup  8-bit immediate
+#define FU_DSPADR06   0x090C   // Fixup  6-bit address
+#define FU_DSPPP06    0x0A0C   // Fixup  6 bit pp address
+#define FU_DSPIMMFL8  0x0B0C   // Fixup  8-bit immediate float
+#define FU_DSPIMMFL16 0x0C0C   // Fixup 16-bit immediate float
+#define FU_DSPIMMFL24 0x0D0C   // Fixup 24-bit immediate float
+
 
 // Chunks are used to hold generated code and fixup records
 #define CHUNK  struct _chunk
diff --git a/token.h b/token.h
index e20402bfd59db523f888ba41ad9a241c1e173f5d..59e6ff50051ee7edf2aa4041029cb9e80d53e7cb 100644 (file)
--- a/token.h
+++ b/token.h
@@ -63,6 +63,8 @@
 #define DOTQ            'Q'                    // .q or .Q (essentially an alias for P)
 #define DOTS            'S'                    // .s or .S (FPU Single)
 #define ENDEXPR         'E'                    // End of expression
+#define UNLT            0x81           // Unary '<' (low byte)
+#define UNGT            0x82           // Unary '>' (high byte)
 
 // ^^ operators
 #define CR_DEFINED      'p'                    // ^^defined - is symbol defined?