+ 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 == REG56_A)
+ S1 = 4;
+ else if (S1 == REG56_B)
+ S1 = 5;
+ else
+ S1 &= 7;
+
+ inst = 0b0100000000000000;
+ inst |= dspImmedEXVAL;
+ inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
+ return inst;
+ }
+ else
+ {
+ // 'S,L:ea'
+ if (S1 == REG56_A)
+ S1 = 4;
+ else if (S1 == REG56_B)
+ S1 = 5;
+ else
+ S1 &= 7;
+
+ if (ea1 == DSP_EA_ABS)
+ deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+
+ inst |= 0b0100000001110000;
+ 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 >= REG56_A10 && *(tok + 1) <= REG56_BA) || (*tok >= REG56_A && *tok <= REG56_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 == REG56_A)
+ immreg = 4;
+ else if (immreg == REG56_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 &= 0b1111111110111111;
+ 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 == REG56_A)
+ D1 = 4;
+ else if (D1 == REG56_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 |= 0b0000000000110000;
+ 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 = 0b0100000001000000;
+
+ if (S1 == REG56_A)
+ S1 = 4;
+ else if (S1 == REG56_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 >= REG56_A10 && *tok <= REG56_BA) || (*tok >= REG56_A && *tok <= REG56_B)) && *(tok + 1) == EOL)
+ {
+ //'L:ea,D'
+ D1 = *tok++;
+
+ if (D1 == REG56_A)
+ D1 = 4;
+ else if (D1 == REG56_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) && (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 >= REG56_R0 && *tok <= REG56_R7)
+ {
+ // We got '-(Rn' so mark it down
+ ea = DSP_EA_PREDEC1 | (*tok++ - REG56_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 >= REG56_R0 && *tok <= REG56_R7)
+ {
+ // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
+ ea = *tok++ - REG56_R0;
+
+ if (*tok == '+')
+ {
+ // '(Rn+Nn)'
+ tok++;
+
+ if (*tok < REG56_N0 || *tok > REG56_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 >= REG56_N0 && *tok <= REG56_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 >= REG56_N0 && *tok <= REG56_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 >= REG56_N0 && *tok <= REG56_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 >= REG56_N0 && *tok <= REG56_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) && (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) && (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 0b0010000000000000;
+ }
+
+ if (*tok == '#')
+ {
+ // '#xxxxxx,D', '#xx,D'
+ tok++;
+ force_imm = NUM_NORMAL;
+
+ if (*tok == '>')