2 // RMAC - Renamed Macro Assembler for the Atari Jaguar Console System
3 // AMODE.C - DSP 56001 Addressing Modes
4 // Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
9 #include "dsp56k_amode.h"
23 // Address-mode information
24 int dsp_am0; // Addressing mode
25 int dsp_a0reg; // Register
26 TOKEN dsp_a0expr[EXPRSIZE]; // Expression
27 uint64_t dsp_a0exval; // Expression's value
28 WORD dsp_a0exattr; // Expression's attribute
29 LONG dsp_a0memspace; // Addressing mode's memory space (P, X, Y)
30 SYM * dsp_a0esym; // External symbol involved in expr
32 int dsp_am1; // Addressing mode
33 int dsp_a1reg; // Register
34 TOKEN dsp_a1expr[EXPRSIZE]; // Expression
35 uint64_t dsp_a1exval; // Expression's value
36 WORD dsp_a1exattr; // Expression's attribute
37 LONG dsp_a1memspace; // Addressing mode's memory space (P, X, Y)
38 SYM * dsp_a1esym; // External symbol involved in expr
40 int dsp_am2; // Addressing mode
41 int dsp_a2reg; // Register
42 TOKEN dsp_a2expr[EXPRSIZE]; // Expression
43 uint64_t dsp_a2exval; // Expression's value
44 WORD dsp_a2exattr; // Expression's attribute
45 SYM * dsp_a2esym; // External symbol involved in expr
47 int dsp_am3; // Addressing mode
48 int dsp_a3reg; // Register
49 TOKEN dsp_a3expr[EXPRSIZE]; // Expression
50 uint64_t dsp_a3exval; // Expression's value
51 WORD dsp_a3exattr; // Expression's attribute
52 SYM * dsp_a3esym; // External symbol involved in expr
54 TOKEN dspImmedEXPR[EXPRSIZE]; // Expression
55 uint64_t dspImmedEXVAL; // Expression's value
56 WORD dspImmedEXATTR; // Expression's attribute
57 SYM * dspImmedESYM; // External symbol involved in expr
58 int deposit_extra_ea; // Optional effective address extension
59 TOKEN dspaaEXPR[EXPRSIZE]; // Expression
60 uint64_t dspaaEXVAL; // Expression's value
61 WORD dspaaEXATTR; // Expression's attribute
62 SYM * dspaaESYM; // External symbol involved in expr
64 LONG dsp_a0perspace; // Peripheral space (X, Y - used in movep)
65 LONG dsp_a1perspace; // Peripheral space (X, Y - used in movep)
67 int dsp_k; // Multiplications sign
69 static inline LONG checkea(const uint32_t termchar, const int strings);
71 // ea checking error strings put into a table because I'm not sure there's an
72 // easy way to do otherwise (the messages start getting differerent in many
73 // places so it will get awkward to code those in) (I'd rather burn some RAM
74 // in order to have more helpful error messages than the other way round)
81 const char *ea_errors[][12] = {
84 "unrecognised X: parallel move syntax: expected '(' after 'X:-'", // 0
85 "unrecognised X: parallel move syntax: expected ')' after 'X:-(Rn'", // 1
86 "unrecognised X: parallel move syntax: expected R0-R7 after 'X:-('", // 2
87 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn+'", // 3
88 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn+Nn)'", // 4
89 "unrecognised X: parallel move syntax: expected ')' after 'X:(Rn+Nn'", // 5
90 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)+Nn'", // 6
91 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)+'", // 7
92 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)-Nn'", // 8
93 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)-'", // 9
94 "unrecognised X: parallel move syntax: expected '+', '-' or ',' after 'X:(Rn)'", // 10
95 "unrecognised X: parallel move syntax: expected '+' or ')' after 'X:(Rn'", // 11
99 "unrecognised Y: parallel move syntax: expected '(' after 'Y:-'", // 0
100 "unrecognised Y: parallel move syntax: expected ')' after 'Y:-(Rn'", // 1
101 "unrecognised Y: parallel move syntax: expected R0-R7 after 'Y:-('", // 2
102 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn+'", // 3
103 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn+Nn)'", // 4
104 "unrecognised Y: parallel move syntax: expected ')' after 'Y:(Rn+Nn'", // 5
105 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)+Nn'", // 6
106 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)+'", // 7
107 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)-Nn'", // 8
108 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)-'", // 9
109 "unrecognised Y: parallel move syntax: expected '+', '-' or ',' after 'Y:(Rn)'", // 10
110 "unrecognised Y: parallel move syntax: expected '+' or ')' after 'Y:(Rn'", // 11
114 "unrecognised L: parallel move syntax: expected '(' after 'L:-'", // 0
115 "unrecognised L: parallel move syntax: expected ')' after 'L:-(Rn'", // 1
116 "unrecognised L: parallel move syntax: expected R0-R7 after 'L:-('", // 2
117 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn+'", // 3
118 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn+Nn)'", // 4
119 "unrecognised L: parallel move syntax: expected ')' after 'L:(Rn+Nn'", // 5
120 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)+Nn'", // 6
121 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)+'", // 7
122 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)-Nn'", // 8
123 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)-'", // 9
124 "unrecognised L: parallel move syntax: expected '+', '-' or ',' after 'L:(Rn)'", // 10
125 "unrecognised L: parallel move syntax: expected '+' or ')' after 'L:(Rn'", // 11
129 "unrecognised P: effective address syntax: expected '(' after 'P:-'", // 0
130 "unrecognised P: effective address syntax: expected ')' after 'P:-(Rn'", // 1
131 "unrecognised P: effective address syntax: expected R0-R7 after 'P:-('", // 2
132 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn+'", // 3
133 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn+Nn)'", // 4
134 "unrecognised P: effective address syntax: expected ')' after 'P:(Rn+Nn'", // 5
135 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)+Nn'", // 6
136 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)+'", // 7
137 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)-Nn'", // 8
138 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)-'", // 9
139 "unrecognised P: effective address syntax: expected '+', '-' or ',' after 'P:(Rn)'", // 10
140 "unrecognised P: effective address syntax: expected '+' or ')' after 'P:(Rn'", // 11
153 // Parse a single addressing mode
155 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)
157 if (*tok == KW_A || *tok == KW_B)
163 else if (*tok == '#')
169 // Immediate Short Addressing Mode Force Operator
171 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
174 if (*AnEXVAL > 0xFFF && *AnEXVAL < -4096)
175 return error("immediate short addressing mode forced but address is bigger than $FFF");
177 if ((int32_t)*AnEXVAL <= 0xFF && (int32_t)*AnEXVAL > -0x100)
186 else if (*tok == '>')
188 // Immediate Long Addressing Mode Force Operator
191 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
194 if ((int32_t)*AnEXVAL > 0xFFFFFF || (int32_t)*AnEXVAL < -0xFFFFFF)
195 return error("long immediate is bigger than $FFFFFF");
201 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
204 if (*AnEXATTR & DEFINED)
206 if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
211 else if (*AnEXVAL < 0x1000)
218 // We have no clue what size our immediate will be
219 // so we have to assume the worst
225 else if (*tok >= KW_X0 && *tok <= KW_Y1)
231 else if (*tok == KW_X && *(tok + 1) == ':')
235 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
237 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
240 if (*AnEXATTR & DEFINED)
242 if (*AnEXVAL > 0xFFFFFF)
243 return error("long address is bigger than $FFFFFF");
245 *memspace = 0 << 6; // Mark we're on X memory space
247 // Check if value is between $FFC0 and $FFFF, AKA X:pp
248 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
250 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
251 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
252 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
256 *memspace = 0 << 6; // Mark we're on X memory space
257 *perspace = 0 << 16; // Mark we're on X peripheral space
258 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
262 // If the symbol/expression is defined then check for valid range.
263 // Otherwise the value had better fit or Fixups will bark!
277 *memspace = 0 << 6; // Mark we're on X memory space
284 else if (*tok == '<')
287 // Short Addressing Mode Force Operator in the case of '<'
290 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
293 // If the symbol/expression is defined then check for valid range.
294 // Otherwise the value had better fit or Fixups will bark!
295 if (*AnEXATTR & DEFINED)
298 return error("short addressing mode forced but address is bigger than $3F");
302 // Mark it as a fixup
303 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
307 *memspace = 0 << 6; // Mark we're on X memory space
308 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
311 else if (*tok == '>')
313 // Long Addressing Mode Force Operator
316 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
318 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
321 if (*AnEXATTR&DEFINED)
323 if (*AnEXVAL > 0xFFFFFF)
324 return error("long address is bigger than $FFFFFF");
326 *memspace = 0 << 6; // Mark we're on X memory space
333 *memspace = 0 << 6; // Mark we're on X memory space
340 else if (*tok == SHL) // '<<'
342 // I/O Short Addressing Mode Force Operator
346 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
349 // If the symbol/expression is defined then check for valid range.
350 // Otherwise the value had better fit or Fixups will bark!
351 if (*AnEXATTR & DEFINED)
353 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
355 if (*AnEXVAL < 0xFFFFFFC0)
356 return error("I/O Short Addressing Mode addresses must be between $FFC0 and $FFFF");
360 *memspace = 0 << 6; // Mark we're on X memory space
361 *perspace = 0 << 16; // Mark we're on X peripheral space
362 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
366 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
368 // TODO: what if we need M_DSPAA here????
369 *memspace = 0 << 6; // Mark we're on X memory space
376 else if (*tok == KW_Y && *(tok + 1) == ':')
380 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
382 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
385 if (*AnEXVAL > 0xFFFFFF)
386 return error("long address is bigger than $FFFFFF");
388 *memspace = 1 << 6; // Mark we're on Y memory space
390 // Check if value is between $ffc0 and $ffff, AKA Y:pp
391 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
393 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
394 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
395 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
399 *perspace = 1 << 16; // Mark we're on X peripheral space
400 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
404 // If the symbol/expression is defined then check for valid range.
405 // Otherwise the value had better fit or Fixups will bark!
406 if (*AnEXATTR & DEFINED)
426 else if (*tok == '<')
429 // Short Addressing Mode Force Operator in the case of '<'
432 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
435 // If the symbol/expression is defined then check for valid range.
436 // Otherwise the value had better fit or Fixups will bark!
437 if (*AnEXATTR & DEFINED)
441 if (CHECK_OPTS(OPT_56K_AUTO_LONG))
444 warn("o11: short addressing mode forced but address is bigger than $3F - switching to long");
447 *memspace = 1 << 6; // Mark we're on Y memory space
453 return error("short addressing mode forced but address is bigger than $3F - turn opt switch o11 on to bypass");
459 // Mark it as a fixup
460 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
464 *memspace = 1 << 6; // Mark we're on Y memory space
465 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
468 else if (*tok == '>')
470 // Long Addressing Mode Force Operator
473 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
475 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
478 if (*AnEXATTR&DEFINED)
480 if (*AnEXVAL > 0xFFFFFF)
481 return error("long address is bigger than $FFFFFF");
483 *memspace = 1 << 6; // Mark we're on Y memory space
491 *memspace = 1 << 6; // Mark we're on Y memory space
498 else if (*tok == SHL) // '<<'
500 // I/O Short Addressing Mode Force Operator
504 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
507 // If the symbol/expression is defined then check for valid range.
508 // Otherwise the value had better fit or Fixups will bark!
509 if (*AnEXATTR & DEFINED)
511 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
513 if (*AnEXVAL < 0xFFFFFFC0)
514 return error("I/O Short Addressing Mode addresses must be between $FFE0 and $1F");
518 *memspace = 1 << 6; // Mark we're on Y memory space
519 *perspace = 1 << 16; // Mark we're on Y peripheral space
520 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
524 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
526 *memspace = 1 << 6; // Mark we're on Y memory space
532 // TODO: add absolute address checks
534 else if ((*tok >= KW_X) && (*tok <= KW_Y))
540 else if ((*tok >= KW_M0) && (*tok <= KW_M7))
543 *areg = (*tok++) & 7;
546 else if ((*tok >= KW_R0) && (*tok <= KW_R7))
549 *areg = (*tok++) - KW_R0;
552 else if ((*tok >= KW_N0) && (*tok <= KW_N7))
555 *areg = (*tok++) & 7;
558 else if ((*tok == KW_A0) || (*tok == KW_A1) || (*tok == KW_B0)
565 else if ((*tok == KW_A2) || (*tok == KW_B2))
571 else if ((*tok == '-') && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
573 // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
576 // Check to see if this is the first operand
578 return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
585 else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
587 // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
590 // Check to see if this is the first operand
592 return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
599 else if (*tok == '(' || *tok == '-')
601 // Could be either an expression or ea mode
602 if (*tok + 1 == SYMBOL)
606 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
613 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
621 // TODO: add absolute address checks
622 return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
624 else if (*tok == KW_P && *(tok + 1) == ':')
628 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
631 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
634 if (*AnEXVAL > 0xFFFFFF)
635 return error("long address is bigger than $FFFFFF");
644 *areg = (int)*AnEXVAL; // Lame, but what the hell
650 else if (*tok == '<')
653 // Short Addressing Mode Force Operator in the case of '<'
656 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
660 return error("short addressing mode forced but address is bigger than $3F");
663 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
666 else if (*tok == '>')
668 // Long Addressing Mode Force Operator
671 // Immediate Short Addressing Mode Force Operator
672 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
675 if (*AnEXATTR & DEFINED)
677 if (*AnEXVAL > 0xFFFFFF)
678 return error("long address is bigger than $FFFFFF");
686 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
694 else if (*tok == SHL)
696 // I/O Short Addressing Mode Force Operator
699 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
702 if (*AnEXVAL > 0xFFF)
703 return error("I/O short addressing mode forced but address is bigger than $FFF");
708 else if (*tok == '<')
710 // Short Addressing Mode Force Operator
713 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
716 if (*AnEXATTR & DEFINED)
718 if (*AnEXVAL > 0xFFF)
719 return error("short addressing mode forced but address is bigger than $FFF");
725 else if (*tok == '>')
727 // Long Addressing Mode Force Operator
730 // Immediate Short Addressing Mode Force Operator
731 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
734 if (*AnEXATTR & DEFINED)
736 if (*AnEXVAL > 0xFFFFFF)
737 return error("long address is bigger than $FFFFFF");
744 else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
753 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
756 // We'll store M_DSPEA_ABS in areg and if we have
757 // any extra info, it'll go in am
758 if (*AnEXATTR & DEFINED)
762 if (*AnEXVAL < 0x1000)
764 else if (*AnEXVAL < 0x10000)
766 else if (*AnEXVAL < 0x1000000)
769 return error("address must be smaller than $1000000");
775 // Well, we have no opinion on the expression's size, so let's assume the worst
782 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
787 // Parse all addressing modes except parallel moves
789 int dsp_amode(int maxea)
792 // Initialize global return values
793 nmodes = dsp_a0reg = dsp_a1reg = 0;
794 dsp_am0 = dsp_am1 = M_AM_NONE;
795 dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
798 dsp_a0exattr = dsp_a1exattr = 0;
799 dsp_a0esym = dsp_a1esym = (SYM *)NULL;
800 dsp_a0memspace = dsp_a1memspace = -1;
801 dsp_a0perspace = dsp_a1perspace = -1;
804 // If at EOL, then no addr modes at all
808 if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
812 // If caller wants only one mode, return just one (ignore comma);
813 // If there is no second addressing mode (no comma), then return just one anyway.
819 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
827 // Parse second addressing mode
828 if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
831 if (maxea == 2 || *tok == EOL)
834 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
842 // Only MAC-like or jsset/clr/tst/chg instructions here
844 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
849 return error(extra_stuff);
855 // Only Tcc instructions here, and then only those that accept 4 operands
857 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
861 return error("expected 4 parameters");
863 if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
869 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
876 // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
877 return error(extra_stuff);
880 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
885 // Helper function which gives us the encoding of a DSP register
887 static inline int SDreg(int reg)
889 if (reg >= KW_X0 && reg <= KW_N7)
891 else if (reg >= KW_A0&® <= KW_A2)
892 return (8 >> (reg & 7)) | 8;
893 else //if (reg>=KW_R0&®<=KW_R7)
894 return reg - KW_R0 + 16;
895 // Handy map for the above:
896 // (values are of course taken from keytab)
897 // Register | Value | Return value
930 // Check for X:Y: parallel mode syntax
932 static inline LONG check_x_y(LONG ea1, LONG S1)
935 LONG eax_temp, eay_temp;
936 LONG D1, D2, S2, ea2;
938 LONG w = 1 << 7; // S1=0, D1=1<<14
940 if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
941 (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
945 case DSP_EA_POSTINC: ea1 = (ea1 & (~0x38)) | 0x8; break;
946 case DSP_EA_POSTINC1: ea1 = (ea1 & (~0x38)) | 0x18; break;
947 case DSP_EA_POSTDEC1: ea1 = (ea1 & (~0x38)) | 0x10; break;
948 case DSP_EA_NOUPD: ea1 = (ea1 & (~0x38)) | 0x00; break;
953 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
955 switch (K_D1 = *tok++)
957 case KW_X0: D1 = 0 << 10; break;
958 case KW_X1: D1 = 1 << 10; break;
959 case KW_A: D1 = 2 << 10; break;
960 case KW_B: D1 = 3 << 10; break;
961 default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
966 // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
971 case 4: D1 = 0 << 10; break;
972 case 5: D1 = 1 << 10; break;
973 case 14: D1 = 2 << 10; break;
974 case 15: D1 = 3 << 10; break;
975 default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
982 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
984 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
988 if (*tok >= KW_R0 && *tok <= KW_R7)
990 ea2 = (*tok++ - KW_R0);
992 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
993 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'");
996 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
998 // If eax register is r0-r3 then eay register is r4-r7.
999 // Encode that to 2 bits (i.e. eay value is 0-3)
1000 eax_temp = (ea2 & 3) << 5; // Store register temporarily
1003 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
1015 else if (*tok >= KW_N0 && *tok <= KW_N7)
1018 if ((*tok++ & 7) != ea2)
1019 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')");
1024 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
1027 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
1030 else if (*tok == '-')
1037 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
1039 else if (*tok++ == ',')
1045 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
1047 ea2 |= eax_temp; // OR eay back from temp
1049 switch (K_D2 = *tok++)
1051 case KW_Y0: D2 = 0 << 8; break;
1052 case KW_Y1: D2 = 1 << 8; break;
1053 case KW_A: D2 = 2 << 8; break;
1054 case KW_B: D2 = 3 << 8; break;
1055 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1059 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
1063 return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
1065 inst = B16(11000000, 00000000) | w;
1066 inst |= ea1 | D1 | ea2 | D2;
1070 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1072 else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1074 // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1077 case KW_Y0: S2 = 0 << 8; break;
1078 case KW_Y1: S2 = 1 << 8; break;
1079 case KW_A: S2 = 2 << 8; break;
1080 case KW_B: S2 = 3 << 8; break;
1081 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1085 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1089 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1091 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1095 if (*tok >= KW_R0 && *tok <= KW_R7)
1097 ea2 = (*tok++ - KW_R0);
1099 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
1100 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'");
1103 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
1104 // If eax register is r0-r3 then eay register is r4-r7.
1105 // Encode that to 2 bits (i.e. eay value is 0-3)
1106 eay_temp = (ea2 & 3) << 5; //Store register temporarily
1109 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1118 else if (*tok >= KW_N0 && *tok <= KW_N7)
1121 if ((*tok++ & 7) != ea2)
1122 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')");
1127 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1130 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1133 else if (*tok == '-')
1139 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1141 else if (*tok == EOL)
1147 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1149 ea2 |= eay_temp; //OR eay back from temp
1151 inst = B16(10000000, 00000000) | w;
1152 inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1156 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1159 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1162 return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
1165 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1169 // Parse X: addressing space parallel moves
1171 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1173 int immreg; // Immediate register destination
1174 LONG S2, D1, D2; // Source and Destinations
1175 LONG ea1; // ea bitfields
1176 uint32_t termchar = ','; // Termination character for ea checks
1177 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1178 ea1 = -1; // initialise e1 (useful for some code paths)
1185 if (tok[1] == CONST || tok[1] == FCONST)
1188 dspImmedEXVAL = *tok++;
1192 // This could be either -(Rn), -aa or -ea. Check for immediate first
1193 if (tok[1] == SYMBOL)
1195 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1200 // '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'
1201 if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
1204 if (ea1 == DSP_EA_ABS)
1205 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1208 return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1211 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
1213 if (ea1 == B8(00110100))
1214 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
1216 inst = B16(00001000, 00000000) | ea1 | (0 << 8);
1219 else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1222 if (ea1 == DSP_EA_ABS)
1223 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1226 return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1229 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
1231 if (ea1 == B8(00110100))
1232 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
1234 inst = B16(00001001, 00000000) | ea1 | (1 << 8);
1237 else if (*tok == KW_A || *tok == KW_B)
1239 // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1242 case 4: D1 = 0 << 10; break;
1243 case 5: D1 = 1 << 10; break;
1244 case 14: D1 = 2 << 10; break;
1245 case 15: D1 = 3 << 10; break;
1246 default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
1249 if (tok[1] == ',' && tok[2] == KW_Y)
1251 // 'S1,X:eax S2,Y:eay'
1252 return check_x_y(ea1, S1);
1256 if (ea1 == DSP_EA_ABS)
1257 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1261 case KW_A: S2 = 0 << 9; break;
1262 case KW_B: S2 = 1 << 9; break;
1263 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
1267 return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1269 if (*tok == KW_Y0 || *tok == KW_Y1)
1271 if (*tok++ == KW_Y0)
1277 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1279 inst = B16(00010000, 00000000) | (0 << 7);
1280 inst |= ea1 | D1 | S2 | D2;
1284 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1286 else if (*tok == KW_Y)
1288 // 'S1,X:eax Y:eay,D2'
1289 return check_x_y(ea1, S1);
1291 else if (*tok == KW_Y0 || *tok == KW_Y1)
1293 // 'S1,X:eax S2,Y:eay'
1294 return check_x_y(ea1, S1);
1297 return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1301 // Only check for aa if we have a defined number in our hands or we've
1302 // been asked to use a short number format. The former case we'll just test
1303 // it to see if it's small enough. The later - it's the programmer's call
1304 // so he'd better have a small address or the fixups will bite him/her in the arse!
1305 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1308 // It's an immediate, so ea or eax is probably an absolute address
1309 // (unless it's aa if the immediate is small enough)
1310 // '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'
1312 // Check for aa (which is 6 bits zero extended)
1313 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1317 // It might be X:aa but we're not 100% sure yet.
1318 // If it is, the only possible syntax here is 'X:aa,D'.
1319 // So check ahead to see if EOL follows D, then we're good to go.
1320 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)
1322 // Yup, we're good to go - 'X:aa,D' it is
1324 immreg = SDreg(*tok++);
1325 inst = inst | (uint32_t)dspImmedEXVAL;
1326 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1327 inst |= 1 << 7; // W
1336 inst = inst | (uint32_t)dspImmedEXVAL;
1337 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1342 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1343 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1345 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1346 goto x_checkea_right;
1352 // Well, that settles it - we do have an ea in our hands
1355 // 'X:ea,D' [... S2,d2]
1357 return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
1359 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1366 inst = inst | B8(01000000) | (1 << 7);
1367 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1370 if (ea1 == DSP_EA_ABS)
1371 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1378 if (*tok == KW_A || *tok == KW_B)
1383 return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1385 if (*tok == KW_Y0 || *tok == KW_Y1)
1390 return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
1392 inst = B16(00010000, 00000000) | (1 << 7);
1393 inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
1394 inst |= (S2 & 1) << 9;
1395 inst |= (D2 & 1) << 8;
1400 return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1403 return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1407 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,'");
1414 inst = inst | B8(01000000) | (0 << 7);
1415 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1418 if (ea1 == DSP_EA_ABS)
1419 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1425 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1426 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1427 goto x_checkea_right;
1436 // It's not an immediate, check for '-(Rn)'
1437 ea1 = checkea(termchar, X_ERRORS);
1446 else if (*tok == '#')
1450 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1453 // Okay so we have immediate data - mark it down
1455 // Now, proceed to the main code for this branch
1458 else if (*tok == '(')
1460 // Maybe we got an expression here, check for it
1461 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1463 // Evaluate the expression and go to immediate code path
1464 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1468 // Nope, let's check for ea then
1469 ea1 = checkea(termchar, X_ERRORS);
1478 return error("Comma expected after 'X:(Rn)')");
1480 // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
1481 // If it is, the only possible syntax here is 'X:ea,D'.
1482 // So check ahead to see if EOL follows D, then we're good to go.
1483 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1488 inst = inst | B8(01000000) | (1 << 7);
1490 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1499 inst = inst | B8(01000000) | (0 << 7);
1501 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1506 goto x_checkea_right;
1510 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
1511 // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
1512 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)))
1515 // Check if D1 is x0, x1, a or b
1518 case KW_X0: D1 = 0 << 10; break;
1519 case KW_X1: D1 = 1 << 10; break;
1520 case KW_A: D1 = 2 << 10; break;
1521 case KW_B: D1 = 3 << 10; break;
1522 default: return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
1527 case KW_A: S2 = 0 << 9; break;
1528 case KW_B: S2 = 1 << 9; break;
1529 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
1533 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1535 if (*tok == KW_Y0 || *tok == KW_Y1)
1537 if (*tok++ == KW_Y0)
1543 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1545 inst = B16(00010000, 00000000) | (W << 7);
1546 inst |= ea1 | D1 | S2 | D2;
1550 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1553 // Check to see if we got eax (which is a subset of ea)
1556 if ((inst = check_x_y(ea1, 0)) != 0)
1560 // Rewind pointer as it might be an expression and check for it
1563 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1566 // Yes, we have an expression, so we now check for
1567 // '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'
1572 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1574 // Check for immediate address
1575 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1578 // We set ea1 here - if it's aa instead of ea
1579 // then it won't be used anyway
1582 if (!(dspImmedEXATTR&DEFINED))
1584 force_imm = NUM_FORCE_LONG;
1585 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1590 else if (*tok == '>')
1592 // Check for immediate address forced long
1595 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1598 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
1599 return error("long address is bigger than $FFFFFF");
1601 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1603 force_imm = NUM_FORCE_LONG;
1607 else if (*tok == '<')
1609 // Check for immediate address forced short
1612 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1615 force_imm = NUM_FORCE_SHORT;
1617 if (dspImmedEXATTR & DEFINED)
1619 if (dspImmedEXVAL > 0x3F)
1621 if (CHECK_OPTS(OPT_56K_AUTO_LONG))
1623 if (optim_warn_flag)
1624 warn("o11: short addressing mode forced but address is bigger than $3F - switching to long");
1626 force_imm = NUM_FORCE_LONG;
1627 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1632 return error("short addressing mode forced but address is bigger than $3F - turn opt switch o11 on to bypass");
1638 // This might end up as something like 'move Y:<adr,register'
1639 // so let's mark it as an extra aa fixup here.
1640 // Note: we are branching to x_check_immed without a
1641 // defined dspImmed so it's going to be 0. It probably
1642 // doesn't harm anything.
1643 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1649 return error("unknown x: addressing mode");
1654 // Parse Y: addressing space parallel moves
1656 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1658 int immreg; // Immediate register destination
1659 LONG D2; // Destination
1660 LONG ea1; // ea bitfields
1661 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1664 if (tok[1] == CONST || tok[1] == FCONST)
1667 dspImmedEXVAL = *tok++;
1670 // This could be either -(Rn), -aa or -ea. Check for immediate first
1671 if (*tok == SYMBOL || tok[1] == SYMBOL)
1673 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1675 // Only check for aa if we have a defined number in our hands or we've
1676 // been asked to use a short number format. The former case we'll just test
1677 // it to see if it's small enough. The later - it's the programmer's call
1678 // so he'd better have a small address or the fixups will bite him/her in the arse!
1679 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1681 // It's an immediate, so ea is probably an absolute address
1682 // (unless it's aa if the immediate is small enough)
1683 // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
1685 // Check for aa (which is 6 bits zero extended)
1686 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1688 // It might be Y:aa but we're not 100% sure yet.
1689 // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
1690 // So check ahead to see if EOL follows D, then we're good to go.
1691 if (*tok == EOL && S1 != 0)
1694 inst = B16(01001000, 00000000);
1695 inst |= dspImmedEXVAL;
1696 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1700 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)
1702 // Yup, we're good to go - 'Y:aa,D' it is
1704 immreg = SDreg(*tok++);
1705 inst |= dspImmedEXVAL;
1706 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1711 // Well, that settles it - we do have a ea in our hands
1712 if (*tok == EOL && S1 != 0)
1715 inst = B16(01001000, 01110000);
1717 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1718 if (ea1 == DSP_EA_ABS)
1719 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1724 return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1726 if (D1 == 0 && S1 == 0)
1729 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1734 return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1736 inst |= B16(00000000, 01110000);
1738 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1739 if (ea1 == DSP_EA_ABS)
1740 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1744 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,'");
1749 if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1754 inst |= (S1 & 1) << 11;
1755 inst |= (D1 & 1) << 10;
1756 inst |= (D2 & 8) << (9 - 3);
1757 inst |= (D2 & 1) << 8;
1761 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1769 // It's not an immediate, check for '-(Rn)'
1770 ea1 = checkea(',', Y_ERRORS);
1779 else if (*tok == '#')
1783 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1786 // Okay so we have immediate data - mark it down
1788 // Now, proceed to the main code for this branch
1791 else if (*tok == '(')
1793 // Maybe we got an expression here, check for it
1794 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1796 // Evaluate the expression and go to immediate code path
1797 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1801 // Nope, let's check for ea then
1802 if (S1 == 0 || (S1 != 0 && D1 != 0))
1803 ea1 = checkea(',', Y_ERRORS);
1805 ea1 = checkea(EOL, Y_ERRORS);
1811 if (S1 != 0 && *tok == EOL)
1814 inst = B16(01001000, 01000000);
1816 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1819 else if (S1 != 0 && D1 != 0 && S2 == 0)
1824 case 14: S1 = 0 << 11; break; // A
1825 case 15: S1 = 1 << 11; break; // B
1826 default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
1831 case 4: D1 = 0 << 10; break; // X0
1832 case 5: D1 = 1 << 10; break; // X1
1833 default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
1837 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1841 case KW_Y0: D2 = 0 << 8; break;
1842 case KW_Y1: D2 = 1 << 8; break;
1843 case KW_A: D2 = 2 << 8; break;
1844 case KW_B: D2 = 3 << 8; break;
1845 default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
1848 inst = B16(00010000, 11000000);
1849 inst |= S1 | D1 | D2;
1855 return error("Comma expected after 'Y:(Rn)')");
1857 // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
1858 // If it is, the only possible syntax here is 'Y:ea,D'.
1859 // So check ahead to see if EOL follows D, then we're good to go.
1860 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1864 inst |= B16(00000000, 01000000);
1866 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1870 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1872 // Check for immediate address
1873 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1876 // Yes, we have an expression, so we now check for
1877 // 'Y:ea,D' or 'Y:aa,D'
1878 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1880 if (!(dspImmedEXATTR&DEFINED))
1882 force_imm = NUM_FORCE_LONG;
1883 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1888 else if (*tok == '>')
1890 // Check for immediate address forced long
1893 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1896 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
1897 return error("long address is bigger than $FFFFFF");
1899 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1901 force_imm = NUM_FORCE_LONG;
1905 else if (*tok == '<')
1909 if (S1 != 0 && D1 != 0)
1911 // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
1912 // there's no Y:aa mode here, so we'll force long
1913 if (CHECK_OPTS(OPT_56K_AUTO_LONG))
1915 if (optim_warn_flag)
1916 warn("forced short addressing in R:Y mode is not allowed - switching to long");
1918 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1923 force_imm = NUM_FORCE_LONG;
1924 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1929 return error("forced short addressing in R:Y mode is not allowed - turn opt switch o11 on to bypass");
1934 // Check for immediate address forced short
1935 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1937 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1940 force_imm = NUM_FORCE_SHORT;
1942 if (dspImmedEXATTR & DEFINED)
1944 if (dspImmedEXVAL > 0xFFF)
1946 if (CHECK_OPTS(OPT_56K_AUTO_LONG))
1948 if (optim_warn_flag)
1949 warn("short addressing mode forced but address is bigger than $FFF - switching to long");
1952 force_imm = NUM_FORCE_LONG;
1953 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1957 return error("short addressing mode forced but address is bigger than $FFF - turn opt switch o11 on to bypass");
1963 // This might end up as something like 'move Y:<adr,register'
1964 // so let's mark it as an extra aa fixup here.
1965 // Note: we are branching to y_check_immed without a
1966 // defined dspImmed so it's going to be 0. It probably
1967 // doesn't harm anything.
1968 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1975 return error("unrecognised Y: parallel move syntax");
1980 // Parse L: addressing space parallel moves
1982 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1984 int immreg; // Immediate register destination
1985 LONG D1; // Source and Destinations
1986 LONG ea1; // ea bitfields
1987 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1991 if (*tok == CONST || tok[1] == FCONST)
1994 dspImmedEXVAL = *tok++;
1998 // This could be either -(Rn), -aa or -ea. Check for immediate first
1999 // Maybe we got an expression here, check for it
2000 if (*tok == SYMBOL || tok[1] == SYMBOL)
2002 // Evaluate the expression and go to immediate code path
2003 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
2005 // Only check for aa if we have a defined number in our hands
2006 // or we've been asked to use a short number format. The
2007 // former case we'll just test it to see if it's small enough.
2008 // The later - it's the programmer's call so he'd better have
2009 // a small address or the fixups will bite him/her in the arse!
2010 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
2012 // It's an immediate, so ea is probably an absolute address
2013 // (unless it's aa if the immediate is small enough)
2014 // 'L:ea,D' or 'L:aa,D'
2016 // Check for aa (which is 6 bits zero extended)
2020 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
2025 else if (S1 == KW_B)
2030 inst = B16(01000000, 00000000);
2031 inst |= dspImmedEXVAL;
2032 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2040 else if (S1 == KW_B)
2045 if (ea1 == DSP_EA_ABS)
2046 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2048 inst |= B16(01000000, 01110000);
2049 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2057 return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
2059 // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
2060 if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
2061 return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
2063 if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
2071 else if (immreg == KW_B)
2077 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
2079 inst &= B16(11111111, 10111111);
2080 inst |= dspImmedEXVAL;
2081 inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
2086 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
2088 // Hang on, we've got a L:<aa here, let's do that instead
2092 // Well, that settles it - we do have a ea in our hands
2098 else if (D1 == KW_B)
2104 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
2106 inst |= B16(00000000, 00110000);
2107 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2113 //It's not an immediate, check for '-(Rn)'
2114 ea1 = checkea(',', L_ERRORS);
2123 else if (*tok == '(')
2125 // Maybe we got an expression here, check for it
2126 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
2128 // Evaluate the expression and go to immediate code path
2129 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
2133 //Nope, let's check for ea then
2135 ea1 = checkea(',', L_ERRORS);
2137 ea1 = checkea(EOL, L_ERRORS);
2146 inst = B16(01000000, 01000000);
2150 else if (S1 == KW_B)
2156 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2159 else if (*tok++ != ',')
2160 return error("Comma expected after 'L:(Rn)')");
2162 // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
2163 // If it is, the only possible syntax here is 'L:ea,D'.
2164 // So check ahead to see if EOL follows D, then we're good to go.
2165 if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
2172 else if (D1 == KW_B)
2178 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2182 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2184 // Check for immediate address
2185 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2188 // We set ea1 here - if it's aa instead of ea
2189 // then it won't be used anyway
2192 if (!(dspImmedEXATTR & DEFINED))
2194 force_imm = NUM_FORCE_LONG;
2195 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2197 else if (dspImmedEXVAL > 0x3f)
2199 // Definitely no aa material, so it's going to be a long
2200 // Mark that we need to deposit an extra word
2201 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2204 // Yes, we have an expression, so we now check for
2205 // 'L:ea,D' or 'L:aa,D'
2208 else if (*tok == '>')
2210 // Check for immediate address forced long
2213 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2216 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
2217 return error("long address is bigger than $FFFFFF");
2219 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2221 force_imm = NUM_FORCE_LONG;
2224 else if (*tok == '<')
2226 // Check for immediate address forced short
2229 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2232 if (dspImmedEXATTR & DEFINED)
2234 if (dspImmedEXVAL > 0xFFF)
2235 return error("short addressing mode forced but address is bigger than $FFF");
2239 // This might end up as something like 'move Y:<adr,register'
2240 // so let's mark it as an extra aa fixup here.
2241 // Note: we are branching to l_check_immed without a
2242 // defined dspImmed so it's going to be 0. It probably
2243 // doesn't harm anything.
2244 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
2247 force_imm = NUM_FORCE_SHORT;
2251 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");
2256 // Checks for all ea cases where indexed addressing is concenred
2258 static inline LONG checkea(const uint32_t termchar, const int strings)
2268 return error(ea_errors[strings][0]);
2270 if (*tok >= KW_R0 && *tok <= KW_R7)
2272 // We got '-(Rn' so mark it down
2273 ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2276 return error(ea_errors[strings][1]);
2278 // Now, proceed to the main code for this branch
2282 return error(ea_errors[strings][2]);
2284 else if (*tok == '(')
2286 // Checking for ea of type (Rn)
2289 if (*tok >= KW_R0 && *tok <= KW_R7)
2291 // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2292 ea = *tok++ - KW_R0;
2299 if (*tok < KW_N0 || *tok > KW_N7)
2300 return error(ea_errors[strings][3]);
2302 if ((*tok++ & 7) != ea)
2303 return error(ea_errors[strings][4]);
2308 return error(ea_errors[strings][5]);
2312 else if (*tok == ')')
2314 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2321 if (termchar == ',')
2326 ea |= DSP_EA_POSTINC1;
2329 else if (*tok >= KW_N0 && *tok <= KW_N7)
2332 if ((*tok++ & 7) != ea)
2333 return error(ea_errors[strings][6]);
2335 ea |= DSP_EA_POSTINC;
2339 return error(ea_errors[strings][7]);
2343 if (*tok >= KW_N0 && *tok <= KW_N7)
2346 if ((*tok++ & 7) != ea)
2347 return error(ea_errors[strings][6]);
2349 ea |= DSP_EA_POSTINC;
2355 ea |= DSP_EA_POSTINC1;
2360 else if (*tok == '-')
2364 if (termchar == ',')
2369 ea |= DSP_EA_POSTDEC1;
2372 else if (*tok >= KW_N0 && *tok <= KW_N7)
2375 if ((*tok++ & 7) != ea)
2376 return error(ea_errors[strings][8]);
2378 ea |= DSP_EA_POSTDEC;
2382 return error(ea_errors[strings][9]);
2386 if (*tok >= KW_N0 && *tok <= KW_N7)
2389 if ((*tok++ & 7) != ea)
2390 return error(ea_errors[strings][8]);
2392 ea |= DSP_EA_POSTDEC;
2398 ea |= DSP_EA_POSTDEC1;
2403 else if (termchar == ',')
2412 return error(ea_errors[strings][10]);
2422 return error(ea_errors[strings][11]);
2426 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");
2431 // Checks for all ea cases, i.e. all addressing modes that checkea handles
2432 // plus immediate addresses included forced short/long ones.
2433 // In other words this is a superset of checkea (and in fact calls checkea).
2435 LONG checkea_full(const uint32_t termchar, const int strings)
2439 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2441 // Check for immediate address
2442 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2445 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2447 // Yes, we have an expression
2450 else if (*tok == '>')
2452 // Check for immediate address forced long
2455 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2458 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
2459 return error("long address is bigger than $FFFFFF");
2461 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2463 // Yes, we have an expression
2466 else if (*tok == '<')
2468 // Check for immediate address forced short
2471 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2474 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFF))
2475 return error("short addressing mode forced but address is bigger than $FFF");
2477 // Yes, we have an expression
2482 ea1 = checkea(termchar, strings);
2494 // Main routine to check parallel move modes.
2495 // It's quite complex so it's split into a few procedures (in fact most of the
2496 // above ones). A big effort was made so this can be managable and not too
2497 // hacky, however one look at the 56001 manual regarding parallel moves and
2498 // you'll know that this is not an easy // problem to deal with!
2499 // dest=destination register from the main opcode. This must not be the same
2500 // as D1 or D2 and that even goes for stuff like dest=A, D1=A0/1/2!!!
2502 LONG parmoves(WORD dest)
2504 int force_imm; // Addressing mode force operator
2505 int immreg; // Immediate register destination
2506 LONG inst; // 16 bit bitfield that has the parallel move opcode
2507 LONG S1, S2, D1, D2; // Source and Destinations
2508 LONG ea1; // ea bitfields
2513 return B16(00100000, 00000000);
2518 // '#xxxxxx,D', '#xx,D'
2520 force_imm = NUM_NORMAL;
2524 force_imm = NUM_FORCE_LONG;
2527 else if (*tok == '<')
2529 force_imm = NUM_FORCE_SHORT;
2533 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2537 return error("expected comma");
2539 if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
2540 return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
2542 immreg = SDreg(*tok++);
2546 if (!(dspImmedEXATTR & FLOAT))
2548 if (dspImmedEXATTR & DEFINED)
2550 // From I parallel move:
2551 // "If the destination register D is X0, X1, Y0, Y1, A, or
2552 // B, the 8-bit immediate short operand is interpreted as
2553 // a signed fraction and is stored in the specified
2554 // destination register. That is, the 8 - bit data is
2555 // stored in the eight MS bits of the destination operand,
2556 // and the remaining bits of the destination operand D are
2558 // The funny bit is that Motorola assembler can parse
2559 // something like 'move #$FF0000,b' into an I (immediate
2560 // short move) - so let's do that as well then...
2561 if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
2563 if ((dspImmedEXVAL & 0xFFFF) == 0)
2565 dspImmedEXVAL >>= 16;
2569 if (force_imm == NUM_FORCE_SHORT)
2571 if (dspImmedEXVAL < 0xFF && (int32_t)dspImmedEXVAL > -0x100)
2574 // value fits in 8 bits - immediate move
2575 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2580 if (CHECK_OPTS(OPT_56K_AUTO_LONG))
2582 if (optim_warn_flag)
2583 warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2584 force_imm = NUM_FORCE_LONG;
2588 return error("forced short immediate value doesn't fit in 8 bits - turn opt switch o11 on to bypass");
2593 if (force_imm == NUM_FORCE_LONG)
2597 // X or Y Data move. I don't think it matters much
2598 // which of the two it will be, so let's use X.
2599 deposit_immediate_long_with_register:
2600 inst = B16(01000000, 11110100);
2601 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2602 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2606 if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2608 // value fits in 8 bits - immediate move
2609 deposit_immediate_short_with_register:
2610 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2615 // value doesn't fit in 8 bits, so it can either be
2616 // X or Y Data move. I don't think it matters much
2617 // which of the two it will be, so let's use X:.
2618 // TODO: if we're just goto'ing perhaps the logic can be simplified
2619 goto deposit_immediate_long_with_register;
2624 if (force_imm != NUM_FORCE_SHORT)
2627 // TODO: if we're just goto'ing perhaps the logic can be simplified
2628 goto deposit_immediate_long_with_register;
2633 // No visibility of the number so let's add a fixup for this
2634 AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
2635 inst = B16(00100000, 00000000);
2636 inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
2644 if (dspImmedEXATTR & DEFINED)
2646 double f = *(double *)&dspImmedEXVAL;
2647 // Check direct.c for ossom comments regarding conversion!
2648 //N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
2649 dspImmedEXVAL = ((uint32_t)(int32_t)round(f * (1 << 23))) & 0xFFFFFF;
2654 if ((dspImmedEXVAL & 0xFFFF) == 0)
2656 if (CHECK_OPTS(OPT_56K_SHORT))
2658 // Value's 16 lower bits are not set so the value can
2659 // fit in a single byte (check parallel I move quoted
2661 if (optim_warn_flag)
2662 warn("o10: Immediate value fits inside 8 bits, so using instruction short format");
2664 dspImmedEXVAL >>= 16;
2665 goto deposit_immediate_short_with_register;
2669 return error("Immediate value fits inside 8 bits, so using instruction short format - turn opt switch o10 on to bypass");
2673 if (force_imm == NUM_FORCE_SHORT)
2675 if ((dspImmedEXVAL & 0xFFFF) != 0)
2677 if (CHECK_OPTS(OPT_56K_AUTO_LONG))
2679 if (optim_warn_flag)
2680 warn("o11: Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
2682 goto deposit_immediate_long_with_register;
2686 return error("Immediate value short format forced but value does not fit inside 8 bits - turn opt switch o11 on to bypass");
2690 return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2693 // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
2694 goto deposit_immediate_long_with_register;
2698 if (force_imm == NUM_FORCE_SHORT)
2700 goto deposit_immediate_short_with_register;
2704 // Just deposit a float fixup
2705 AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
2706 inst = B16(00100000, 00000000);
2707 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2715 // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2718 case 4: D1 = 0 << 10;break; // X0
2719 case 5: D1 = 1 << 10;break; // X1
2720 case 14: D1 = 2 << 10;break; // A
2721 case 15: D1 = 3 << 10;break; // B
2722 default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
2727 case KW_A: S2 = 0 << 9; break;
2728 case KW_B: S2 = 1 << 9; break;
2729 default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
2733 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2737 case KW_Y0: D2 = 0 << 8; break;
2738 case KW_Y1: D2 = 1 << 8; break;
2739 default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
2743 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2745 inst = B16(00010000, 10110100) | D1 | S2 | D2;
2746 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2750 else if (*tok == KW_X)
2753 // Hey look, it's just the register X and not the addressing mode - fall through to general case
2754 goto parse_everything_else;
2759 return error("expected ':' after 'X' in parallel move (i.e. X:)");
2761 // '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'
2762 return parse_x(1, B16(01000000, 00000000), 0, 1);
2764 else if (*tok == KW_Y)
2767 // Hey look, it's just the register y and not the addressing mode - fall through to general case
2768 goto parse_everything_else;
2773 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2775 // 'Y:ea,D' or 'Y:aa,D'
2776 return parse_y(B16(01001000, 10000000), 0, 0, 0);
2778 else if (*tok == KW_L)
2780 // 'L:ea,D' or 'L:aa,D'
2783 return error("expected ':' after 'L' in parallel move (i.e. L:)");
2785 return parse_l(1, B16(01000000, 11000000), 0);
2787 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))
2789 // Everything else - brace for impact!
2791 // X: 'S,X:ea' 'S,X:aa'
2792 // X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
2793 // Y: 'S,Y:ea' 'S,Y:aa'
2794 // 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'
2795 // L: 'S,L:ea' 'S,L:aa'
2797 parse_everything_else:
2802 return error("Comma expected after 'S')");
2806 // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
2807 // 'A,X:ea X0,A' 'B,X:ea X0,B'
2811 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2813 return parse_x(0, B16(01000000, 00000000), S1, 1);
2815 else if (*tok == KW_Y)
2817 // 'S,Y:ea' 'S,Y:aa'
2821 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2823 return parse_y(B16(0000000, 00000000), S1, 0, 0);
2825 else if (*tok == KW_L)
2827 // 'S,L:ea' 'S,L:aa'
2831 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2833 return parse_l(1, B16(00000000, 00000000), L_S1);
2835 else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2838 // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
2839 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2845 inst = B16(00100000, 00000000);
2846 inst |= (S1 << 5) | (D1);
2849 else if (*tok == KW_Y)
2854 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2855 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2858 else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2860 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2863 if (S1 == 6 && D1 == 14 && S2 == 14)
2867 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2870 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2873 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2875 ea1 = checkea_full(EOL, Y_ERRORS);
2880 inst = B16(00001000, 10000000);
2885 else if (S1 == 6 && D1 == 15 && S2 == 15)
2889 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2892 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2895 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2897 ea1 = checkea_full(EOL, Y_ERRORS);
2902 inst = B16(00001000, 10000000);
2907 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2911 return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2914 return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2917 return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2919 ea1 = checkea_full(EOL, Y_ERRORS);
2924 inst = B16(00010000, 01000000);
2925 inst |= (S1 & 1) << 11;
2926 inst |= (D1 & 1) << 10;
2927 inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2932 return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2935 else if (*tok == '#')
2937 // R:Y: 'S1,D1 #xxxxxx,D2'
2942 // Well, forcing an immediate to be 24 bits is legal here
2943 // but then it's the only available option so my guess is that this
2944 // is simply superfluous. So let's just eat the character
2948 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2951 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
2952 return error("immediate is bigger than $FFFFFF");
2954 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2957 return error("Comma expected after 'S1,D1 #xxxxxx')");
2959 // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
2962 case KW_Y0: D2 = 0 << 8; break;
2963 case KW_Y1: D2 = 1 << 8; break;
2964 case KW_A: D2 = 2 << 8; break;
2965 case KW_B: D2 = 3 << 8; break;
2966 default: return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
2969 if (S1 == 14 || S1 == 15)
2971 if (D1 == 4 || D1 == 5)
2973 inst = B16(00010000, 11110100);
2974 inst |= (S1 & 1) << 11;
2975 inst |= (D1 & 1) << 10;
2977 dspImmedEXVAL = dspaaEXVAL;
2981 return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2984 return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2987 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2990 return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2992 else if (*tok == '(')
2995 // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2998 if (*tok >= KW_R0 && *tok <= KW_R7)
3000 ea1 = (*tok++ - KW_R0);
3003 return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
3006 return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
3015 else if (*tok >= KW_N0 && *tok <= KW_N7)
3018 if ((*tok++ & 7) != ea1)
3019 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
3024 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
3027 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
3029 else if (*tok == '-')
3039 else if (*tok >= KW_N0 && *tok <= KW_N7)
3042 if ((*tok++ & 7) != ea1)
3043 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
3048 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
3052 inst = B16(00100000, 01000000);
3057 return error("extra (unexpected) text found");