+ 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");