//
-// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC - Renamed Macro Assembler for the Atari Jaguar Console System
// AMODE.C - DSP 56001 Addressing Modes
-// Copyright (C) 199x Landon Dyer, 2011-2019 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
#include "sect.h"
#include "math.h"
-#define DEF_KW
-#include "kwtab.h"
#define DEF_MN
#include "mntab.h"
+#define DEF_REG56
+#include "56kregs.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
WORD dspaaEXATTR; // Expression's attribute
SYM * dspaaESYM; // External symbol involved in expr
-int dsp_k; // Multiplications sign
+LONG dsp_a0perspace; // Peripheral space (X, Y - used in movep)
+LONG dsp_a1perspace; // Peripheral space (X, Y - used in movep)
+
+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)
+// 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
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)
+ if (*tok == REG56_A || *tok == REG56_B)
{
*am = M_ACC56;
*areg = *tok++;
return OK;
}
- else if (*tok >= KW_X0 && *tok <= KW_Y1)
+ else if (*tok >= REG56_X0 && *tok <= REG56_Y1)
{
*am = M_ALU24;
*areg = *tok++;
return OK;
}
- else if (*tok == KW_X && *(tok + 1) == ':')
+ else if (*tok == REG56_X && *(tok + 1) == ':')
{
tok = tok + 2;
*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...
+ *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
return OK;
}
else
return ERROR;
}
- else if (*tok == KW_Y && *(tok + 1) == ':')
+ else if (*tok == REG56_Y && *(tok + 1) == ':')
{
tok = tok + 2;
{
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;
+ if (CHECK_OPTS(OPT_56K_AUTO_LONG))
+ {
+ if (optim_warn_flag)
+ warn("o11: 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
+ {
+ return error("short addressing mode forced but address is bigger than $3F - turn opt switch o11 on to bypass");
+ }
}
}
else
return ERROR;
// TODO: add absolute address checks
}
- else if ((*tok >= KW_X) && (*tok <= KW_Y))
+ else if ((*tok >= REG56_X) && (*tok <= REG56_Y))
{
*am = M_INP48;
*areg = *tok++;
return OK;
}
- else if ((*tok >= KW_M0) && (*tok <= KW_M7))
+ else if ((*tok >= REG56_M0) && (*tok <= REG56_M7))
{
*am = M_DSPM;
*areg = (*tok++) & 7;
return OK;
}
- else if ((*tok >= KW_R0) && (*tok <= KW_R7))
+ else if ((*tok >= REG56_R0) && (*tok <= REG56_R7))
{
*am = M_DSPR;
- *areg = (*tok++) - KW_R0;
+ *areg = (*tok++) - REG56_R0;
return OK;
}
- else if ((*tok >= KW_N0) && (*tok <= KW_N7))
+ else if ((*tok >= REG56_N0) && (*tok <= REG56_N7))
{
*am = M_DSPN;
*areg = (*tok++) & 7;
return OK;
}
- else if ((*tok == KW_A0) || (*tok == KW_A1) || (*tok == KW_B0)
- || (*tok == KW_B1))
+ else if ((*tok == REG56_A0) || (*tok == REG56_A1) || (*tok == REG56_B0)
+ || (*tok == REG56_B1))
{
*am = M_ACC24;
*areg = *tok++;
return OK;
}
- else if ((*tok == KW_A2) || (*tok == KW_B2))
+ else if ((*tok == REG56_A2) || (*tok == REG56_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))
+ else if ((*tok == '-') && (*(tok + 1) == REG56_X0 || *(tok + 1) == REG56_X1 || *(tok + 1) == REG56_Y0 || *(tok + 1) == REG56_Y1))
{
// '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
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))
+ else if (*tok == '+' && (*(tok + 1) == REG56_X0 || *(tok + 1) == REG56_X1 || *(tok + 1) == REG56_Y0 || *(tok + 1) == REG56_Y1))
{
// '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
tok++;
// 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) == ':')
+ else if (*tok == REG56_P && *(tok + 1) == ':')
{
tok = tok + 2;
*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))
+ else if (*tok == REG56_PC || *tok == REG56_CCR || *tok == REG56_SR || *tok == REG56_SP || (*tok >= REG56_MR&&*tok <= REG56_SS))
{
*areg = *tok++;
*am = M_DSPPCU;
//
static inline int SDreg(int reg)
{
- if (reg >= KW_X0 && reg <= KW_N7)
+ if (reg >= REG56_X0 && reg <= REG56_N7)
return reg & 0xFF;
- else if (reg >= KW_A0&® <= KW_A2)
+ else if (reg >= REG56_A0&® <= REG56_A2)
return (8 >> (reg & 7)) | 8;
- else //if (reg>=KW_R0&®<=KW_R7)
- return reg - KW_R0 + 16;
+ else //if (reg>=REG56_R0&®<=REG56_R7)
+ return reg - REG56_R0 + 16;
// Handy map for the above:
// (values are of course taken from keytab)
// Register | Value | Return value
// 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;
+ case REG56_X0: D1 = 0 << 10; break;
+ case REG56_X1: D1 = 1 << 10; break;
+ case REG56_A: D1 = 2 << 10; break;
+ case REG56_B: D1 = 3 << 10; break;
default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
}
}
}
}
- if (*tok == KW_Y)
+ if (*tok == REG56_Y)
{
tok++;
// 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
if (*tok++ == '(')
{
- if (*tok >= KW_R0 && *tok <= KW_R7)
+ if (*tok >= REG56_R0 && *tok <= REG56_R7)
{
- ea2 = (*tok++ - KW_R0);
+ ea2 = (*tok++ - REG56_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'");
ea2 = 3 << 12;
tok++;
}
- else if (*tok >= KW_N0 && *tok <= KW_N7)
+ else if (*tok >= REG56_N0 && *tok <= REG56_N7)
{
// (Rn)+Nn
if ((*tok++ & 7) != ea2)
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;
+ case REG56_Y0: D2 = 0 << 8; break;
+ case REG56_Y1: D2 = 1 << 8; break;
+ case REG56_A: D2 = 2 << 8; break;
+ case REG56_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 (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 = 0b1100000000000000 | 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)
+ else if (*tok == REG56_Y0 || *tok == REG56_Y1 || *tok == REG56_A || *tok == REG56_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;
+ case REG56_Y0: S2 = 0 << 8; break;
+ case REG56_Y1: S2 = 1 << 8; break;
+ case REG56_A: S2 = 2 << 8; break;
+ case REG56_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)
+ if (*tok++ == REG56_Y)
{
// 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
if (*tok++ != ':')
if (*tok++ == '(')
{
- if (*tok >= KW_R0 && *tok <= KW_R7)
+ if (*tok >= REG56_R0 && *tok <= REG56_R7)
{
- ea2 = (*tok++ - KW_R0);
+ ea2 = (*tok++ - REG56_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'");
if (*tok == EOL)
// (Rn)+
ea2 = 3 << 12;
- else if (*tok >= KW_N0 && *tok <= KW_N7)
+ else if (*tok >= REG56_N0 && *tok <= REG56_N7)
{
// (Rn)+Nn
if ((*tok++ & 7) != ea2)
ea2 |= eay_temp; //OR eay back from temp
- inst = B16(10000000, 00000000) | w;
+ inst = 0b1000000000000000 | w;
inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
return inst;
}
{
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)
+ if (*tok == REG56_X0 && tok[1] == ',' && tok[2] == REG56_A)
{
// 'A,X:ea X0,A'
if (ea1 == DSP_EA_ABS)
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))
+ if (ea1 == 0b00110100)
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);
+ inst = 0b0000100000000000 | ea1 | (0 << 8);
return inst;
}
- else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
+ else if (*tok == REG56_X0 && tok[1] == ',' && tok[2] == REG56_B)
{
// 'B,X:ea X0,B'
if (ea1 == DSP_EA_ABS)
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))
+ if (ea1 == 0b00110100)
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);
+ inst = 0b0000100100000000 | ea1 | (1 << 8);
return inst;
}
- else if (*tok == KW_A || *tok == KW_B)
+ else if (*tok == REG56_A || *tok == REG56_B)
{
// 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
switch (S1)
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)
+ if (tok[1] == ',' && tok[2] == REG56_Y)
{
// 'S1,X:eax S2,Y:eay'
return check_x_y(ea1, S1);
switch (*tok++)
{
- case KW_A: S2 = 0 << 9; break;
- case KW_B: S2 = 1 << 9; break;
+ case REG56_A: S2 = 0 << 9; break;
+ case REG56_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 == REG56_Y0 || *tok == REG56_Y1)
{
- if (*tok++ == KW_Y0)
+ if (*tok++ == REG56_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 = 0b0001000000000000 | (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)
+ else if (*tok == REG56_Y)
{
// 'S1,X:eax Y:eay,D2'
return check_x_y(ea1, S1);
}
- else if (*tok == KW_Y0 || *tok == KW_Y1)
+ else if (*tok == REG56_Y0 || *tok == REG56_Y1)
{
// 'S1,X:eax S2,Y:eay'
return check_x_y(ea1, S1);
// 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)
+ if (*tok == ',' && ((*(tok + 1) >= REG56_X0 && *(tok + 1) <= REG56_N7) || (*(tok + 1) >= REG56_R0 && *(tok + 1) <= REG56_R7) || (*(tok + 1) >= REG56_A0 && *(tok + 1) <= REG56_A2)) && *(tok + 2) == EOL)
{
// Yup, we're good to go - 'X:aa,D' it is
tok++;
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))
+ if ((*tok >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_A2))
{
D1 = SDreg(*tok++);
if (*tok == EOL)
{
// 'X:ea,D'
- inst = inst | B8(01000000) | (1 << 7);
+ inst = inst | 0b01000000 | (1 << 7);
inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
inst |= ea1;
else
{
// 'X:ea,D1 S2,D2'
- if (*tok == KW_A || *tok == KW_B)
+ if (*tok == REG56_A || *tok == REG56_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)
+ if (*tok == REG56_Y0 || *tok == REG56_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 = 0b0001000000000000 | (1 << 7);
inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
inst |= (S2 & 1) << 9;
inst |= (D2 & 1) << 8;
if (*tok == EOL)
{
// 'S,X:ea'
- inst = inst | B8(01000000) | (0 << 7);
+ inst = inst | 0b01000000 | (0 << 7);
inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
inst |= ea1;
// 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)
+ if (((*tok >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_A2)) && *(tok + 1) == EOL)
{
//'X:ea,D'
D1 = SDreg(*tok++);
- inst = inst | B8(01000000) | (1 << 7);
+ inst = inst | 0b01000000 | (1 << 7);
inst |= ea1;
inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
return inst;
if (*tok == EOL)
{
//'S,X:ea'
- inst = inst | B8(01000000) | (0 << 7);
+ inst = inst | 0b01000000 | (0 << 7);
inst |= ea1;
inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
return inst;
// '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)))
+ if ((*tok == REG56_X0 || *tok == REG56_X1 || *tok == REG56_A || *tok == REG56_B) && (*(tok + 1) == REG56_A || *(tok + 1) == REG56_B) && (*(tok + 2) == ',') && (*(tok + 3) == REG56_Y0 || (*(tok + 3) == REG56_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;
+ case REG56_X0: D1 = 0 << 10; break;
+ case REG56_X1: D1 = 1 << 10; break;
+ case REG56_A: D1 = 2 << 10; break;
+ case REG56_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;
+ case REG56_A: S2 = 0 << 9; break;
+ case REG56_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 == REG56_Y0 || *tok == REG56_Y1)
{
- if (*tok++ == KW_Y0)
+ if (*tok++ == REG56_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 = 0b0001000000000000 | (W << 7);
inst |= ea1 | D1 | S2 | D2;
return inst;
}
if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
return ERROR;
- if (dspImmedEXATTR & DEFINED)
- if (dspImmedEXVAL > 0xffffff)
- return error("long address is bigger than $ffffff");
+ if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
+ return error("long address is bigger than $FFFFFF");
deposit_extra_ea = DEPOSIT_EXTRA_WORD;
{
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;
+ if (CHECK_OPTS(OPT_56K_AUTO_LONG))
+ {
+ if (optim_warn_flag)
+ warn("o11: 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
+ {
+ return error("short addressing mode forced but address is bigger than $3F - turn opt switch o11 on to bypass");
+ }
}
}
else
if (*tok == EOL && S1 != 0)
{
// 'S,Y:aa'
- inst = B16(01001000, 00000000);
+ inst = 0b0100100000000000;
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)
+
+ if (*tok == ',' && ((*(tok + 1) >= REG56_X0 && *(tok + 1) <= REG56_N7) || (*(tok + 1) >= REG56_R0 && *(tok + 1) <= REG56_R7) || (*(tok + 1) >= REG56_A0 && *(tok + 1) <= REG56_A2)) && *(tok + 2) == EOL)
{
// Yup, we're good to go - 'Y:aa,D' it is
tok++;
if (*tok == EOL && S1 != 0)
{
// 'S,Y:ea'
- inst = B16(01001000, 01110000);
+ inst = 0b0100100001110000;
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))
+ if ((*tok >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_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 |= 0b0000000001110000;
inst |= ea1;
inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
if (ea1 == DSP_EA_ABS)
else
{
// 'S1,D1 Y:ea,D2'
- if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
+ if (*tok == REG56_A || *tok == REG56_B || *tok == REG56_Y0 || *tok == REG56_Y1)
{
D2 = SDreg(*tok++);
inst |= ea1;
else
return ERROR;
}
- else
- {
- // It's not an immediate, check for '-(Rn)'
- ea1 = checkea(',', Y_ERRORS);
-
- if (ea1 == ERROR)
- return ERROR;
+ else
+ {
+ // It's not an immediate, check for '-(Rn)'
+ ea1 = checkea(',', Y_ERRORS);
- goto y_gotea1;
+ if (ea1 == ERROR)
+ return ERROR;
- }
- }
- 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;
- }
+ goto y_gotea1;
- // Nope, let's check for ea then
- if (S1 == 0 || (S1 != 0 && D1 != 0))
- ea1 = checkea(',', Y_ERRORS);
- else
- ea1 = checkea(EOL, Y_ERRORS);
+ }
+ }
+ else if (*tok == '#')
+ {
+ tok++;
- if (ea1 == ERROR)
- return ERROR;
+ if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+ 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;
- }
+ // 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;
+ }
- 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");
+ // 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 (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
- return ERROR;
+ if (ea1 == ERROR)
+ return ERROR;
- ea1 = DSP_EA_ABS;
+ y_gotea1:
+ if (S1 != 0 && *tok == EOL)
+ {
+ // 'S,Y:ea'
+ inst = 0b0100100001000000;
+ 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;
+ }
- 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;
- }
+ 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;
+ }
- goto y_check_immed;
- }
- }
+ if (*tok++ != ',')
+ return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
- return error("unrecognised Y: parallel move syntax");
-}
+ switch (*tok++)
+ {
+ case REG56_Y0: D2 = 0 << 8; break;
+ case REG56_Y1: D2 = 1 << 8; break;
+ case REG56_A: D2 = 2 << 8; break;
+ case REG56_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 = 0b0001000011000000;
+ inst |= S1 | D1 | D2;
+ inst |= ea1;
+ return inst;
+ }
-//
-// 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 (*tok++ != ',')
+ return error("Comma expected after 'Y:(Rn)')");
- if (ea1 == ERROR)
- return ERROR;
+ // 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 >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_A2)) && *(tok + 1) == EOL)
+ {
+ //'Y:ea,D'
+ D1 = SDreg(*tok++);
+ inst |= 0b0000000001000000;
+ 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;
- goto l_gotea1;
+ // 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
- }
- }
- 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;
- }
+ if (!(dspImmedEXATTR&DEFINED))
+ {
+ force_imm = NUM_FORCE_LONG;
+ deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+ }
- //Nope, let's check for ea then
- if (S1 == 0)
- ea1 = checkea(',', L_ERRORS);
- else
- ea1 = checkea(EOL, L_ERRORS);
+ goto y_check_immed;
+ }
+ else if (*tok == '>')
+ {
+ // Check for immediate address forced long
+ tok++;
- if (ea1 == ERROR)
- return ERROR;
+ if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+ 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)')");
+ if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
+ return error("long address is bigger than $FFFFFF");
- // 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;
- }
+ 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_LONG;
+ ea1 = DSP_EA_ABS;
+ goto y_check_immed;
+ }
+ else if (*tok == '<')
+ {
+ tok++;
- force_imm = NUM_FORCE_SHORT;
- goto l_check_immed;
- }
+ 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
+ if (CHECK_OPTS(OPT_56K_AUTO_LONG))
+ {
+ if (optim_warn_flag)
+ warn("forced short addressing in R:Y mode is not allowed - switching to long");
- 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");
-}
+ if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
+ return ERROR;
+ ea1 = DSP_EA_ABS;
-//
-// 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");
-}
+ force_imm = NUM_FORCE_LONG;
+ deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+ goto y_check_immed;
+ }
+ else
+ {
+ return error("forced short addressing in R:Y mode is not allowed - turn opt switch o11 on to bypass");
+ }
+ }
+ 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;
-//
-// 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;
+ force_imm = NUM_FORCE_SHORT;
- if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
- {
- // Check for immediate address
- if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
- return ERROR;
+ if (dspImmedEXATTR & DEFINED)
+ {
+ if (dspImmedEXVAL > 0xFFF)
+ {
+ if (CHECK_OPTS(OPT_56K_AUTO_LONG))
+ {
+ if (optim_warn_flag)
+ warn("short addressing mode forced but address is bigger than $FFF - switching to long");
- deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+ ea1 = DSP_EA_ABS;
+ force_imm = NUM_FORCE_LONG;
+ deposit_extra_ea = DEPOSIT_EXTRA_WORD;
+ }
+ else
+ {
+ return error("short addressing mode forced but address is bigger than $FFF - turn opt switch o11 on to bypass");
+ }
+ }
+ }
+ 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;
+ }
- // 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;
- }
+ goto y_check_immed;
+ }
+ }
+ return error("unrecognised Y: parallel move syntax");
}
//
-// 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!!!
+// Parse L: addressing space parallel moves
//
-LONG parmoves(WORD dest)
+static inline LONG parse_l(const int W, LONG inst, LONG S1)
{
- 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
+ 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 == EOL)
+ if (*tok == '-')
{
- // No parallel move
- return B16(00100000, 00000000);
- }
+ if (*tok == CONST || tok[1] == FCONST)
+ {
+ tok++;
+ dspImmedEXVAL = *tok++;
+ goto l_check_immed;
+ }
- if (*tok == '#')
- {
- // '#xxxxxx,D', '#xx,D'
+ // 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++ != ',')
return error("expected comma");
- if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
+ if (!((*tok >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_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 (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 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)
+ if ((dspImmedEXVAL & 0xFFFF) == 0)
{
dspImmedEXVAL >>= 16;
}
{
// '#xx,D'
// value fits in 8 bits - immediate move
- inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
+ inst = 0b0010000000000000 + (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 (CHECK_OPTS(OPT_56K_AUTO_LONG))
+ {
+ if (optim_warn_flag)
+ warn("forced short immediate value doesn't fit in 8 bits - switching to long");
+ force_imm = NUM_FORCE_LONG;
+ }
+ else
+ {
+ return error("forced short immediate value doesn't fit in 8 bits - turn opt switch o11 on to bypass");
+ }
}
}
// 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 = 0b0100000011110100;
inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
deposit_extra_ea = DEPOSIT_EXTRA_WORD;
return inst;
{
// value fits in 8 bits - immediate move
deposit_immediate_short_with_register:
- inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
+ inst = 0b0010000000000000 + (immreg << 8) + (uint32_t)dspImmedEXVAL;
return inst;
}
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 = 0b0010000000000000;
inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
return inst;
}
{
double f = *(double *)&dspImmedEXVAL;
// Check direct.c for ossom comments regarding conversion!
-//N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
+ //N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
dspImmedEXVAL = ((uint32_t)(int32_t)round(f * (1 << 23))) & 0xFFFFFF;
double g;
g = f * (1 << 23);
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 (CHECK_OPTS(OPT_56K_SHORT))
+ {
+ // Value's 16 lower bits are not set so the value can
+ // fit in a single byte (check parallel I move quoted
+ // above)
+ if (optim_warn_flag)
+ warn("o10: Immediate value fits inside 8 bits, so using instruction short format");
+
+ dspImmedEXVAL >>= 16;
+ goto deposit_immediate_short_with_register;
+ }
+ else
+ {
+ return error("Immediate value fits inside 8 bits, so using instruction short format - turn opt switch o10 on to bypass");
+ }
}
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;
+ if (CHECK_OPTS(OPT_56K_AUTO_LONG))
+ {
+ if (optim_warn_flag)
+ warn("o11: Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
+
+ goto deposit_immediate_long_with_register;
+ }
+ else
+ {
+ return error("Immediate value short format forced but value does not fit inside 8 bits - turn opt switch o11 on to bypass");
+ }
}
return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
{
// Just deposit a float fixup
AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
- inst = B16(00100000, 00000000);
+ inst = 0b0010000000000000;
inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
return inst;
}
switch (*tok++)
{
- case KW_A: S2 = 0 << 9; break;
- case KW_B: S2 = 1 << 9; break;
+ case REG56_A: S2 = 0 << 9; break;
+ case REG56_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;
}
switch (*tok++)
{
- case KW_Y0: D2 = 0 << 8; break;
- case KW_Y1: D2 = 1 << 8; break;
+ case REG56_Y0: D2 = 0 << 8; break;
+ case REG56_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;
+ inst = 0b0001000010110100 | D1 | S2 | D2;
deposit_extra_ea = DEPOSIT_EXTRA_WORD;
return inst;
}
}
- else if (*tok == KW_X)
+ else if (*tok == REG56_X)
{
if (tok[1] == ',')
// Hey look, it's just the register X and not the addressing mode - fall through to general case
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);
+ return parse_x(1, 0b0100000000000000, 0, 1);
}
- else if (*tok == KW_Y)
+ else if (*tok == REG56_Y)
{
if (tok[1] == ',')
// Hey look, it's just the register y and not the addressing mode - fall through to general case
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);
+ return parse_y(0b0100100010000000, 0, 0, 0);
}
- else if (*tok == KW_L)
+ else if (*tok == REG56_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);
+ return parse_l(1, 0b0100000011000000, 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))
+ else if ((*tok >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_A2) || (*tok >= REG56_A10 && *tok <= REG56_BA))
{
// Everything else - brace for impact!
// R: 'S,D'
if (*tok++ != ',')
return error("Comma expected after 'S')");
- if (*tok == KW_X)
+ if (*tok == REG56_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'
if (*tok++ != ':')
return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
- return parse_x(0, B16(01000000, 00000000), S1, 1);
+ return parse_x(0, 0b0100000000000000, S1, 1);
}
- else if (*tok == KW_Y)
+ else if (*tok == REG56_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);
+ return parse_y(0b000000000000000, S1, 0, 0);
}
- else if (*tok == KW_L)
+ else if (*tok == REG56_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);
+ return parse_l(1, 0b0000000000000000, L_S1);
}
- else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
+ else if ((*tok >= REG56_X0 && *tok <= REG56_N7) || (*tok >= REG56_R0 && *tok <= REG56_R7) || (*tok >= REG56_A0 && *tok <= REG56_A2))
{
// 'S,D'
// 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
if (*tok == EOL)
{
// R 'S,D'
- inst = B16(00100000, 00000000);
+ inst = 0b0010000000000000;
inst |= (S1 << 5) | (D1);
return inst;
}
- else if (*tok == KW_Y)
+ else if (*tok == REG56_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);
+ return parse_y(0b0001000001000000, S1, D1, 0);
}
- else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
+ else if (*tok == REG56_A || *tok == REG56_B || *tok == REG56_Y0 || *tok == REG56_Y1)
{
// 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
S2 = SDreg(*tok++);
if (*tok++ != ',')
return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
- if (*tok++ != KW_Y)
+ if (*tok++ != REG56_Y)
return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
if (*tok++ != ':')
if (ea1 == ERROR)
return ERROR;
- inst = B16(00001000, 10000000);
+ inst = 0b0000100010000000;
inst |= 0 << 8;
inst |= ea1;
return inst;
if (*tok++ != ',')
return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
- if (*tok++ != KW_Y)
+ if (*tok++ != REG56_Y)
return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
if (*tok++ != ':')
if (ea1 == ERROR)
return ERROR;
- inst = B16(00001000, 10000000);
+ inst = 0b0000100010000000;
inst |= 1 << 8;
inst |= ea1;
return inst;
if (*tok++ != ',')
return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
- if (*tok++ != KW_Y)
+ if (*tok++ != REG56_Y)
return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
if (*tok++ != ':')
if (ea1 == ERROR)
return ERROR;
- inst = B16(00010000, 01000000);
+ inst = 0b0001000001000000;
inst |= (S1 & 1) << 11;
inst |= (D1 & 1) << 10;
inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
return ERROR;
- if (dspImmedEXATTR & DEFINED)
- if (dspImmedEXVAL > 0xffffff)
- return error("immediate is bigger than $ffffff");
+ if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
+ return error("immediate is bigger than $FFFFFF");
deposit_extra_ea = DEPOSIT_EXTRA_WORD;
// 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;
+ case REG56_Y0: D2 = 0 << 8; break;
+ case REG56_Y1: D2 = 1 << 8; break;
+ case REG56_A: D2 = 2 << 8; break;
+ case REG56_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 (D1 == 4 || D1 == 5)
{
- inst = B16(00010000, 11110100);
+ inst = 0b0001000011110100;
inst |= (S1 & 1) << 11;
inst |= (D1 & 1) << 10;
inst |= D2;
// U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
tok++;
- if (*tok >= KW_R0 && *tok <= KW_R7)
+ if (*tok >= REG56_R0 && *tok <= REG56_R7)
{
- ea1 = (*tok++ - KW_R0);
+ ea1 = (*tok++ - REG56_R0);
}
else
return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
if (*tok == EOL)
// (Rn)+
ea1 |= 3 << 3;
- else if (*tok >= KW_N0 && *tok <= KW_N7)
+ else if (*tok >= REG56_N0 && *tok <= REG56_N7)
{
// (Rn)+Nn
if ((*tok++ & 7) != ea1)
ea1 |= 2 << 3;
tok++;
}
- else if (*tok >= KW_N0 && *tok <= KW_N7)
+ else if (*tok >= REG56_N0 && *tok <= REG56_N7)
{
// (Rn)-Nn
if ((*tok++ & 7) != ea1)
}
}
- inst = B16(00100000, 01000000);
+ inst = 0b0010000001000000;
inst |= ea1;
return inst;
}