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 int dsp_k; // Multiplications sign
67 static inline LONG checkea(const uint32_t termchar, const int strings);
69 // ea checking error strings put into a table because I'm not sure there's an easy way to do otherwise
70 // (the messages start getting differerent in many places so it will get awkward to code those in)
71 // (I'd rather burn some RAM in order to have more helpful error messages than the other way round)
78 const char *ea_errors[][12] = {
81 "unrecognised X: parallel move syntax: expected '(' after 'X:-'", // 0
82 "unrecognised X: parallel move syntax: expected ')' after 'X:-(Rn'", // 1
83 "unrecognised X: parallel move syntax: expected R0-R7 after 'X:-('", // 2
84 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn+'", // 3
85 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn+Nn)'", // 4
86 "unrecognised X: parallel move syntax: expected ')' after 'X:(Rn+Nn'", // 5
87 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)+Nn'", // 6
88 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)+'", // 7
89 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)-Nn'", // 8
90 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)-'", // 9
91 "unrecognised X: parallel move syntax: expected '+', '-' or ',' after 'X:(Rn)'", // 10
92 "unrecognised X: parallel move syntax: expected '+' or ')' after 'X:(Rn'", // 11
96 "unrecognised Y: parallel move syntax: expected '(' after 'Y:-'", // 0
97 "unrecognised Y: parallel move syntax: expected ')' after 'Y:-(Rn'", // 1
98 "unrecognised Y: parallel move syntax: expected R0-R7 after 'Y:-('", // 2
99 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn+'", // 3
100 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn+Nn)'", // 4
101 "unrecognised Y: parallel move syntax: expected ')' after 'Y:(Rn+Nn'", // 5
102 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)+Nn'", // 6
103 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)+'", // 7
104 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)-Nn'", // 8
105 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)-'", // 9
106 "unrecognised Y: parallel move syntax: expected '+', '-' or ',' after 'Y:(Rn)'", // 10
107 "unrecognised Y: parallel move syntax: expected '+' or ')' after 'Y:(Rn'", // 11
111 "unrecognised L: parallel move syntax: expected '(' after 'L:-'", // 0
112 "unrecognised L: parallel move syntax: expected ')' after 'L:-(Rn'", // 1
113 "unrecognised L: parallel move syntax: expected R0-R7 after 'L:-('", // 2
114 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn+'", // 3
115 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn+Nn)'", // 4
116 "unrecognised L: parallel move syntax: expected ')' after 'L:(Rn+Nn'", // 5
117 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)+Nn'", // 6
118 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)+'", // 7
119 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)-Nn'", // 8
120 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)-'", // 9
121 "unrecognised L: parallel move syntax: expected '+', '-' or ',' after 'L:(Rn)'", // 10
122 "unrecognised L: parallel move syntax: expected '+' or ')' after 'L:(Rn'", // 11
126 "unrecognised P: effective address syntax: expected '(' after 'P:-'", // 0
127 "unrecognised P: effective address syntax: expected ')' after 'P:-(Rn'", // 1
128 "unrecognised P: effective address syntax: expected R0-R7 after 'P:-('", // 2
129 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn+'", // 3
130 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn+Nn)'", // 4
131 "unrecognised P: effective address syntax: expected ')' after 'P:(Rn+Nn'", // 5
132 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)+Nn'", // 6
133 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)+'", // 7
134 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)-Nn'", // 8
135 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)-'", // 9
136 "unrecognised P: effective address syntax: expected '+', '-' or ',' after 'P:(Rn)'", // 10
137 "unrecognised P: effective address syntax: expected '+' or ')' after 'P:(Rn'", // 11
149 // Parse a single addressing mode
151 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)
153 if (*tok == KW_A || *tok == KW_B)
159 else if (*tok == '#')
165 // Immediate Short Addressing Mode Force Operator
167 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
170 if (*AnEXVAL > 0xFFF && *AnEXVAL < -4096)
171 return error("immediate short addressing mode forced but address is bigger than $FFF");
173 if ((int32_t)*AnEXVAL <= 0xFF && (int32_t)*AnEXVAL > -0x100)
182 else if (*tok == '>')
184 // Immediate Long Addressing Mode Force Operator
187 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
190 if ((int32_t)*AnEXVAL > 0xFFFFFF || (int32_t)*AnEXVAL < -0xFFFFFF)
191 return error("long immediate is bigger than $FFFFFF");
197 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
200 if (*AnEXATTR & DEFINED)
202 if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
207 else if (*AnEXVAL < 0x1000)
214 // We have no clue what size our immediate will be
215 // so we have to assume the worst
221 else if (*tok >= KW_X0 && *tok <= KW_Y1)
227 else if (*tok == KW_X && *(tok + 1) == ':')
231 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
233 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
236 if (*AnEXATTR & DEFINED)
238 if (*AnEXVAL > 0xFFFFFF)
239 return error("long address is bigger than $FFFFFF");
241 *memspace = 0 << 6; // Mark we're on X memory space
243 // Check if value is between $FFC0 and $FFFF, AKA X:pp
244 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
246 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
247 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
248 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
252 *memspace = 0 << 6; // Mark we're on X memory space
253 *perspace = 0 << 16; // Mark we're on X peripheral space
254 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
258 // If the symbol/expression is defined then check for valid range.
259 // Otherwise the value had better fit or Fixups will bark!
273 *memspace = 0 << 6; // Mark we're on X memory space
280 else if (*tok == '<')
283 // Short Addressing Mode Force Operator in the case of '<'
286 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
289 // If the symbol/expression is defined then check for valid range.
290 // Otherwise the value had better fit or Fixups will bark!
291 if (*AnEXATTR & DEFINED)
294 return error("short addressing mode forced but address is bigger than $3F");
298 // Mark it as a fixup
299 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
303 *memspace = 0 << 6; // Mark we're on X memory space
304 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
307 else if (*tok == '>')
309 // Long Addressing Mode Force Operator
312 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
314 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
317 if (*AnEXATTR&DEFINED)
319 if (*AnEXVAL > 0xFFFFFF)
320 return error("long address is bigger than $FFFFFF");
322 *memspace = 0 << 6; // Mark we're on X memory space
329 *memspace = 0 << 6; // Mark we're on X memory space
336 else if (*tok == SHL) // '<<'
338 // I/O Short Addressing Mode Force Operator
342 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
345 // If the symbol/expression is defined then check for valid range.
346 // Otherwise the value had better fit or Fixups will bark!
347 if (*AnEXATTR & DEFINED)
349 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
351 if (*AnEXVAL < 0xFFFFFFC0)
352 return error("I/O Short Addressing Mode addresses must be between $FFC0 and $FFFF");
356 *memspace = 0 << 6; // Mark we're on X memory space
357 *perspace = 0 << 16; // Mark we're on X peripheral space
358 *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5...
362 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
364 // TODO: what if we need M_DSPAA here????
365 *memspace = 0 << 6; // Mark we're on X memory space
372 else if (*tok == KW_Y && *(tok + 1) == ':')
376 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
378 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
381 if (*AnEXVAL > 0xFFFFFF)
382 return error("long address is bigger than $FFFFFF");
384 *memspace = 1 << 6; // Mark we're on Y memory space
386 // Check if value is between $ffc0 and $ffff, AKA Y:pp
387 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
389 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
390 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
391 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
395 *perspace = 1 << 16; // Mark we're on X peripheral space
396 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
400 // If the symbol/expression is defined then check for valid range.
401 // Otherwise the value had better fit or Fixups will bark!
402 if (*AnEXATTR & DEFINED)
422 else if (*tok == '<')
425 // Short Addressing Mode Force Operator in the case of '<'
428 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
431 // If the symbol/expression is defined then check for valid range.
432 // Otherwise the value had better fit or Fixups will bark!
433 if (*AnEXATTR & DEFINED)
437 warn("short addressing mode forced but address is bigger than $3F - switching to long");
439 *memspace = 1 << 6; // Mark we're on Y memory space
446 // Mark it as a fixup
447 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
451 *memspace = 1 << 6; // Mark we're on Y memory space
452 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
455 else if (*tok == '>')
457 // Long Addressing Mode Force Operator
460 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
462 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
465 if (*AnEXATTR&DEFINED)
467 if (*AnEXVAL > 0xFFFFFF)
468 return error("long address is bigger than $FFFFFF");
470 *memspace = 1 << 6; // Mark we're on Y memory space
478 *memspace = 1 << 6; // Mark we're on Y memory space
485 else if (*tok == SHL) // '<<'
487 // I/O Short Addressing Mode Force Operator
491 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
494 // If the symbol/expression is defined then check for valid range.
495 // Otherwise the value had better fit or Fixups will bark!
496 if (*AnEXATTR & DEFINED)
498 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
500 if (*AnEXVAL < 0xFFFFFFC0)
501 return error("I/O Short Addressing Mode addresses must be between $FFE0 and $1F");
505 *memspace = 1 << 6; // Mark we're on Y memory space
506 *perspace = 1 << 16; // Mark we're on Y peripheral space
507 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
511 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
513 *memspace = 1 << 6; // Mark we're on Y memory space
519 // TODO: add absolute address checks
521 else if ((*tok >= KW_X) && (*tok <= KW_Y))
527 else if ((*tok >= KW_M0) && (*tok <= KW_M7))
530 *areg = (*tok++) & 7;
533 else if ((*tok >= KW_R0) && (*tok <= KW_R7))
536 *areg = (*tok++) - KW_R0;
539 else if ((*tok >= KW_N0) && (*tok <= KW_N7))
542 *areg = (*tok++) & 7;
545 else if ((*tok == KW_A0) || (*tok == KW_A1) || (*tok == KW_B0)
552 else if ((*tok == KW_A2) || (*tok == KW_B2))
558 else if ((*tok == '-') && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
560 // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
563 // Check to see if this is the first operand
565 return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
572 else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
574 // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
577 // Check to see if this is the first operand
579 return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
586 else if (*tok == '(' || *tok == '-')
588 // Could be either an expression or ea mode
589 if (*tok + 1 == SYMBOL)
593 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
600 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
608 // TODO: add absolute address checks
609 return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
611 else if (*tok == KW_P && *(tok + 1) == ':')
615 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
618 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
621 if (*AnEXVAL > 0xFFFFFF)
622 return error("long address is bigger than $FFFFFF");
631 *areg = (int)*AnEXVAL; // Lame, but what the hell
637 else if (*tok == '<')
640 // Short Addressing Mode Force Operator in the case of '<'
643 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
647 return error("short addressing mode forced but address is bigger than $3F");
650 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
653 else if (*tok == '>')
655 // Long Addressing Mode Force Operator
658 // Immediate Short Addressing Mode Force Operator
659 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
662 if (*AnEXATTR & DEFINED)
664 if (*AnEXVAL > 0xFFFFFF)
665 return error("long address is bigger than $FFFFFF");
673 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
681 else if (*tok == SHL)
683 // I/O Short Addressing Mode Force Operator
686 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
689 if (*AnEXVAL > 0xFFF)
690 return error("I/O short addressing mode forced but address is bigger than $FFF");
695 else if (*tok == '<')
697 // Short Addressing Mode Force Operator
700 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
703 if (*AnEXATTR & DEFINED)
705 if (*AnEXVAL > 0xFFF)
706 return error("short addressing mode forced but address is bigger than $FFF");
712 else if (*tok == '>')
714 // Long Addressing Mode Force Operator
717 // Immediate Short Addressing Mode Force Operator
718 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
721 if (*AnEXATTR & DEFINED)
723 if (*AnEXVAL > 0xFFFFFF)
724 return error("long address is bigger than $FFFFFF");
731 else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
740 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
743 // We'll store M_DSPEA_ABS in areg and if we have
744 // any extra info, it'll go in am
745 if (*AnEXATTR & DEFINED)
749 if (*AnEXVAL < 0x1000)
751 else if (*AnEXVAL < 0x10000)
753 else if (*AnEXVAL < 0x1000000)
756 return error("address must be smaller than $1000000");
762 // Well, we have no opinion on the expression's size, so let's assume the worst
769 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
774 // Parse all addressing modes except parallel moves
776 int dsp_amode(int maxea)
779 // Initialize global return values
780 nmodes = dsp_a0reg = dsp_a1reg = 0;
781 dsp_am0 = dsp_am1 = M_AM_NONE;
782 dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
785 dsp_a0exattr = dsp_a1exattr = 0;
786 dsp_a0esym = dsp_a1esym = (SYM *)NULL;
787 dsp_a0memspace = dsp_a1memspace = -1;
788 dsp_a0perspace = dsp_a1perspace = -1;
791 // If at EOL, then no addr modes at all
795 if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
799 // If caller wants only one mode, return just one (ignore comma);
800 // If there is no second addressing mode (no comma), then return just one anyway.
806 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
814 // Parse second addressing mode
815 if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
818 if (maxea == 2 || *tok == EOL)
821 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
829 // Only MAC-like or jsset/clr/tst/chg instructions here
831 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
836 return error(extra_stuff);
842 // Only Tcc instructions here, and then only those that accept 4 operands
844 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
848 return error("expected 4 parameters");
850 if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
856 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
863 // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
864 return error(extra_stuff);
867 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
872 // Helper function which gives us the encoding of a DSP register
874 static inline int SDreg(int reg)
876 if (reg >= KW_X0 && reg <= KW_N7)
878 else if (reg >= KW_A0&® <= KW_A2)
879 return (8 >> (reg & 7)) | 8;
880 else //if (reg>=KW_R0&®<=KW_R7)
881 return reg - KW_R0 + 16;
882 // Handy map for the above:
883 // (values are of course taken from keytab)
884 // Register | Value | Return value
917 // Check for X:Y: parallel mode syntax
919 static inline LONG check_x_y(LONG ea1, LONG S1)
922 LONG eax_temp, eay_temp;
923 LONG D1, D2, S2, ea2;
925 LONG w = 1 << 7; // S1=0, D1=1<<14
927 if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
928 (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
932 case DSP_EA_POSTINC: ea1 = (ea1 & (~0x38)) | 0x8; break;
933 case DSP_EA_POSTINC1: ea1 = (ea1 & (~0x38)) | 0x18; break;
934 case DSP_EA_POSTDEC1: ea1 = (ea1 & (~0x38)) | 0x10; break;
935 case DSP_EA_NOUPD: ea1 = (ea1 & (~0x38)) | 0x00; break;
940 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
942 switch (K_D1 = *tok++)
944 case KW_X0: D1 = 0 << 10; break;
945 case KW_X1: D1 = 1 << 10; break;
946 case KW_A: D1 = 2 << 10; break;
947 case KW_B: D1 = 3 << 10; break;
948 default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
953 // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
958 case 4: D1 = 0 << 10; break;
959 case 5: D1 = 1 << 10; break;
960 case 14: D1 = 2 << 10; break;
961 case 15: D1 = 3 << 10; break;
962 default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
969 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
971 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
975 if (*tok >= KW_R0 && *tok <= KW_R7)
977 ea2 = (*tok++ - KW_R0);
979 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
980 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'");
983 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
985 // If eax register is r0-r3 then eay register is r4-r7.
986 // Encode that to 2 bits (i.e. eay value is 0-3)
987 eax_temp = (ea2 & 3) << 5; // Store register temporarily
990 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
1002 else if (*tok >= KW_N0 && *tok <= KW_N7)
1005 if ((*tok++ & 7) != ea2)
1006 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')");
1011 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
1014 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
1017 else if (*tok == '-')
1024 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
1026 else if (*tok++ == ',')
1032 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
1034 ea2 |= eax_temp; // OR eay back from temp
1036 switch (K_D2 = *tok++)
1038 case KW_Y0: D2 = 0 << 8; break;
1039 case KW_Y1: D2 = 1 << 8; break;
1040 case KW_A: D2 = 2 << 8; break;
1041 case KW_B: D2 = 3 << 8; break;
1042 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1046 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
1050 return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
1052 inst = B16(11000000, 00000000) | w;
1053 inst |= ea1 | D1 | ea2 | D2;
1057 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1059 else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1061 // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1064 case KW_Y0: S2 = 0 << 8; break;
1065 case KW_Y1: S2 = 1 << 8; break;
1066 case KW_A: S2 = 2 << 8; break;
1067 case KW_B: S2 = 3 << 8; break;
1068 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1072 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1076 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1078 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1082 if (*tok >= KW_R0 && *tok <= KW_R7)
1084 ea2 = (*tok++ - KW_R0);
1086 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
1087 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'");
1090 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
1091 // If eax register is r0-r3 then eay register is r4-r7.
1092 // Encode that to 2 bits (i.e. eay value is 0-3)
1093 eay_temp = (ea2 & 3) << 5; //Store register temporarily
1096 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1105 else if (*tok >= KW_N0 && *tok <= KW_N7)
1108 if ((*tok++ & 7) != ea2)
1109 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')");
1114 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1117 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1120 else if (*tok == '-')
1126 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1128 else if (*tok == EOL)
1134 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1136 ea2 |= eay_temp; //OR eay back from temp
1138 inst = B16(10000000, 00000000) | w;
1139 inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1143 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1146 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1149 return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
1152 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1156 // Parse X: addressing space parallel moves
1158 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1160 int immreg; // Immediate register destination
1161 LONG S2, D1, D2; // Source and Destinations
1162 LONG ea1; // ea bitfields
1163 uint32_t termchar = ','; // Termination character for ea checks
1164 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1165 ea1 = -1; // initialise e1 (useful for some code paths)
1172 if (tok[1] == CONST || tok[1] == FCONST)
1175 dspImmedEXVAL = *tok++;
1179 // This could be either -(Rn), -aa or -ea. Check for immediate first
1180 if (tok[1] == SYMBOL)
1182 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1187 // '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'
1188 if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
1191 if (ea1 == DSP_EA_ABS)
1192 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1195 return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1198 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
1200 if (ea1 == B8(00110100))
1201 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
1203 inst = B16(00001000, 00000000) | ea1 | (0 << 8);
1206 else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1209 if (ea1 == DSP_EA_ABS)
1210 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1213 return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1216 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
1218 if (ea1 == B8(00110100))
1219 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
1221 inst = B16(00001001, 00000000) | ea1 | (1 << 8);
1224 else if (*tok == KW_A || *tok == KW_B)
1226 // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1229 case 4: D1 = 0 << 10; break;
1230 case 5: D1 = 1 << 10; break;
1231 case 14: D1 = 2 << 10; break;
1232 case 15: D1 = 3 << 10; break;
1233 default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
1236 if (tok[1] == ',' && tok[2] == KW_Y)
1238 // 'S1,X:eax S2,Y:eay'
1239 return check_x_y(ea1, S1);
1243 if (ea1 == DSP_EA_ABS)
1244 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1248 case KW_A: S2 = 0 << 9; break;
1249 case KW_B: S2 = 1 << 9; break;
1250 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
1254 return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1256 if (*tok == KW_Y0 || *tok == KW_Y1)
1258 if (*tok++ == KW_Y0)
1264 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1266 inst = B16(00010000, 00000000) | (0 << 7);
1267 inst |= ea1 | D1 | S2 | D2;
1271 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1273 else if (*tok == KW_Y)
1275 // 'S1,X:eax Y:eay,D2'
1276 return check_x_y(ea1, S1);
1278 else if (*tok == KW_Y0 || *tok == KW_Y1)
1280 // 'S1,X:eax S2,Y:eay'
1281 return check_x_y(ea1, S1);
1284 return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1288 // Only check for aa if we have a defined number in our hands or we've
1289 // been asked to use a short number format. The former case we'll just test
1290 // it to see if it's small enough. The later - it's the programmer's call
1291 // so he'd better have a small address or the fixups will bite him/her in the arse!
1292 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1295 // It's an immediate, so ea or eax is probably an absolute address
1296 // (unless it's aa if the immediate is small enough)
1297 // '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'
1299 // Check for aa (which is 6 bits zero extended)
1300 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1304 // It might be X:aa but we're not 100% sure yet.
1305 // If it is, the only possible syntax here is 'X:aa,D'.
1306 // So check ahead to see if EOL follows D, then we're good to go.
1307 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)
1309 // Yup, we're good to go - 'X:aa,D' it is
1311 immreg = SDreg(*tok++);
1312 inst = inst | (uint32_t)dspImmedEXVAL;
1313 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1314 inst |= 1 << 7; // W
1323 inst = inst | (uint32_t)dspImmedEXVAL;
1324 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1329 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1330 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1332 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1333 goto x_checkea_right;
1339 // Well, that settles it - we do have an ea in our hands
1342 // 'X:ea,D' [... S2,d2]
1344 return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
1346 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1353 inst = inst | B8(01000000) | (1 << 7);
1354 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1357 if (ea1 == DSP_EA_ABS)
1358 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1365 if (*tok == KW_A || *tok == KW_B)
1370 return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1372 if (*tok == KW_Y0 || *tok == KW_Y1)
1377 return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
1379 inst = B16(00010000, 00000000) | (1 << 7);
1380 inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
1381 inst |= (S2 & 1) << 9;
1382 inst |= (D2 & 1) << 8;
1387 return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1390 return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1394 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,'");
1401 inst = inst | B8(01000000) | (0 << 7);
1402 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1405 if (ea1 == DSP_EA_ABS)
1406 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1412 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1413 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1414 goto x_checkea_right;
1423 // It's not an immediate, check for '-(Rn)'
1424 ea1 = checkea(termchar, X_ERRORS);
1433 else if (*tok == '#')
1437 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1440 // Okay so we have immediate data - mark it down
1442 // Now, proceed to the main code for this branch
1445 else if (*tok == '(')
1447 // Maybe we got an expression here, check for it
1448 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1450 // Evaluate the expression and go to immediate code path
1451 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1455 // Nope, let's check for ea then
1456 ea1 = checkea(termchar, X_ERRORS);
1465 return error("Comma expected after 'X:(Rn)')");
1467 // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
1468 // If it is, the only possible syntax here is 'X:ea,D'.
1469 // So check ahead to see if EOL follows D, then we're good to go.
1470 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1475 inst = inst | B8(01000000) | (1 << 7);
1477 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1486 inst = inst | B8(01000000) | (0 << 7);
1488 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1493 goto x_checkea_right;
1497 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
1498 // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
1499 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)))
1502 // Check if D1 is x0, x1, a or b
1505 case KW_X0: D1 = 0 << 10; break;
1506 case KW_X1: D1 = 1 << 10; break;
1507 case KW_A: D1 = 2 << 10; break;
1508 case KW_B: D1 = 3 << 10; break;
1509 default: return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
1514 case KW_A: S2 = 0 << 9; break;
1515 case KW_B: S2 = 1 << 9; break;
1516 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
1520 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1522 if (*tok == KW_Y0 || *tok == KW_Y1)
1524 if (*tok++ == KW_Y0)
1530 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1532 inst = B16(00010000, 00000000) | (W << 7);
1533 inst |= ea1 | D1 | S2 | D2;
1537 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1540 // Check to see if we got eax (which is a subset of ea)
1543 if ((inst = check_x_y(ea1, 0)) != 0)
1547 // Rewind pointer as it might be an expression and check for it
1550 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1553 // Yes, we have an expression, so we now check for
1554 // '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'
1559 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1561 // Check for immediate address
1562 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1565 // We set ea1 here - if it's aa instead of ea
1566 // then it won't be used anyway
1569 if (!(dspImmedEXATTR&DEFINED))
1571 force_imm = NUM_FORCE_LONG;
1572 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1577 else if (*tok == '>')
1579 // Check for immediate address forced long
1582 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1585 if (dspImmedEXATTR & DEFINED)
1586 if (dspImmedEXVAL > 0xffffff)
1587 return error("long address is bigger than $ffffff");
1589 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1591 force_imm = NUM_FORCE_LONG;
1595 else if (*tok == '<')
1597 // Check for immediate address forced short
1600 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1603 force_imm = NUM_FORCE_SHORT;
1605 if (dspImmedEXATTR & DEFINED)
1607 if (dspImmedEXVAL > 0x3F)
1609 warn("short addressing mode forced but address is bigger than $3F - switching to long");
1610 force_imm = NUM_FORCE_LONG;
1611 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1617 // This might end up as something like 'move Y:<adr,register'
1618 // so let's mark it as an extra aa fixup here.
1619 // Note: we are branching to x_check_immed without a
1620 // defined dspImmed so it's going to be 0. It probably
1621 // doesn't harm anything.
1622 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1628 return error("unknown x: addressing mode");
1633 // Parse Y: addressing space parallel moves
1635 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1637 int immreg; // Immediate register destination
1638 LONG D2; // Destination
1639 LONG ea1; // ea bitfields
1640 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1643 if (tok[1] == CONST || tok[1] == FCONST)
1646 dspImmedEXVAL = *tok++;
1649 // This could be either -(Rn), -aa or -ea. Check for immediate first
1650 if (*tok == SYMBOL || tok[1] == SYMBOL)
1652 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1654 // Only check for aa if we have a defined number in our hands or we've
1655 // been asked to use a short number format. The former case we'll just test
1656 // it to see if it's small enough. The later - it's the programmer's call
1657 // so he'd better have a small address or the fixups will bite him/her in the arse!
1658 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1660 // It's an immediate, so ea is probably an absolute address
1661 // (unless it's aa if the immediate is small enough)
1662 // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
1664 // Check for aa (which is 6 bits zero extended)
1665 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1667 // It might be Y:aa but we're not 100% sure yet.
1668 // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
1669 // So check ahead to see if EOL follows D, then we're good to go.
1670 if (*tok == EOL && S1 != 0)
1673 inst = B16(01001000, 00000000);
1674 inst |= dspImmedEXVAL;
1675 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1678 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)
1680 // Yup, we're good to go - 'Y:aa,D' it is
1682 immreg = SDreg(*tok++);
1683 inst |= dspImmedEXVAL;
1684 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1689 // Well, that settles it - we do have a ea in our hands
1690 if (*tok == EOL && S1 != 0)
1693 inst = B16(01001000, 01110000);
1695 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1696 if (ea1 == DSP_EA_ABS)
1697 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1701 return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1702 if (D1 == 0 && S1 == 0)
1705 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1709 return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1710 inst |= B16(00000000, 01110000);
1712 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1713 if (ea1 == DSP_EA_ABS)
1714 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1718 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,'");
1723 if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1728 inst |= (S1 & 1) << 11;
1729 inst |= (D1 & 1) << 10;
1730 inst |= (D2 & 8) << (9 - 3);
1731 inst |= (D2 & 1) << 8;
1735 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1743 // It's not an immediate, check for '-(Rn)'
1744 ea1 = checkea(',', Y_ERRORS);
1753 else if (*tok == '#')
1756 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1758 // Okay so we have immediate data - mark it down
1760 // Now, proceed to the main code for this branch
1763 else if (*tok == '(')
1765 // Maybe we got an expression here, check for it
1766 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1768 // Evaluate the expression and go to immediate code path
1769 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1773 // Nope, let's check for ea then
1774 if (S1 == 0 || (S1 != 0 && D1 != 0))
1775 ea1 = checkea(',', Y_ERRORS);
1777 ea1 = checkea(EOL, Y_ERRORS);
1783 if (S1 != 0 && *tok == EOL)
1786 inst = B16(01001000, 01000000);
1788 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1791 else if (S1 != 0 && D1 != 0 && S2 == 0)
1796 case 14: S1 = 0 << 11; break; // A
1797 case 15: S1 = 1 << 11; break; // B
1798 default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
1802 case 4: D1 = 0 << 10; break; // X0
1803 case 5: D1 = 1 << 10; break; // X1
1804 default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
1807 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1810 case KW_Y0: D2 = 0 << 8; break;
1811 case KW_Y1: D2 = 1 << 8; break;
1812 case KW_A: D2 = 2 << 8; break;
1813 case KW_B: D2 = 3 << 8; break;
1814 default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
1816 inst = B16(00010000, 11000000);
1817 inst |= S1 | D1 | D2;
1822 return error("Comma expected after 'Y:(Rn)')");
1823 // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
1824 // If it is, the only possible syntax here is 'Y:ea,D'.
1825 // So check ahead to see if EOL follows D, then we're good to go.
1826 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1830 inst |= B16(00000000, 01000000);
1832 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1836 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1838 // Check for immediate address
1839 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1842 // Yes, we have an expression, so we now check for
1843 // 'Y:ea,D' or 'Y:aa,D'
1844 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1845 if (!(dspImmedEXATTR&DEFINED))
1847 force_imm = NUM_FORCE_LONG;
1848 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1853 else if (*tok == '>')
1855 // Check for immediate address forced long
1857 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1859 if (dspImmedEXATTR & DEFINED)
1860 if (dspImmedEXVAL > 0xffffff)
1861 return error("long address is bigger than $ffffff");
1863 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1865 force_imm = NUM_FORCE_LONG;
1869 else if (*tok == '<')
1872 if (S1 != 0 && D1 != 0)
1874 // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
1875 // there's no Y:aa mode here, so we'll force long
1876 warn("forced short addressing in R:Y mode is not allowed - switching to long");
1878 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1883 force_imm = NUM_FORCE_LONG;
1884 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1889 // Check for immediate address forced short
1890 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1892 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1894 force_imm = NUM_FORCE_SHORT;
1895 if (dspImmedEXATTR & DEFINED)
1897 if (dspImmedEXVAL > 0xfff)
1899 warn("short addressing mode forced but address is bigger than $fff - switching to long");
1901 force_imm = NUM_FORCE_LONG;
1902 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1907 // This might end up as something like 'move Y:<adr,register'
1908 // so let's mark it as an extra aa fixup here.
1909 // Note: we are branching to y_check_immed without a
1910 // defined dspImmed so it's going to be 0. It probably
1911 // doesn't harm anything.
1912 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1919 return error("unrecognised Y: parallel move syntax");
1924 // Parse L: addressing space parallel moves
1926 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1928 int immreg; // Immediate register destination
1929 LONG D1; // Source and Destinations
1930 LONG ea1; // ea bitfields
1931 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1934 if (*tok == CONST || tok[1] == FCONST)
1937 dspImmedEXVAL = *tok++;
1940 // This could be either -(Rn), -aa or -ea. Check for immediate first
1941 // Maybe we got an expression here, check for it
1942 if (*tok == SYMBOL || tok[1] == SYMBOL)
1944 // Evaluate the expression and go to immediate code path
1945 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1947 // Only check for aa if we have a defined number in our hands or we've
1948 // been asked to use a short number format. The former case we'll just test
1949 // it to see if it's small enough. The later - it's the programmer's call
1950 // so he'd better have a small address or the fixups will bite him/her in the arse!
1951 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1953 // It's an immediate, so ea is probably an absolute address
1954 // (unless it's aa if the immediate is small enough)
1955 // 'L:ea,D' or 'L:aa,D'
1957 // Check for aa (which is 6 bits zero extended)
1961 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1966 else if (S1 == KW_B)
1971 inst = B16(01000000, 00000000);
1972 inst |= dspImmedEXVAL;
1973 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1981 else if (S1 == KW_B)
1986 if (ea1 == DSP_EA_ABS)
1987 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1989 inst |= B16(01000000, 01110000);
1990 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1997 return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
1998 // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
1999 if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
2000 return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
2002 if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
2009 else if (immreg == KW_B)
2015 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
2017 inst &= B16(11111111, 10111111);
2018 inst |= dspImmedEXVAL;
2019 inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
2024 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
2026 // Hang on, we've got a L:<aa here, let's do that instead
2030 // Well, that settles it - we do have a ea in our hands
2035 else if (D1 == KW_B)
2041 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
2043 inst |= B16(00000000, 00110000);
2044 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2050 //It's not an immediate, check for '-(Rn)'
2051 ea1 = checkea(',', L_ERRORS);
2060 else if (*tok == '(')
2062 // Maybe we got an expression here, check for it
2063 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
2065 // Evaluate the expression and go to immediate code path
2066 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
2070 //Nope, let's check for ea then
2072 ea1 = checkea(',', L_ERRORS);
2074 ea1 = checkea(EOL, L_ERRORS);
2083 inst = B16(01000000, 01000000);
2086 else if (S1 == KW_B)
2092 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2095 else if (*tok++ != ',')
2096 return error("Comma expected after 'L:(Rn)')");
2098 // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
2099 // If it is, the only possible syntax here is 'L:ea,D'.
2100 // So check ahead to see if EOL follows D, then we're good to go.
2101 if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
2107 else if (D1 == KW_B)
2113 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2117 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2119 // Check for immediate address
2120 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2123 // We set ea1 here - if it's aa instead of ea
2124 // then it won't be used anyway
2126 if (!(dspImmedEXATTR & DEFINED))
2128 force_imm = NUM_FORCE_LONG;
2129 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2131 else if (dspImmedEXVAL > 0x3f)
2133 // Definitely no aa material, so it's going to be a long
2134 // Mark that we need to deposit an extra word
2135 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2138 // Yes, we have an expression, so we now check for
2139 // 'L:ea,D' or 'L:aa,D'
2142 else if (*tok == '>')
2144 // Check for immediate address forced long
2146 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2148 if (dspImmedEXATTR & DEFINED)
2149 if (dspImmedEXVAL > 0xffffff)
2150 return error("long address is bigger than $ffffff");
2152 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2154 force_imm = NUM_FORCE_LONG;
2157 else if (*tok == '<')
2159 // Check for immediate address forced short
2161 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2163 if (dspImmedEXATTR & DEFINED)
2165 if (dspImmedEXVAL > 0xfff)
2166 return error("short addressing mode forced but address is bigger than $fff");
2170 // This might end up as something like 'move Y:<adr,register'
2171 // so let's mark it as an extra aa fixup here.
2172 // Note: we are branching to l_check_immed without a
2173 // defined dspImmed so it's going to be 0. It probably
2174 // doesn't harm anything.
2175 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
2178 force_imm = NUM_FORCE_SHORT;
2182 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");
2187 // Checks for all ea cases where indexed addressing is concenred
2189 static inline LONG checkea(const uint32_t termchar, const int strings)
2197 return error(ea_errors[strings][0]);
2198 if (*tok >= KW_R0 && *tok <= KW_R7)
2200 // We got '-(Rn' so mark it down
2201 ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2203 return error(ea_errors[strings][1]);
2204 // Now, proceed to the main code for this branch
2208 return error(ea_errors[strings][2]);
2210 else if (*tok == '(')
2212 // Checking for ea of type (Rn)
2214 if (*tok >= KW_R0 && *tok <= KW_R7)
2216 // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2217 ea = *tok++ - KW_R0;
2222 if (*tok < KW_N0 || *tok > KW_N7)
2223 return error(ea_errors[strings][3]);
2224 if ((*tok++ & 7) != ea)
2225 return error(ea_errors[strings][4]);
2228 return error(ea_errors[strings][5]);
2231 else if (*tok == ')')
2233 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2238 if (termchar == ',')
2243 ea |= DSP_EA_POSTINC1;
2246 else if (*tok >= KW_N0 && *tok <= KW_N7)
2249 if ((*tok++ & 7) != ea)
2250 return error(ea_errors[strings][6]);
2251 ea |= DSP_EA_POSTINC;
2255 return error(ea_errors[strings][7]);
2259 if (*tok >= KW_N0 && *tok <= KW_N7)
2262 if ((*tok++ & 7) != ea)
2263 return error(ea_errors[strings][6]);
2264 ea |= DSP_EA_POSTINC;
2270 ea |= DSP_EA_POSTINC1;
2275 else if (*tok == '-')
2278 if (termchar == ',')
2283 ea |= DSP_EA_POSTDEC1;
2286 else if (*tok >= KW_N0 && *tok <= KW_N7)
2289 if ((*tok++ & 7) != ea)
2290 return error(ea_errors[strings][8]);
2291 ea |= DSP_EA_POSTDEC;
2295 return error(ea_errors[strings][9]);
2299 if (*tok >= KW_N0 && *tok <= KW_N7)
2302 if ((*tok++ & 7) != ea)
2303 return error(ea_errors[strings][8]);
2304 ea |= DSP_EA_POSTDEC;
2310 ea |= DSP_EA_POSTDEC1;
2315 else if (termchar == ',')
2324 return error(ea_errors[strings][10]);
2334 return error(ea_errors[strings][11]);
2337 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");
2342 // Checks for all ea cases, i.e. all addressing modes that checkea handles
2343 // plus immediate addresses included forced short/long ones.
2344 // In other words this is a superset of checkea (and in fact calls checkea).
2346 LONG checkea_full(const uint32_t termchar, const int strings)
2350 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2352 // Check for immediate address
2353 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2356 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2358 // Yes, we have an expression
2361 else if (*tok == '>')
2363 // Check for immediate address forced long
2365 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2367 if (dspImmedEXATTR & DEFINED)
2368 if (dspImmedEXVAL > 0xffffff)
2369 return error("long address is bigger than $ffffff");
2371 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2373 // Yes, we have an expression
2376 else if (*tok == '<')
2378 // Check for immediate address forced short
2380 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2382 if (dspImmedEXATTR & DEFINED)
2383 if (dspImmedEXVAL > 0xfff)
2384 return error("short addressing mode forced but address is bigger than $fff");
2386 // Yes, we have an expression
2391 ea1 = checkea(termchar, strings);
2402 // Main routine to check parallel move modes.
2403 // It's quite complex so it's split into a few procedures (in fact most of the
2404 // above ones). A big effort was made so this can be managable and not too
2405 // hacky, however one look at the 56001 manual regarding parallel moves and
2406 // you'll know that this is not an easy // problem to deal with!
2407 // dest=destination register from the main opcode. This must not be the same
2408 // as D1 or D2 and that even goes for stuff like dest=A, D1=A0/1/2!!!
2410 LONG parmoves(WORD dest)
2412 int force_imm; // Addressing mode force operator
2413 int immreg; // Immediate register destination
2414 LONG inst; // 16 bit bitfield that has the parallel move opcode
2415 LONG S1, S2, D1, D2; // Source and Destinations
2416 LONG ea1; // ea bitfields
2421 return B16(00100000, 00000000);
2426 // '#xxxxxx,D', '#xx,D'
2428 force_imm = NUM_NORMAL;
2432 force_imm = NUM_FORCE_LONG;
2435 else if (*tok == '<')
2437 force_imm = NUM_FORCE_SHORT;
2441 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2445 return error("expected comma");
2447 if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
2448 return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
2450 immreg = SDreg(*tok++);
2454 if (!(dspImmedEXATTR & FLOAT))
2456 if (dspImmedEXATTR & DEFINED)
2458 // From I parallel move:
2459 // "If the destination register D is X0, X1, Y0, Y1, A, or B, the 8-bit immediate short operand
2460 // is interpreted as a signed fraction and is stored in the specified destination register.
2461 // That is, the 8 - bit data is stored in the eight MS bits of the destination operand, and the
2462 // remaining bits of the destination operand D are zeroed."
2463 // The funny bit is that Motorola assembler can parse something like 'move #$FF0000,b' into an
2464 // I (immediate short move) - so let's do that as well then...
2465 if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
2467 if ((dspImmedEXVAL & 0xffff) == 0)
2469 dspImmedEXVAL >>= 16;
2473 if (force_imm == NUM_FORCE_SHORT)
2475 if (dspImmedEXVAL < 0xFF && (int32_t)dspImmedEXVAL > -0x100)
2478 // value fits in 8 bits - immediate move
2479 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2484 warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2485 force_imm = NUM_FORCE_LONG;
2489 if (force_imm == NUM_FORCE_LONG)
2493 // X or Y Data move. I don't think it matters much
2494 // which of the two it will be, so let's use X.
2495 deposit_immediate_long_with_register:
2496 inst = B16(01000000, 11110100);
2497 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2498 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2502 if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2504 // value fits in 8 bits - immediate move
2505 deposit_immediate_short_with_register:
2506 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2511 // value doesn't fit in 8 bits, so it can either be
2512 // X or Y Data move. I don't think it matters much
2513 // which of the two it will be, so let's use X:.
2514 // TODO: if we're just goto'ing perhaps the logic can be simplified
2515 goto deposit_immediate_long_with_register;
2520 if (force_imm != NUM_FORCE_SHORT)
2523 // TODO: if we're just goto'ing perhaps the logic can be simplified
2524 goto deposit_immediate_long_with_register;
2529 // No visibility of the number so let's add a fixup for this
2530 AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
2531 inst = B16(00100000, 00000000);
2532 inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
2540 if (dspImmedEXATTR & DEFINED)
2542 double f = *(double *)&dspImmedEXVAL;
2543 // Check direct.c for ossom comments regarding conversion!
2544 //N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
2545 dspImmedEXVAL = ((uint32_t)(int32_t)round(f * (1 << 23))) & 0xFFFFFF;
2550 if ((dspImmedEXVAL & 0xFFFF) == 0)
2552 // Value's 16 lower bits are not set so the value can fit in a single byte
2553 // (check parallel I move quoted above)
2554 warn("Immediate value fits inside 8 bits, so using instruction short format");
2555 dspImmedEXVAL >>= 16;
2556 goto deposit_immediate_short_with_register;
2559 if (force_imm == NUM_FORCE_SHORT)
2561 if ((dspImmedEXVAL & 0xFFFF) != 0)
2563 warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
2564 goto deposit_immediate_long_with_register;
2567 return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2570 // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
2571 goto deposit_immediate_long_with_register;
2575 if (force_imm == NUM_FORCE_SHORT)
2577 goto deposit_immediate_short_with_register;
2581 // Just deposit a float fixup
2582 AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
2583 inst = B16(00100000, 00000000);
2584 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2592 // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2595 case 4: D1 = 0 << 10;break; // X0
2596 case 5: D1 = 1 << 10;break; // X1
2597 case 14: D1 = 2 << 10;break; // A
2598 case 15: D1 = 3 << 10;break; // B
2599 default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
2604 case KW_A: S2 = 0 << 9; break;
2605 case KW_B: S2 = 1 << 9; break;
2606 default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
2610 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2614 case KW_Y0: D2 = 0 << 8; break;
2615 case KW_Y1: D2 = 1 << 8; break;
2616 default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
2620 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2622 inst = B16(00010000, 10110100) | D1 | S2 | D2;
2623 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2627 else if (*tok == KW_X)
2630 // Hey look, it's just the register X and not the addressing mode - fall through to general case
2631 goto parse_everything_else;
2636 return error("expected ':' after 'X' in parallel move (i.e. X:)");
2638 // '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'
2639 return parse_x(1, B16(01000000, 00000000), 0, 1);
2641 else if (*tok == KW_Y)
2644 // Hey look, it's just the register y and not the addressing mode - fall through to general case
2645 goto parse_everything_else;
2650 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2652 // 'Y:ea,D' or 'Y:aa,D'
2653 return parse_y(B16(01001000, 10000000), 0, 0, 0);
2655 else if (*tok == KW_L)
2657 // 'L:ea,D' or 'L:aa,D'
2660 return error("expected ':' after 'L' in parallel move (i.e. L:)");
2662 return parse_l(1, B16(01000000, 11000000), 0);
2664 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))
2666 // Everything else - brace for impact!
2668 // X: 'S,X:ea' 'S,X:aa'
2669 // X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
2670 // Y: 'S,Y:ea' 'S,Y:aa'
2671 // 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'
2672 // L: 'S,L:ea' 'S,L:aa'
2674 parse_everything_else:
2679 return error("Comma expected after 'S')");
2683 // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
2684 // 'A,X:ea X0,A' 'B,X:ea X0,B'
2688 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2690 return parse_x(0, B16(01000000, 00000000), S1, 1);
2692 else if (*tok == KW_Y)
2694 // 'S,Y:ea' 'S,Y:aa'
2698 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2700 return parse_y(B16(0000000, 00000000), S1, 0, 0);
2702 else if (*tok == KW_L)
2704 // 'S,L:ea' 'S,L:aa'
2708 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2710 return parse_l(1, B16(00000000, 00000000), L_S1);
2712 else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2715 // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
2716 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2722 inst = B16(00100000, 00000000);
2723 inst |= (S1 << 5) | (D1);
2726 else if (*tok == KW_Y)
2731 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2732 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2735 else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2737 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2740 if (S1 == 6 && D1 == 14 && S2 == 14)
2744 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2747 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2750 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2752 ea1 = checkea_full(EOL, Y_ERRORS);
2757 inst = B16(00001000, 10000000);
2762 else if (S1 == 6 && D1 == 15 && S2 == 15)
2766 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2769 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2772 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2774 ea1 = checkea_full(EOL, Y_ERRORS);
2779 inst = B16(00001000, 10000000);
2784 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2788 return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2791 return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2794 return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2796 ea1 = checkea_full(EOL, Y_ERRORS);
2801 inst = B16(00010000, 01000000);
2802 inst |= (S1 & 1) << 11;
2803 inst |= (D1 & 1) << 10;
2804 inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2809 return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2812 else if (*tok == '#')
2814 // R:Y: 'S1,D1 #xxxxxx,D2'
2819 // Well, forcing an immediate to be 24 bits is legal here
2820 // but then it's the only available option so my guess is that this
2821 // is simply superfluous. So let's just eat the character
2825 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2828 if (dspImmedEXATTR & DEFINED)
2829 if (dspImmedEXVAL > 0xffffff)
2830 return error("immediate is bigger than $ffffff");
2832 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2835 return error("Comma expected after 'S1,D1 #xxxxxx')");
2837 // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
2840 case KW_Y0: D2 = 0 << 8; break;
2841 case KW_Y1: D2 = 1 << 8; break;
2842 case KW_A: D2 = 2 << 8; break;
2843 case KW_B: D2 = 3 << 8; break;
2844 default: return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
2847 if (S1 == 14 || S1 == 15)
2849 if (D1 == 4 || D1 == 5)
2851 inst = B16(00010000, 11110100);
2852 inst |= (S1 & 1) << 11;
2853 inst |= (D1 & 1) << 10;
2855 dspImmedEXVAL = dspaaEXVAL;
2859 return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2862 return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2865 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2868 return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2870 else if (*tok == '(')
2873 // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2876 if (*tok >= KW_R0 && *tok <= KW_R7)
2878 ea1 = (*tok++ - KW_R0);
2881 return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
2884 return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
2893 else if (*tok >= KW_N0 && *tok <= KW_N7)
2896 if ((*tok++ & 7) != ea1)
2897 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
2902 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
2905 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
2907 else if (*tok == '-')
2917 else if (*tok >= KW_N0 && *tok <= KW_N7)
2920 if ((*tok++ & 7) != ea1)
2921 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
2926 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
2930 inst = B16(00100000, 01000000);
2935 return error("extra (unexpected) text found");