2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // AMODE.C - DSP 56001 Addressing Modes
4 // Copyright (C) 199x Landon Dyer, 2011-2020 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 nmodes; // Number of addr'ing modes found
25 int dsp_am0; // Addressing mode
26 int dsp_a0reg; // Register
27 TOKEN dsp_a0expr[EXPRSIZE]; // Expression
28 uint64_t dsp_a0exval; // Expression's value
29 WORD dsp_a0exattr; // Expression's attribute
30 LONG dsp_a0memspace; // Addressing mode's memory space (P, X, Y)
31 SYM * dsp_a0esym; // External symbol involved in expr
33 int dsp_am1; // Addressing mode
34 int dsp_a1reg; // Register
35 TOKEN dsp_a1expr[EXPRSIZE]; // Expression
36 uint64_t dsp_a1exval; // Expression's value
37 WORD dsp_a1exattr; // Expression's attribute
38 LONG dsp_a1memspace; // Addressing mode's memory space (P, X, Y)
39 SYM * dsp_a1esym; // External symbol involved in expr
41 int dsp_am2; // Addressing mode
42 int dsp_a2reg; // Register
43 TOKEN dsp_a2expr[EXPRSIZE]; // Expression
44 uint64_t dsp_a2exval; // Expression's value
45 WORD dsp_a2exattr; // Expression's attribute
46 SYM * dsp_a2esym; // External symbol involved in expr
48 int dsp_am3; // Addressing mode
49 int dsp_a3reg; // Register
50 TOKEN dsp_a3expr[EXPRSIZE]; // Expression
51 uint64_t dsp_a3exval; // Expression's value
52 WORD dsp_a3exattr; // Expression's attribute
53 SYM * dsp_a3esym; // External symbol involved in expr
55 TOKEN dspImmedEXPR[EXPRSIZE]; // Expression
56 uint64_t dspImmedEXVAL; // Expression's value
57 WORD dspImmedEXATTR; // Expression's attribute
58 SYM * dspImmedESYM; // External symbol involved in expr
59 int deposit_extra_ea; // Optional effective address extension
60 TOKEN dspaaEXPR[EXPRSIZE]; // Expression
61 uint64_t dspaaEXVAL; // Expression's value
62 WORD dspaaEXATTR; // Expression's attribute
63 SYM * dspaaESYM; // External symbol involved in expr
65 LONG dsp_a0perspace; // Peripheral space (X, Y - used in movep)
66 LONG dsp_a1perspace; // Peripheral space (X, Y - used in movep)
68 int dsp_k; // Multiplications sign
70 static inline LONG checkea(const uint32_t termchar, const int strings);
72 // ea checking error strings put into a table because I'm not sure there's an easy way to do otherwise
73 // (the messages start getting differerent in many places so it will get awkward to code those in)
74 // (I'd rather burn some RAM 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
152 // Parse a single addressing mode
154 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)
156 if (*tok == KW_A || *tok == KW_B)
162 else if (*tok == '#')
168 // Immediate Short Addressing Mode Force Operator
170 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
173 if (*AnEXVAL > 0xFFF && *AnEXVAL < -4096)
174 return error("immediate short addressing mode forced but address is bigger than $FFF");
176 if ((int32_t)*AnEXVAL <= 0xFF && (int32_t)*AnEXVAL > -0x100)
185 else if (*tok == '>')
187 // Immediate Long Addressing Mode Force Operator
190 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
193 if ((int32_t)*AnEXVAL > 0xFFFFFF || (int32_t)*AnEXVAL < -0xFFFFFF)
194 return error("long immediate is bigger than $FFFFFF");
200 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
203 if (*AnEXATTR & DEFINED)
205 if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
210 else if (*AnEXVAL < 0x1000)
217 // We have no clue what size our immediate will be
218 // so we have to assume the worst
224 else if (*tok >= KW_X0 && *tok <= KW_Y1)
230 else if (*tok == KW_X && *(tok + 1) == ':')
234 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
236 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
239 if (*AnEXATTR & DEFINED)
241 if (*AnEXVAL > 0xFFFFFF)
242 return error("long address is bigger than $FFFFFF");
244 *memspace = 0 << 6; // Mark we're on X memory space
246 // Check if value is between $FFC0 and $FFFF, AKA X:pp
247 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
249 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
250 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
251 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
255 *memspace = 0 << 6; // Mark we're on X memory space
256 *perspace = 0 << 16; // Mark we're on X peripheral space
257 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
261 // If the symbol/expression is defined then check for valid range.
262 // Otherwise the value had better fit or Fixups will bark!
276 *memspace = 0 << 6; // Mark we're on X memory space
283 else if (*tok == '<')
286 // Short Addressing Mode Force Operator in the case of '<'
289 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
292 // If the symbol/expression is defined then check for valid range.
293 // Otherwise the value had better fit or Fixups will bark!
294 if (*AnEXATTR & DEFINED)
297 return error("short addressing mode forced but address is bigger than $3F");
301 // Mark it as a fixup
302 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
306 *memspace = 0 << 6; // Mark we're on X memory space
307 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
310 else if (*tok == '>')
312 // Long Addressing Mode Force Operator
315 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
317 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
320 if (*AnEXATTR&DEFINED)
322 if (*AnEXVAL > 0xFFFFFF)
323 return error("long address is bigger than $FFFFFF");
325 *memspace = 0 << 6; // Mark we're on X memory space
332 *memspace = 0 << 6; // Mark we're on X memory space
339 else if (*tok == SHL) // '<<'
341 // I/O Short Addressing Mode Force Operator
345 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
348 // If the symbol/expression is defined then check for valid range.
349 // Otherwise the value had better fit or Fixups will bark!
350 if (*AnEXATTR & DEFINED)
352 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
354 if (*AnEXVAL < 0xFFFFFFC0)
355 return error("I/O Short Addressing Mode addresses must be between $FFC0 and $FFFF");
359 *memspace = 0 << 6; // Mark we're on X memory space
360 *perspace = 0 << 16; // Mark we're on X peripheral space
361 *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5...
365 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
367 // TODO: what if we need M_DSPAA here????
368 *memspace = 0 << 6; // Mark we're on X memory space
375 else if (*tok == KW_Y && *(tok + 1) == ':')
379 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
381 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
384 if (*AnEXVAL > 0xFFFFFF)
385 return error("long address is bigger than $FFFFFF");
387 *memspace = 1 << 6; // Mark we're on Y memory space
389 // Check if value is between $ffc0 and $ffff, AKA Y:pp
390 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
392 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
393 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
394 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
398 *perspace = 1 << 16; // Mark we're on X peripheral space
399 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
403 // If the symbol/expression is defined then check for valid range.
404 // Otherwise the value had better fit or Fixups will bark!
405 if (*AnEXATTR & DEFINED)
425 else if (*tok == '<')
428 // Short Addressing Mode Force Operator in the case of '<'
431 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
434 // If the symbol/expression is defined then check for valid range.
435 // Otherwise the value had better fit or Fixups will bark!
436 if (*AnEXATTR & DEFINED)
441 warn("short addressing mode forced but address is bigger than $3F - switching to long");
443 *memspace = 1 << 6; // Mark we're on Y memory space
450 // Mark it as a fixup
451 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
455 *memspace = 1 << 6; // Mark we're on Y memory space
456 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
459 else if (*tok == '>')
461 // Long Addressing Mode Force Operator
464 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
466 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
469 if (*AnEXATTR&DEFINED)
471 if (*AnEXVAL > 0xFFFFFF)
472 return error("long address is bigger than $FFFFFF");
474 *memspace = 1 << 6; // Mark we're on Y memory space
482 *memspace = 1 << 6; // Mark we're on Y memory space
489 else if (*tok == SHL) // '<<'
491 // I/O Short Addressing Mode Force Operator
495 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
498 // If the symbol/expression is defined then check for valid range.
499 // Otherwise the value had better fit or Fixups will bark!
500 if (*AnEXATTR & DEFINED)
502 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
504 if (*AnEXVAL < 0xFFFFFFC0)
505 return error("I/O Short Addressing Mode addresses must be between $FFE0 and $1F");
509 *memspace = 1 << 6; // Mark we're on Y memory space
510 *perspace = 1 << 16; // Mark we're on Y peripheral space
511 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
515 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
517 *memspace = 1 << 6; // Mark we're on Y memory space
523 // TODO: add absolute address checks
525 else if ((*tok >= KW_X) && (*tok <= KW_Y))
531 else if ((*tok >= KW_M0) && (*tok <= KW_M7))
534 *areg = (*tok++) & 7;
537 else if ((*tok >= KW_R0) && (*tok <= KW_R7))
540 *areg = (*tok++) - KW_R0;
543 else if ((*tok >= KW_N0) && (*tok <= KW_N7))
546 *areg = (*tok++) & 7;
549 else if ((*tok == KW_A0) || (*tok == KW_A1) || (*tok == KW_B0)
556 else if ((*tok == KW_A2) || (*tok == KW_B2))
562 else if ((*tok == '-') && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
564 // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
567 // Check to see if this is the first operand
569 return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
576 else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
578 // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
581 // Check to see if this is the first operand
583 return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
590 else if (*tok == '(' || *tok == '-')
592 // Could be either an expression or ea mode
593 if (*tok + 1 == SYMBOL)
597 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
604 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
612 // TODO: add absolute address checks
613 return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
615 else if (*tok == KW_P && *(tok + 1) == ':')
619 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
622 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
625 if (*AnEXVAL > 0xFFFFFF)
626 return error("long address is bigger than $FFFFFF");
635 *areg = (int)*AnEXVAL; // Lame, but what the hell
641 else if (*tok == '<')
644 // Short Addressing Mode Force Operator in the case of '<'
647 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
651 return error("short addressing mode forced but address is bigger than $3F");
654 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
657 else if (*tok == '>')
659 // Long Addressing Mode Force Operator
662 // Immediate Short Addressing Mode Force Operator
663 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
666 if (*AnEXATTR & DEFINED)
668 if (*AnEXVAL > 0xFFFFFF)
669 return error("long address is bigger than $FFFFFF");
677 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
685 else if (*tok == SHL)
687 // I/O Short Addressing Mode Force Operator
690 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
693 if (*AnEXVAL > 0xFFF)
694 return error("I/O short addressing mode forced but address is bigger than $FFF");
699 else if (*tok == '<')
701 // Short Addressing Mode Force Operator
704 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
707 if (*AnEXATTR & DEFINED)
709 if (*AnEXVAL > 0xFFF)
710 return error("short addressing mode forced but address is bigger than $FFF");
716 else if (*tok == '>')
718 // Long Addressing Mode Force Operator
721 // Immediate Short Addressing Mode Force Operator
722 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
725 if (*AnEXATTR & DEFINED)
727 if (*AnEXVAL > 0xFFFFFF)
728 return error("long address is bigger than $FFFFFF");
735 else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
744 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
747 // We'll store M_DSPEA_ABS in areg and if we have
748 // any extra info, it'll go in am
749 if (*AnEXATTR & DEFINED)
753 if (*AnEXVAL < 0x1000)
755 else if (*AnEXVAL < 0x10000)
757 else if (*AnEXVAL < 0x1000000)
760 return error("address must be smaller than $1000000");
766 // Well, we have no opinion on the expression's size, so let's assume the worst
773 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
778 // Parse all addressing modes except parallel moves
780 int dsp_amode(int maxea)
783 // Initialize global return values
784 nmodes = dsp_a0reg = dsp_a1reg = 0;
785 dsp_am0 = dsp_am1 = M_AM_NONE;
786 dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
789 dsp_a0exattr = dsp_a1exattr = 0;
790 dsp_a0esym = dsp_a1esym = (SYM *)NULL;
791 dsp_a0memspace = dsp_a1memspace = -1;
792 dsp_a0perspace = dsp_a1perspace = -1;
795 // If at EOL, then no addr modes at all
799 if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
803 // If caller wants only one mode, return just one (ignore comma);
804 // If there is no second addressing mode (no comma), then return just one anyway.
810 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
818 // Parse second addressing mode
819 if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
822 if (maxea == 2 || *tok == EOL)
825 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
833 // Only MAC-like or jsset/clr/tst/chg instructions here
835 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
840 return error(extra_stuff);
846 // Only Tcc instructions here, and then only those that accept 4 operands
848 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
852 return error("expected 4 parameters");
854 if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
860 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
867 // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
868 return error(extra_stuff);
871 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
876 // Helper function which gives us the encoding of a DSP register
878 static inline int SDreg(int reg)
880 if (reg >= KW_X0 && reg <= KW_N7)
882 else if (reg >= KW_A0&® <= KW_A2)
883 return (8 >> (reg & 7)) | 8;
884 else //if (reg>=KW_R0&®<=KW_R7)
885 return reg - KW_R0 + 16;
886 // Handy map for the above:
887 // (values are of course taken from keytab)
888 // Register | Value | Return value
921 // Check for X:Y: parallel mode syntax
923 static inline LONG check_x_y(LONG ea1, LONG S1)
926 LONG eax_temp, eay_temp;
927 LONG D1, D2, S2, ea2;
929 LONG w = 1 << 7; // S1=0, D1=1<<14
931 if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
932 (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
936 case DSP_EA_POSTINC: ea1 = (ea1 & (~0x38)) | 0x8; break;
937 case DSP_EA_POSTINC1: ea1 = (ea1 & (~0x38)) | 0x18; break;
938 case DSP_EA_POSTDEC1: ea1 = (ea1 & (~0x38)) | 0x10; break;
939 case DSP_EA_NOUPD: ea1 = (ea1 & (~0x38)) | 0x00; break;
944 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
946 switch (K_D1 = *tok++)
948 case KW_X0: D1 = 0 << 10; break;
949 case KW_X1: D1 = 1 << 10; break;
950 case KW_A: D1 = 2 << 10; break;
951 case KW_B: D1 = 3 << 10; break;
952 default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
957 // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
962 case 4: D1 = 0 << 10; break;
963 case 5: D1 = 1 << 10; break;
964 case 14: D1 = 2 << 10; break;
965 case 15: D1 = 3 << 10; break;
966 default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
973 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
975 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
979 if (*tok >= KW_R0 && *tok <= KW_R7)
981 ea2 = (*tok++ - KW_R0);
983 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
984 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'");
987 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
989 // If eax register is r0-r3 then eay register is r4-r7.
990 // Encode that to 2 bits (i.e. eay value is 0-3)
991 eax_temp = (ea2 & 3) << 5; // Store register temporarily
994 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
1006 else if (*tok >= KW_N0 && *tok <= KW_N7)
1009 if ((*tok++ & 7) != ea2)
1010 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')");
1015 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
1018 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
1021 else if (*tok == '-')
1028 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
1030 else if (*tok++ == ',')
1036 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
1038 ea2 |= eax_temp; // OR eay back from temp
1040 switch (K_D2 = *tok++)
1042 case KW_Y0: D2 = 0 << 8; break;
1043 case KW_Y1: D2 = 1 << 8; break;
1044 case KW_A: D2 = 2 << 8; break;
1045 case KW_B: D2 = 3 << 8; break;
1046 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1050 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
1054 return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
1056 inst = B16(11000000, 00000000) | w;
1057 inst |= ea1 | D1 | ea2 | D2;
1061 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1063 else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1065 // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1068 case KW_Y0: S2 = 0 << 8; break;
1069 case KW_Y1: S2 = 1 << 8; break;
1070 case KW_A: S2 = 2 << 8; break;
1071 case KW_B: S2 = 3 << 8; break;
1072 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1076 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1080 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1082 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1086 if (*tok >= KW_R0 && *tok <= KW_R7)
1088 ea2 = (*tok++ - KW_R0);
1090 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
1091 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'");
1094 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
1095 // If eax register is r0-r3 then eay register is r4-r7.
1096 // Encode that to 2 bits (i.e. eay value is 0-3)
1097 eay_temp = (ea2 & 3) << 5; //Store register temporarily
1100 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1109 else if (*tok >= KW_N0 && *tok <= KW_N7)
1112 if ((*tok++ & 7) != ea2)
1113 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')");
1118 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1121 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1124 else if (*tok == '-')
1130 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1132 else if (*tok == EOL)
1138 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1140 ea2 |= eay_temp; //OR eay back from temp
1142 inst = B16(10000000, 00000000) | w;
1143 inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1147 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1150 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1153 return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
1156 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1160 // Parse X: addressing space parallel moves
1162 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1164 int immreg; // Immediate register destination
1165 LONG S2, D1, D2; // Source and Destinations
1166 LONG ea1; // ea bitfields
1167 uint32_t termchar = ','; // Termination character for ea checks
1168 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1169 ea1 = -1; // initialise e1 (useful for some code paths)
1176 if (tok[1] == CONST || tok[1] == FCONST)
1179 dspImmedEXVAL = *tok++;
1183 // This could be either -(Rn), -aa or -ea. Check for immediate first
1184 if (tok[1] == SYMBOL)
1186 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1191 // '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'
1192 if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
1195 if (ea1 == DSP_EA_ABS)
1196 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1199 return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1202 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
1204 if (ea1 == B8(00110100))
1205 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
1207 inst = B16(00001000, 00000000) | ea1 | (0 << 8);
1210 else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1213 if (ea1 == DSP_EA_ABS)
1214 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1217 return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1220 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
1222 if (ea1 == B8(00110100))
1223 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
1225 inst = B16(00001001, 00000000) | ea1 | (1 << 8);
1228 else if (*tok == KW_A || *tok == KW_B)
1230 // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1233 case 4: D1 = 0 << 10; break;
1234 case 5: D1 = 1 << 10; break;
1235 case 14: D1 = 2 << 10; break;
1236 case 15: D1 = 3 << 10; break;
1237 default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
1240 if (tok[1] == ',' && tok[2] == KW_Y)
1242 // 'S1,X:eax S2,Y:eay'
1243 return check_x_y(ea1, S1);
1247 if (ea1 == DSP_EA_ABS)
1248 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1252 case KW_A: S2 = 0 << 9; break;
1253 case KW_B: S2 = 1 << 9; break;
1254 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
1258 return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1260 if (*tok == KW_Y0 || *tok == KW_Y1)
1262 if (*tok++ == KW_Y0)
1268 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1270 inst = B16(00010000, 00000000) | (0 << 7);
1271 inst |= ea1 | D1 | S2 | D2;
1275 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1277 else if (*tok == KW_Y)
1279 // 'S1,X:eax Y:eay,D2'
1280 return check_x_y(ea1, S1);
1282 else if (*tok == KW_Y0 || *tok == KW_Y1)
1284 // 'S1,X:eax S2,Y:eay'
1285 return check_x_y(ea1, S1);
1288 return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1292 // Only check for aa if we have a defined number in our hands or we've
1293 // been asked to use a short number format. The former case we'll just test
1294 // it to see if it's small enough. The later - it's the programmer's call
1295 // so he'd better have a small address or the fixups will bite him/her in the arse!
1296 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1299 // It's an immediate, so ea or eax is probably an absolute address
1300 // (unless it's aa if the immediate is small enough)
1301 // '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'
1303 // Check for aa (which is 6 bits zero extended)
1304 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1308 // It might be X:aa but we're not 100% sure yet.
1309 // If it is, the only possible syntax here is 'X:aa,D'.
1310 // So check ahead to see if EOL follows D, then we're good to go.
1311 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)
1313 // Yup, we're good to go - 'X:aa,D' it is
1315 immreg = SDreg(*tok++);
1316 inst = inst | (uint32_t)dspImmedEXVAL;
1317 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1318 inst |= 1 << 7; // W
1327 inst = inst | (uint32_t)dspImmedEXVAL;
1328 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1333 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1334 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1336 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1337 goto x_checkea_right;
1343 // Well, that settles it - we do have an ea in our hands
1346 // 'X:ea,D' [... S2,d2]
1348 return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
1350 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1357 inst = inst | B8(01000000) | (1 << 7);
1358 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1361 if (ea1 == DSP_EA_ABS)
1362 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1369 if (*tok == KW_A || *tok == KW_B)
1374 return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1376 if (*tok == KW_Y0 || *tok == KW_Y1)
1381 return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
1383 inst = B16(00010000, 00000000) | (1 << 7);
1384 inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
1385 inst |= (S2 & 1) << 9;
1386 inst |= (D2 & 1) << 8;
1391 return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1394 return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1398 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,'");
1405 inst = inst | B8(01000000) | (0 << 7);
1406 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1409 if (ea1 == DSP_EA_ABS)
1410 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1416 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1417 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1418 goto x_checkea_right;
1427 // It's not an immediate, check for '-(Rn)'
1428 ea1 = checkea(termchar, X_ERRORS);
1437 else if (*tok == '#')
1441 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1444 // Okay so we have immediate data - mark it down
1446 // Now, proceed to the main code for this branch
1449 else if (*tok == '(')
1451 // Maybe we got an expression here, check for it
1452 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1454 // Evaluate the expression and go to immediate code path
1455 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1459 // Nope, let's check for ea then
1460 ea1 = checkea(termchar, X_ERRORS);
1469 return error("Comma expected after 'X:(Rn)')");
1471 // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
1472 // If it is, the only possible syntax here is 'X:ea,D'.
1473 // So check ahead to see if EOL follows D, then we're good to go.
1474 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1479 inst = inst | B8(01000000) | (1 << 7);
1481 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1490 inst = inst | B8(01000000) | (0 << 7);
1492 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1497 goto x_checkea_right;
1501 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
1502 // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
1503 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)))
1506 // Check if D1 is x0, x1, a or b
1509 case KW_X0: D1 = 0 << 10; break;
1510 case KW_X1: D1 = 1 << 10; break;
1511 case KW_A: D1 = 2 << 10; break;
1512 case KW_B: D1 = 3 << 10; break;
1513 default: return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
1518 case KW_A: S2 = 0 << 9; break;
1519 case KW_B: S2 = 1 << 9; break;
1520 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
1524 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1526 if (*tok == KW_Y0 || *tok == KW_Y1)
1528 if (*tok++ == KW_Y0)
1534 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1536 inst = B16(00010000, 00000000) | (W << 7);
1537 inst |= ea1 | D1 | S2 | D2;
1541 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1544 // Check to see if we got eax (which is a subset of ea)
1547 if ((inst = check_x_y(ea1, 0)) != 0)
1551 // Rewind pointer as it might be an expression and check for it
1554 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1557 // Yes, we have an expression, so we now check for
1558 // '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'
1563 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1565 // Check for immediate address
1566 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1569 // We set ea1 here - if it's aa instead of ea
1570 // then it won't be used anyway
1573 if (!(dspImmedEXATTR&DEFINED))
1575 force_imm = NUM_FORCE_LONG;
1576 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1581 else if (*tok == '>')
1583 // Check for immediate address forced long
1586 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1589 if (dspImmedEXATTR & DEFINED)
1590 if (dspImmedEXVAL > 0xffffff)
1591 return error("long address is bigger than $ffffff");
1593 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1595 force_imm = NUM_FORCE_LONG;
1599 else if (*tok == '<')
1601 // Check for immediate address forced short
1604 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1607 force_imm = NUM_FORCE_SHORT;
1609 if (dspImmedEXATTR & DEFINED)
1611 if (dspImmedEXVAL > 0x3F)
1613 if (optim_warn_flag)
1614 warn("short addressing mode forced but address is bigger than $3F - switching to long");
1615 force_imm = NUM_FORCE_LONG;
1616 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1622 // This might end up as something like 'move Y:<adr,register'
1623 // so let's mark it as an extra aa fixup here.
1624 // Note: we are branching to x_check_immed without a
1625 // defined dspImmed so it's going to be 0. It probably
1626 // doesn't harm anything.
1627 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1633 return error("unknown x: addressing mode");
1638 // Parse Y: addressing space parallel moves
1640 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1642 int immreg; // Immediate register destination
1643 LONG D2; // Destination
1644 LONG ea1; // ea bitfields
1645 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1648 if (tok[1] == CONST || tok[1] == FCONST)
1651 dspImmedEXVAL = *tok++;
1654 // This could be either -(Rn), -aa or -ea. Check for immediate first
1655 if (*tok == SYMBOL || tok[1] == SYMBOL)
1657 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1659 // Only check for aa if we have a defined number in our hands or we've
1660 // been asked to use a short number format. The former case we'll just test
1661 // it to see if it's small enough. The later - it's the programmer's call
1662 // so he'd better have a small address or the fixups will bite him/her in the arse!
1663 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1665 // It's an immediate, so ea is probably an absolute address
1666 // (unless it's aa if the immediate is small enough)
1667 // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
1669 // Check for aa (which is 6 bits zero extended)
1670 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1672 // It might be Y:aa but we're not 100% sure yet.
1673 // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
1674 // So check ahead to see if EOL follows D, then we're good to go.
1675 if (*tok == EOL && S1 != 0)
1678 inst = B16(01001000, 00000000);
1679 inst |= dspImmedEXVAL;
1680 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1683 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)
1685 // Yup, we're good to go - 'Y:aa,D' it is
1687 immreg = SDreg(*tok++);
1688 inst |= dspImmedEXVAL;
1689 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1694 // Well, that settles it - we do have a ea in our hands
1695 if (*tok == EOL && S1 != 0)
1698 inst = B16(01001000, 01110000);
1700 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1701 if (ea1 == DSP_EA_ABS)
1702 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1706 return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1707 if (D1 == 0 && S1 == 0)
1710 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1714 return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1715 inst |= B16(00000000, 01110000);
1717 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1718 if (ea1 == DSP_EA_ABS)
1719 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1723 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,'");
1728 if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1733 inst |= (S1 & 1) << 11;
1734 inst |= (D1 & 1) << 10;
1735 inst |= (D2 & 8) << (9 - 3);
1736 inst |= (D2 & 1) << 8;
1740 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1748 // It's not an immediate, check for '-(Rn)'
1749 ea1 = checkea(',', Y_ERRORS);
1758 else if (*tok == '#')
1761 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1763 // Okay so we have immediate data - mark it down
1765 // Now, proceed to the main code for this branch
1768 else if (*tok == '(')
1770 // Maybe we got an expression here, check for it
1771 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1773 // Evaluate the expression and go to immediate code path
1774 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1778 // Nope, let's check for ea then
1779 if (S1 == 0 || (S1 != 0 && D1 != 0))
1780 ea1 = checkea(',', Y_ERRORS);
1782 ea1 = checkea(EOL, Y_ERRORS);
1788 if (S1 != 0 && *tok == EOL)
1791 inst = B16(01001000, 01000000);
1793 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1796 else if (S1 != 0 && D1 != 0 && S2 == 0)
1801 case 14: S1 = 0 << 11; break; // A
1802 case 15: S1 = 1 << 11; break; // B
1803 default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
1807 case 4: D1 = 0 << 10; break; // X0
1808 case 5: D1 = 1 << 10; break; // X1
1809 default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
1812 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1815 case KW_Y0: D2 = 0 << 8; break;
1816 case KW_Y1: D2 = 1 << 8; break;
1817 case KW_A: D2 = 2 << 8; break;
1818 case KW_B: D2 = 3 << 8; break;
1819 default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
1821 inst = B16(00010000, 11000000);
1822 inst |= S1 | D1 | D2;
1827 return error("Comma expected after 'Y:(Rn)')");
1828 // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
1829 // If it is, the only possible syntax here is 'Y:ea,D'.
1830 // So check ahead to see if EOL follows D, then we're good to go.
1831 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1835 inst |= B16(00000000, 01000000);
1837 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1841 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1843 // Check for immediate address
1844 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1847 // Yes, we have an expression, so we now check for
1848 // 'Y:ea,D' or 'Y:aa,D'
1849 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1850 if (!(dspImmedEXATTR&DEFINED))
1852 force_imm = NUM_FORCE_LONG;
1853 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1858 else if (*tok == '>')
1860 // Check for immediate address forced long
1862 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1864 if (dspImmedEXATTR & DEFINED)
1865 if (dspImmedEXVAL > 0xffffff)
1866 return error("long address is bigger than $ffffff");
1868 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1870 force_imm = NUM_FORCE_LONG;
1874 else if (*tok == '<')
1877 if (S1 != 0 && D1 != 0)
1879 // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
1880 // there's no Y:aa mode here, so we'll force long
1881 if (optim_warn_flag)
1882 warn("forced short addressing in R:Y mode is not allowed - switching to long");
1884 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1889 force_imm = NUM_FORCE_LONG;
1890 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1895 // Check for immediate address forced short
1896 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1898 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1900 force_imm = NUM_FORCE_SHORT;
1901 if (dspImmedEXATTR & DEFINED)
1903 if (dspImmedEXVAL > 0xfff)
1905 if (optim_warn_flag)
1906 warn("short addressing mode forced but address is bigger than $fff - switching to long");
1908 force_imm = NUM_FORCE_LONG;
1909 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1914 // This might end up as something like 'move Y:<adr,register'
1915 // so let's mark it as an extra aa fixup here.
1916 // Note: we are branching to y_check_immed without a
1917 // defined dspImmed so it's going to be 0. It probably
1918 // doesn't harm anything.
1919 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1926 return error("unrecognised Y: parallel move syntax");
1931 // Parse L: addressing space parallel moves
1933 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1935 int immreg; // Immediate register destination
1936 LONG D1; // Source and Destinations
1937 LONG ea1; // ea bitfields
1938 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1941 if (*tok == CONST || tok[1] == FCONST)
1944 dspImmedEXVAL = *tok++;
1947 // This could be either -(Rn), -aa or -ea. Check for immediate first
1948 // Maybe we got an expression here, check for it
1949 if (*tok == SYMBOL || tok[1] == SYMBOL)
1951 // Evaluate the expression and go to immediate code path
1952 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1954 // Only check for aa if we have a defined number in our hands or we've
1955 // been asked to use a short number format. The former case we'll just test
1956 // it to see if it's small enough. The later - it's the programmer's call
1957 // so he'd better have a small address or the fixups will bite him/her in the arse!
1958 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1960 // It's an immediate, so ea is probably an absolute address
1961 // (unless it's aa if the immediate is small enough)
1962 // 'L:ea,D' or 'L:aa,D'
1964 // Check for aa (which is 6 bits zero extended)
1968 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1973 else if (S1 == KW_B)
1978 inst = B16(01000000, 00000000);
1979 inst |= dspImmedEXVAL;
1980 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1988 else if (S1 == KW_B)
1993 if (ea1 == DSP_EA_ABS)
1994 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1996 inst |= B16(01000000, 01110000);
1997 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2004 return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
2005 // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
2006 if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
2007 return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
2009 if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
2016 else if (immreg == KW_B)
2022 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
2024 inst &= B16(11111111, 10111111);
2025 inst |= dspImmedEXVAL;
2026 inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
2031 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
2033 // Hang on, we've got a L:<aa here, let's do that instead
2037 // Well, that settles it - we do have a ea in our hands
2042 else if (D1 == KW_B)
2048 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
2050 inst |= B16(00000000, 00110000);
2051 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2057 //It's not an immediate, check for '-(Rn)'
2058 ea1 = checkea(',', L_ERRORS);
2067 else if (*tok == '(')
2069 // Maybe we got an expression here, check for it
2070 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
2072 // Evaluate the expression and go to immediate code path
2073 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
2077 //Nope, let's check for ea then
2079 ea1 = checkea(',', L_ERRORS);
2081 ea1 = checkea(EOL, L_ERRORS);
2090 inst = B16(01000000, 01000000);
2093 else if (S1 == KW_B)
2099 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2102 else if (*tok++ != ',')
2103 return error("Comma expected after 'L:(Rn)')");
2105 // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
2106 // If it is, the only possible syntax here is 'L:ea,D'.
2107 // So check ahead to see if EOL follows D, then we're good to go.
2108 if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
2114 else if (D1 == KW_B)
2120 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2124 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2126 // Check for immediate address
2127 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2130 // We set ea1 here - if it's aa instead of ea
2131 // then it won't be used anyway
2133 if (!(dspImmedEXATTR & DEFINED))
2135 force_imm = NUM_FORCE_LONG;
2136 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2138 else if (dspImmedEXVAL > 0x3f)
2140 // Definitely no aa material, so it's going to be a long
2141 // Mark that we need to deposit an extra word
2142 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2145 // Yes, we have an expression, so we now check for
2146 // 'L:ea,D' or 'L:aa,D'
2149 else if (*tok == '>')
2151 // Check for immediate address forced long
2153 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2155 if (dspImmedEXATTR & DEFINED)
2156 if (dspImmedEXVAL > 0xffffff)
2157 return error("long address is bigger than $ffffff");
2159 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2161 force_imm = NUM_FORCE_LONG;
2164 else if (*tok == '<')
2166 // Check for immediate address forced short
2168 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2170 if (dspImmedEXATTR & DEFINED)
2172 if (dspImmedEXVAL > 0xfff)
2173 return error("short addressing mode forced but address is bigger than $fff");
2177 // This might end up as something like 'move Y:<adr,register'
2178 // so let's mark it as an extra aa fixup here.
2179 // Note: we are branching to l_check_immed without a
2180 // defined dspImmed so it's going to be 0. It probably
2181 // doesn't harm anything.
2182 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
2185 force_imm = NUM_FORCE_SHORT;
2189 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");
2194 // Checks for all ea cases where indexed addressing is concenred
2196 static inline LONG checkea(const uint32_t termchar, const int strings)
2204 return error(ea_errors[strings][0]);
2205 if (*tok >= KW_R0 && *tok <= KW_R7)
2207 // We got '-(Rn' so mark it down
2208 ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2210 return error(ea_errors[strings][1]);
2211 // Now, proceed to the main code for this branch
2215 return error(ea_errors[strings][2]);
2217 else if (*tok == '(')
2219 // Checking for ea of type (Rn)
2221 if (*tok >= KW_R0 && *tok <= KW_R7)
2223 // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2224 ea = *tok++ - KW_R0;
2229 if (*tok < KW_N0 || *tok > KW_N7)
2230 return error(ea_errors[strings][3]);
2231 if ((*tok++ & 7) != ea)
2232 return error(ea_errors[strings][4]);
2235 return error(ea_errors[strings][5]);
2238 else if (*tok == ')')
2240 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2245 if (termchar == ',')
2250 ea |= DSP_EA_POSTINC1;
2253 else if (*tok >= KW_N0 && *tok <= KW_N7)
2256 if ((*tok++ & 7) != ea)
2257 return error(ea_errors[strings][6]);
2258 ea |= DSP_EA_POSTINC;
2262 return error(ea_errors[strings][7]);
2266 if (*tok >= KW_N0 && *tok <= KW_N7)
2269 if ((*tok++ & 7) != ea)
2270 return error(ea_errors[strings][6]);
2271 ea |= DSP_EA_POSTINC;
2277 ea |= DSP_EA_POSTINC1;
2282 else if (*tok == '-')
2285 if (termchar == ',')
2290 ea |= DSP_EA_POSTDEC1;
2293 else if (*tok >= KW_N0 && *tok <= KW_N7)
2296 if ((*tok++ & 7) != ea)
2297 return error(ea_errors[strings][8]);
2298 ea |= DSP_EA_POSTDEC;
2302 return error(ea_errors[strings][9]);
2306 if (*tok >= KW_N0 && *tok <= KW_N7)
2309 if ((*tok++ & 7) != ea)
2310 return error(ea_errors[strings][8]);
2311 ea |= DSP_EA_POSTDEC;
2317 ea |= DSP_EA_POSTDEC1;
2322 else if (termchar == ',')
2331 return error(ea_errors[strings][10]);
2341 return error(ea_errors[strings][11]);
2344 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");
2349 // Checks for all ea cases, i.e. all addressing modes that checkea handles
2350 // plus immediate addresses included forced short/long ones.
2351 // In other words this is a superset of checkea (and in fact calls checkea).
2353 LONG checkea_full(const uint32_t termchar, const int strings)
2357 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2359 // Check for immediate address
2360 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2363 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2365 // Yes, we have an expression
2368 else if (*tok == '>')
2370 // Check for immediate address forced long
2372 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2374 if (dspImmedEXATTR & DEFINED)
2375 if (dspImmedEXVAL > 0xffffff)
2376 return error("long address is bigger than $ffffff");
2378 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2380 // Yes, we have an expression
2383 else if (*tok == '<')
2385 // Check for immediate address forced short
2387 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2389 if (dspImmedEXATTR & DEFINED)
2390 if (dspImmedEXVAL > 0xfff)
2391 return error("short addressing mode forced but address is bigger than $fff");
2393 // Yes, we have an expression
2398 ea1 = checkea(termchar, strings);
2409 // Main routine to check parallel move modes.
2410 // It's quite complex so it's split into a few procedures (in fact most of the
2411 // above ones). A big effort was made so this can be managable and not too
2412 // hacky, however one look at the 56001 manual regarding parallel moves and
2413 // you'll know that this is not an easy // problem to deal with!
2414 // dest=destination register from the main opcode. This must not be the same
2415 // as D1 or D2 and that even goes for stuff like dest=A, D1=A0/1/2!!!
2417 LONG parmoves(WORD dest)
2419 int force_imm; // Addressing mode force operator
2420 int immreg; // Immediate register destination
2421 LONG inst; // 16 bit bitfield that has the parallel move opcode
2422 LONG S1, S2, D1, D2; // Source and Destinations
2423 LONG ea1; // ea bitfields
2428 return B16(00100000, 00000000);
2433 // '#xxxxxx,D', '#xx,D'
2435 force_imm = NUM_NORMAL;
2439 force_imm = NUM_FORCE_LONG;
2442 else if (*tok == '<')
2444 force_imm = NUM_FORCE_SHORT;
2448 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2452 return error("expected comma");
2454 if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
2455 return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
2457 immreg = SDreg(*tok++);
2461 if (!(dspImmedEXATTR & FLOAT))
2463 if (dspImmedEXATTR & DEFINED)
2465 // From I parallel move:
2466 // "If the destination register D is X0, X1, Y0, Y1, A, or B, the 8-bit immediate short operand
2467 // is interpreted as a signed fraction and is stored in the specified destination register.
2468 // That is, the 8 - bit data is stored in the eight MS bits of the destination operand, and the
2469 // remaining bits of the destination operand D are zeroed."
2470 // The funny bit is that Motorola assembler can parse something like 'move #$FF0000,b' into an
2471 // I (immediate short move) - so let's do that as well then...
2472 if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
2474 if ((dspImmedEXVAL & 0xffff) == 0)
2476 dspImmedEXVAL >>= 16;
2480 if (force_imm == NUM_FORCE_SHORT)
2482 if (dspImmedEXVAL < 0xFF && (int32_t)dspImmedEXVAL > -0x100)
2485 // value fits in 8 bits - immediate move
2486 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2491 if (optim_warn_flag)
2492 warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2493 force_imm = NUM_FORCE_LONG;
2497 if (force_imm == NUM_FORCE_LONG)
2501 // X or Y Data move. I don't think it matters much
2502 // which of the two it will be, so let's use X.
2503 deposit_immediate_long_with_register:
2504 inst = B16(01000000, 11110100);
2505 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2506 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2510 if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2512 // value fits in 8 bits - immediate move
2513 deposit_immediate_short_with_register:
2514 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2519 // value doesn't fit in 8 bits, so it can either be
2520 // X or Y Data move. I don't think it matters much
2521 // which of the two it will be, so let's use X:.
2522 // TODO: if we're just goto'ing perhaps the logic can be simplified
2523 goto deposit_immediate_long_with_register;
2528 if (force_imm != NUM_FORCE_SHORT)
2531 // TODO: if we're just goto'ing perhaps the logic can be simplified
2532 goto deposit_immediate_long_with_register;
2537 // No visibility of the number so let's add a fixup for this
2538 AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
2539 inst = B16(00100000, 00000000);
2540 inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
2548 if (dspImmedEXATTR & DEFINED)
2550 double f = *(double *)&dspImmedEXVAL;
2551 // Check direct.c for ossom comments regarding conversion!
2552 //N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
2553 dspImmedEXVAL = ((uint32_t)(int32_t)round(f * (1 << 23))) & 0xFFFFFF;
2558 if ((dspImmedEXVAL & 0xFFFF) == 0)
2560 // Value's 16 lower bits are not set so the value can fit in a single byte
2561 // (check parallel I move quoted above)
2562 if (optim_warn_flag)
2563 warn("Immediate value fits inside 8 bits, so using instruction short format");
2564 dspImmedEXVAL >>= 16;
2565 goto deposit_immediate_short_with_register;
2568 if (force_imm == NUM_FORCE_SHORT)
2570 if ((dspImmedEXVAL & 0xFFFF) != 0)
2572 if (optim_warn_flag)
2573 warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
2574 goto deposit_immediate_long_with_register;
2577 return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2580 // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
2581 goto deposit_immediate_long_with_register;
2585 if (force_imm == NUM_FORCE_SHORT)
2587 goto deposit_immediate_short_with_register;
2591 // Just deposit a float fixup
2592 AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
2593 inst = B16(00100000, 00000000);
2594 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2602 // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2605 case 4: D1 = 0 << 10;break; // X0
2606 case 5: D1 = 1 << 10;break; // X1
2607 case 14: D1 = 2 << 10;break; // A
2608 case 15: D1 = 3 << 10;break; // B
2609 default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
2614 case KW_A: S2 = 0 << 9; break;
2615 case KW_B: S2 = 1 << 9; break;
2616 default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
2620 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2624 case KW_Y0: D2 = 0 << 8; break;
2625 case KW_Y1: D2 = 1 << 8; break;
2626 default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
2630 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2632 inst = B16(00010000, 10110100) | D1 | S2 | D2;
2633 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2637 else if (*tok == KW_X)
2640 // Hey look, it's just the register X and not the addressing mode - fall through to general case
2641 goto parse_everything_else;
2646 return error("expected ':' after 'X' in parallel move (i.e. X:)");
2648 // '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'
2649 return parse_x(1, B16(01000000, 00000000), 0, 1);
2651 else if (*tok == KW_Y)
2654 // Hey look, it's just the register y and not the addressing mode - fall through to general case
2655 goto parse_everything_else;
2660 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2662 // 'Y:ea,D' or 'Y:aa,D'
2663 return parse_y(B16(01001000, 10000000), 0, 0, 0);
2665 else if (*tok == KW_L)
2667 // 'L:ea,D' or 'L:aa,D'
2670 return error("expected ':' after 'L' in parallel move (i.e. L:)");
2672 return parse_l(1, B16(01000000, 11000000), 0);
2674 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))
2676 // Everything else - brace for impact!
2678 // X: 'S,X:ea' 'S,X:aa'
2679 // X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
2680 // Y: 'S,Y:ea' 'S,Y:aa'
2681 // 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'
2682 // L: 'S,L:ea' 'S,L:aa'
2684 parse_everything_else:
2689 return error("Comma expected after 'S')");
2693 // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
2694 // 'A,X:ea X0,A' 'B,X:ea X0,B'
2698 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2700 return parse_x(0, B16(01000000, 00000000), S1, 1);
2702 else if (*tok == KW_Y)
2704 // 'S,Y:ea' 'S,Y:aa'
2708 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2710 return parse_y(B16(0000000, 00000000), S1, 0, 0);
2712 else if (*tok == KW_L)
2714 // 'S,L:ea' 'S,L:aa'
2718 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2720 return parse_l(1, B16(00000000, 00000000), L_S1);
2722 else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2725 // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
2726 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2732 inst = B16(00100000, 00000000);
2733 inst |= (S1 << 5) | (D1);
2736 else if (*tok == KW_Y)
2741 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2742 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2745 else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2747 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2750 if (S1 == 6 && D1 == 14 && S2 == 14)
2754 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2757 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2760 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2762 ea1 = checkea_full(EOL, Y_ERRORS);
2767 inst = B16(00001000, 10000000);
2772 else if (S1 == 6 && D1 == 15 && S2 == 15)
2776 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2779 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2782 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2784 ea1 = checkea_full(EOL, Y_ERRORS);
2789 inst = B16(00001000, 10000000);
2794 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2798 return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2801 return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2804 return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2806 ea1 = checkea_full(EOL, Y_ERRORS);
2811 inst = B16(00010000, 01000000);
2812 inst |= (S1 & 1) << 11;
2813 inst |= (D1 & 1) << 10;
2814 inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2819 return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2822 else if (*tok == '#')
2824 // R:Y: 'S1,D1 #xxxxxx,D2'
2829 // Well, forcing an immediate to be 24 bits is legal here
2830 // but then it's the only available option so my guess is that this
2831 // is simply superfluous. So let's just eat the character
2835 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2838 if (dspImmedEXATTR & DEFINED)
2839 if (dspImmedEXVAL > 0xffffff)
2840 return error("immediate is bigger than $ffffff");
2842 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2845 return error("Comma expected after 'S1,D1 #xxxxxx')");
2847 // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
2850 case KW_Y0: D2 = 0 << 8; break;
2851 case KW_Y1: D2 = 1 << 8; break;
2852 case KW_A: D2 = 2 << 8; break;
2853 case KW_B: D2 = 3 << 8; break;
2854 default: return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
2857 if (S1 == 14 || S1 == 15)
2859 if (D1 == 4 || D1 == 5)
2861 inst = B16(00010000, 11110100);
2862 inst |= (S1 & 1) << 11;
2863 inst |= (D1 & 1) << 10;
2865 dspImmedEXVAL = dspaaEXVAL;
2869 return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2872 return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2875 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2878 return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2880 else if (*tok == '(')
2883 // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2886 if (*tok >= KW_R0 && *tok <= KW_R7)
2888 ea1 = (*tok++ - KW_R0);
2891 return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
2894 return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
2903 else if (*tok >= KW_N0 && *tok <= KW_N7)
2906 if ((*tok++ & 7) != ea1)
2907 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
2912 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
2915 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
2917 else if (*tok == '-')
2927 else if (*tok >= KW_N0 && *tok <= KW_N7)
2930 if ((*tok++ & 7) != ea1)
2931 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
2936 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
2940 inst = B16(00100000, 01000000);
2945 return error("extra (unexpected) text found");