]> Shamusworld >> Repos - rmac/blobdiff - dsp56k_amode.c
Cleanup of codebase and initial commit of 56K assembler by ggn.
[rmac] / dsp56k_amode.c
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;
+}
+