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-2019 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)
169 if (*AnEXVAL > 0xfff && *AnEXVAL<-4096)
170 return error("immediate short addressing mode forced but address is bigger than $fff");
171 if ((int32_t)*AnEXVAL <= 0xff && (int32_t)*AnEXVAL>-0x100)
179 else if (*tok == '>')
181 // Immediate Long Addressing Mode Force Operator
183 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
185 if ((int32_t)*AnEXVAL > 0xffffff || (int32_t)*AnEXVAL < -0xffffff)
186 return error("long immediate is bigger than $ffffff");
191 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
194 if (*AnEXATTR & DEFINED)
196 if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
201 else if (*AnEXVAL < 0x1000)
208 // We have no clue what size our immediate will be
209 // so we have to assume the worst
214 else if (*tok >= KW_X0 && *tok <= KW_Y1)
220 else if (*tok == KW_X && *(tok + 1) == ':')
223 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
225 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
227 if (*AnEXATTR & DEFINED)
229 if (*AnEXVAL > 0xffffff)
230 return error("long address is bigger than $ffffff");
231 *memspace = 0 << 6; // Mark we're on X memory space
233 // Check if value is between $ffc0 and $ffff, AKA X:pp
235 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
236 if ((temp >= 0xffffffc0 /* Check for 32bit sign extended number */
237 && ((int32_t)*AnEXVAL<0)) /* Check if 32bit signed number is negative*/
238 ||(*AnEXVAL<0xffff && *AnEXVAL>=0x8000)) /* Check if 16bit number is negative*/
242 *memspace = 0 << 6; // Mark we're on X memory space
243 *perspace = 0 << 16; // Mark we're on X peripheral space
244 *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5...
250 // If the symbol/expression is defined then check for valid range.
251 // Otherwise the value had better fit or Fixups will bark!
265 *memspace = 0 << 6; // Mark we're on X memory space
271 else if (*tok == '<')
274 // Short Addressing Mode Force Operator in the case of '<'
276 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
279 // If the symbol/expression is defined then check for valid range.
280 // Otherwise the value had better fit or Fixups will bark!
281 if (*AnEXATTR & DEFINED)
284 return error("short addressing mode forced but address is bigger than $3f");
288 // Mark it as a fixup
289 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
292 *memspace = 0 << 6; // Mark we're on X memory space
293 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
296 else if (*tok == '>')
298 // Long Addressing Mode Force Operator
301 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
303 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
305 if (*AnEXATTR&DEFINED)
307 if (*AnEXVAL > 0xffffff)
308 return error("long address is bigger than $ffffff");
309 *memspace = 0 << 6; // Mark we're on X memory space
317 *memspace = 0 << 6; // Mark we're on X memory space
324 else if (*tok == SHL) // '<<'
326 // I/O Short Addressing Mode Force Operator
329 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
332 // If the symbol/expression is defined then check for valid range.
333 // Otherwise the value had better fit or Fixups will bark!
334 if (*AnEXATTR & DEFINED)
336 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
337 if (*AnEXVAL < 0xffffffc0)
338 return error("I/O Short Addressing Mode addresses must be between $ffc0 and $ffff");
341 *memspace = 0 << 6; // Mark we're on X memory space
342 *perspace = 0 << 16; // Mark we're on X peripheral space
343 *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5...
347 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
349 // TODO: what if we need M_DSPAA here????
350 *memspace = 0 << 6; // Mark we're on X memory space
358 else if (*tok == KW_Y && *(tok + 1) == ':')
362 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
364 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
366 if (*AnEXVAL > 0xffffff)
367 return error("long address is bigger than $ffffff");
368 *memspace = 1 << 6; // Mark we're on Y memory space
370 // Check if value is between $ffc0 and $ffff, AKA Y:pp
372 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
373 if ((temp >= 0xffffffc0 /* Check for 32bit sign extended number */
374 && ((int32_t)*AnEXVAL<0)) /* Check if 32bit signed number is negative*/
375 || (*AnEXVAL<0xffff && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
379 *perspace = 1 << 16; // Mark we're on X peripheral space
380 *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5...
386 // If the symbol/expression is defined then check for valid range.
387 // Otherwise the value had better fit or Fixups will bark!
388 if (*AnEXATTR & DEFINED)
408 else if (*tok == '<')
411 // Short Addressing Mode Force Operator in the case of '<'
413 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
416 // If the symbol/expression is defined then check for valid range.
417 // Otherwise the value had better fit or Fixups will bark!
418 if (*AnEXATTR & DEFINED)
422 warn("short addressing mode forced but address is bigger than $3f - switching to long");
424 *memspace = 1 << 6; // Mark we're on Y memory space
431 // Mark it as a fixup
432 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
436 *memspace = 1 << 6; // Mark we're on Y memory space
437 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
440 else if (*tok == '>')
442 // Long Addressing Mode Force Operator
445 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
447 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
449 if (*AnEXATTR&DEFINED)
451 if (*AnEXVAL > 0xffffff)
452 return error("long address is bigger than $ffffff");
453 *memspace = 1 << 6; // Mark we're on Y memory space
461 *memspace = 1 << 6; // Mark we're on Y memory space
468 else if (*tok == SHL) // '<<'
470 // I/O Short Addressing Mode Force Operator
473 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
476 // If the symbol/expression is defined then check for valid range.
477 // Otherwise the value had better fit or Fixups will bark!
478 if (*AnEXATTR & DEFINED)
480 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
481 if (*AnEXVAL < 0xffffffc0)
482 return error("I/O Short Addressing Mode addresses must be between $ffe0 and $1f");
485 *memspace = 1 << 6; // Mark we're on Y memory space
486 *perspace = 1 << 16; // Mark we're on Y peripheral space
487 *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5...
491 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
493 *memspace = 1 << 6; // Mark we're on Y memory space
499 // TODO: add absolute address checks
502 else if (*tok >= KW_X&&*tok <= KW_Y)
508 else if (*tok >= KW_M0 && *tok <= KW_M7)
511 *areg = (*tok++) & 7;
514 else if (*tok >= KW_R0 && *tok <= KW_R7)
517 *areg = (*tok++) - KW_R0;
520 else if (*tok >= KW_N0 && *tok <= KW_N7)
523 *areg = (*tok++) & 7;
526 else if (*tok == KW_A0 || *tok == KW_A1 || *tok == KW_B0 || *tok == KW_B1)
532 else if (*tok == KW_A2 || *tok == KW_B2)
538 else if (*tok == '-' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
540 // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
543 // Check to see if this is the first operand
545 return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
552 else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
554 // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
557 // Check to see if this is the first operand
559 return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
566 else if (*tok == '(' || *tok == '-')
568 // Could be either an expression or ea mode
569 if (*tok + 1 == SYMBOL)
573 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
579 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
586 // TODO: add absolute address checks
587 return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
589 else if (*tok == KW_P && *(tok + 1) == ':')
592 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
595 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
597 if (*AnEXVAL > 0xffffff)
598 return error("long address is bigger than $ffffff");
606 *areg = (int)*AnEXVAL; // Lame, but what the hell
611 else if (*tok == '<')
614 // Short Addressing Mode Force Operator in the case of '<'
616 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
619 return error("short addressing mode forced but address is bigger than $3f");
621 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
624 else if (*tok == '>')
626 // Long Addressing Mode Force Operator
628 // Immediate Short Addressing Mode Force Operator
629 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
631 if (*AnEXATTR & DEFINED)
633 if (*AnEXVAL > 0xffffff)
634 return error("long address is bigger than $ffffff");
641 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
650 else if (*tok == SHL)
652 // I/O Short Addressing Mode Force Operator
654 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
656 if (*AnEXVAL > 0xfff)
657 return error("I/O short addressing mode forced but address is bigger than $fff");
661 else if (*tok == '<')
663 // Short Addressing Mode Force Operator
665 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
667 if (*AnEXATTR & DEFINED)
669 if (*AnEXVAL > 0xfff)
670 return error("short addressing mode forced but address is bigger than $fff");
675 else if (*tok == '>')
677 // Long Addressing Mode Force Operator
679 // Immediate Short Addressing Mode Force Operator
680 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
682 if (*AnEXATTR & DEFINED)
684 if (*AnEXVAL > 0xffffff)
685 return error("long address is bigger than $ffffff");
692 else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
701 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
704 // We'll store M_DSPEA_ABS in areg and if we have
705 // any extra info, it'll go in am
706 if (*AnEXATTR & DEFINED)
709 if (*AnEXVAL < 0x1000)
711 else if (*AnEXVAL < 0x10000)
713 else if (*AnEXVAL < 0x1000000)
716 return error("address must be smaller than $1000000");
721 // Well, we have no opinion on the expression's size, so let's assume the worst
727 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
731 // Parse all addressing modes except parallel moves
733 int dsp_amode(int maxea)
736 // Initialize global return values
737 nmodes = dsp_a0reg = dsp_a1reg = 0;
738 dsp_am0 = dsp_am1 = M_AM_NONE;
739 dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
742 dsp_a0exattr = dsp_a1exattr = 0;
743 dsp_a0esym = dsp_a1esym = (SYM *)NULL;
744 dsp_a0memspace = dsp_a1memspace = -1;
745 dsp_a0perspace = dsp_a1perspace = -1;
748 // If at EOL, then no addr modes at all
752 if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
756 // If caller wants only one mode, return just one (ignore comma);
757 // If there is no second addressing mode (no comma), then return just one anyway.
763 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
771 // Parse second addressing mode
772 if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
775 if (maxea == 2 || *tok == EOL)
778 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
786 // Only MAC-like or jsset/clr/tst/chg instructions here
788 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
793 return error(extra_stuff);
799 // Only Tcc instructions here, and then only those that accept 4 operands
801 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
805 return error("expected 4 parameters");
807 if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
813 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
820 // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
821 return error(extra_stuff);
824 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
830 // Helper function which gives us the encoding of a DSP register
832 static inline int SDreg(int reg)
834 if (reg >= KW_X0 && reg <= KW_N7)
836 else if (reg >= KW_A0&® <= KW_A2)
837 return (8 >> (reg & 7)) | 8;
838 else //if (reg>=KW_R0&®<=KW_R7)
839 return reg - KW_R0 + 16;
840 // Handy map for the above:
841 // (values are of course taken from keytab)
842 // Register | Value | Return value
875 // Check for X:Y: parallel mode syntax
877 static inline LONG check_x_y(LONG ea1, LONG S1)
880 LONG eax_temp, eay_temp;
881 LONG D1, D2, S2, ea2;
883 LONG w = 1 << 7; // S1=0, D1=1<<14
884 if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
885 (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
890 case DSP_EA_POSTINC: ea1 = (ea1&(~0x38)) | 0x8;break;
891 case DSP_EA_POSTINC1: ea1 = (ea1&(~0x38)) | 0x18;break;
892 case DSP_EA_POSTDEC1: ea1 = (ea1&(~0x38)) | 0x10;break;
893 case DSP_EA_NOUPD: ea1 = (ea1&(~0x38)) | 0x00;break;
898 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
900 switch (K_D1 = *tok++)
902 case KW_X0: D1 = 0 << 10; break;
903 case KW_X1: D1 = 1 << 10; break;
904 case KW_A: D1 = 2 << 10; break;
905 case KW_B: D1 = 3 << 10; break;
906 default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
911 // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
915 case 4: D1 = 0 << 10; break;
916 case 5: D1 = 1 << 10; break;
917 case 14: D1 = 2 << 10; break;
918 case 15: D1 = 3 << 10; break;
919 default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
926 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
928 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
931 if (*tok >= KW_R0 && *tok <= KW_R7)
933 ea2 = (*tok++ - KW_R0);
934 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
935 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'");
938 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
939 // If eax register is r0-r3 then eay register is r4-r7.
940 // Encode that to 2 bits (i.e. eay value is 0-3)
941 eax_temp = (ea2 & 3) << 5; // Store register temporarily
943 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
953 else if (*tok >= KW_N0 && *tok <= KW_N7)
956 if ((*tok++ & 7) != ea2)
957 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')");
960 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
963 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
966 else if (*tok == '-')
972 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
974 else if (*tok++ == ',')
980 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
982 ea2 |= eax_temp; // OR eay back from temp
984 switch (K_D2 = *tok++)
986 case KW_Y0: D2 = 0 << 8; break;
987 case KW_Y1: D2 = 1 << 8; break;
988 case KW_A: D2 = 2 << 8; break;
989 case KW_B: D2 = 3 << 8; break;
990 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
994 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
998 return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
1000 inst = B16(11000000, 00000000) | w;
1001 inst |= ea1 | D1 | ea2 | D2;
1005 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1007 else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1009 // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1012 case KW_Y0: S2 = 0 << 8; break;
1013 case KW_Y1: S2 = 1 << 8; break;
1014 case KW_A: S2 = 2 << 8; break;
1015 case KW_B: S2 = 3 << 8; break;
1016 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1020 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1024 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1026 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1029 if (*tok >= KW_R0 && *tok <= KW_R7)
1031 ea2 = (*tok++ - KW_R0);
1032 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
1033 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'");
1036 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
1037 // If eax register is r0-r3 then eay register is r4-r7.
1038 // Encode that to 2 bits (i.e. eay value is 0-3)
1039 eay_temp = (ea2 & 3) << 5; //Store register temporarily
1041 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1048 else if (*tok >= KW_N0 && *tok <= KW_N7)
1051 if ((*tok++ & 7) != ea2)
1052 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')");
1055 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1058 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1061 else if (*tok == '-')
1067 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1069 else if (*tok == EOL)
1075 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1077 ea2 |= eay_temp; //OR eay back from temp
1079 inst = B16(10000000, 00000000) | w;
1080 inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1084 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1088 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1091 return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
1095 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1099 // Parse X: addressing space parallel moves
1101 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1103 int immreg; // Immediate register destination
1104 LONG S2, D1, D2; // Source and Destinations
1105 LONG ea1; // ea bitfields
1106 uint32_t termchar = ','; // Termination character for ea checks
1107 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1108 ea1 = -1; // initialise e1 (useful for some code paths)
1113 if (tok[1] == CONST || tok[1] == FCONST)
1116 dspImmedEXVAL = *tok++;
1119 // This could be either -(Rn), -aa or -ea. Check for immediate first
1120 if (tok[1] == SYMBOL)
1122 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1128 // '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'
1129 if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
1132 if (ea1 == DSP_EA_ABS)
1133 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1135 return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1137 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
1138 if (ea1 == B8(00110100))
1139 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
1140 inst = B16(00001000, 00000000) | ea1 | (0 << 8);
1143 else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1146 if (ea1 == DSP_EA_ABS)
1147 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1149 return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1151 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
1152 if (ea1 == B8(00110100))
1153 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
1154 inst = B16(00001001, 00000000) | ea1 | (1 << 8);
1157 else if (*tok == KW_A || *tok == KW_B)
1159 // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1163 case 4: D1 = 0 << 10; break;
1164 case 5: D1 = 1 << 10; break;
1165 case 14: D1 = 2 << 10; break;
1166 case 15: D1 = 3 << 10; break;
1167 default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
1170 if (tok[1] == ',' && tok[2] == KW_Y)
1172 // 'S1,X:eax S2,Y:eay'
1173 return check_x_y(ea1, S1);
1177 if (ea1 == DSP_EA_ABS)
1178 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1182 case KW_A: S2 = 0 << 9; break;
1183 case KW_B: S2 = 1 << 9; break;
1184 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
1187 return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1189 if (*tok == KW_Y0 || *tok == KW_Y1)
1191 if (*tok++ == KW_Y0)
1197 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1199 inst = B16(00010000, 00000000) | (0 << 7);
1200 inst |= ea1 | D1 | S2 | D2;
1204 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1207 else if (*tok == KW_Y)
1209 // 'S1,X:eax Y:eay,D2'
1210 return check_x_y(ea1, S1);
1212 else if (*tok == KW_Y0 || *tok == KW_Y1)
1214 // 'S1,X:eax S2,Y:eay'
1215 return check_x_y(ea1, S1);
1218 return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1222 // Only check for aa if we have a defined number in our hands or we've
1223 // been asked to use a short number format. The former case we'll just test
1224 // it to see if it's small enough. The later - it's the programmer's call
1225 // so he'd better have a small address or the fixups will bite him/her in the arse!
1226 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1229 // It's an immediate, so ea or eax is probably an absolute address
1230 // (unless it's aa if the immediate is small enough)
1231 // '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'
1233 // Check for aa (which is 6 bits zero extended)
1234 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1238 // It might be X:aa but we're not 100% sure yet.
1239 // If it is, the only possible syntax here is 'X:aa,D'.
1240 // So check ahead to see if EOL follows D, then we're good to go.
1241 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)
1243 // Yup, we're good to go - 'X:aa,D' it is
1245 immreg = SDreg(*tok++);
1246 inst = inst | (uint32_t)dspImmedEXVAL;
1247 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1248 inst |= 1 << 7; // W
1257 inst = inst | (uint32_t)dspImmedEXVAL;
1258 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1263 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1264 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1266 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1267 goto x_checkea_right;
1273 // Well, that settles it - we do have an ea in our hands
1276 // 'X:ea,D' [... S2,d2]
1278 return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
1279 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1285 inst = inst | B8(01000000) | (1 << 7);
1286 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1288 if (ea1 == DSP_EA_ABS)
1289 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1295 if (*tok == KW_A || *tok == KW_B)
1299 return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1300 if (*tok == KW_Y0 || *tok == KW_Y1)
1304 return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
1305 inst = B16(00010000, 00000000) | (1 << 7);
1306 inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
1307 inst |= (S2 & 1) << 9;
1308 inst |= (D2 & 1) << 8;
1313 return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1316 return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1320 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,'");
1327 inst = inst | B8(01000000) | (0 << 7);
1328 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1330 if (ea1 == DSP_EA_ABS)
1331 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1336 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1337 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1338 goto x_checkea_right;
1347 // It's not an immediate, check for '-(Rn)'
1348 ea1 = checkea(termchar, X_ERRORS);
1357 else if (*tok == '#')
1360 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1362 // Okay so we have immediate data - mark it down
1364 // Now, proceed to the main code for this branch
1367 else if (*tok == '(')
1369 // Maybe we got an expression here, check for it
1370 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1372 // Evaluate the expression and go to immediate code path
1373 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1377 // Nope, let's check for ea then
1378 ea1 = checkea(termchar, X_ERRORS);
1386 return error("Comma expected after 'X:(Rn)')");
1388 // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
1389 // If it is, the only possible syntax here is 'X:ea,D'.
1390 // So check ahead to see if EOL follows D, then we're good to go.
1391 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1396 inst = inst | B8(01000000) | (1 << 7);
1398 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1407 inst = inst | B8(01000000) | (0 << 7);
1409 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1414 goto x_checkea_right;
1417 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
1418 // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
1419 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)))
1422 // Check if D1 is x0, x1, a or b
1425 case KW_X0: D1 = 0 << 10; break;
1426 case KW_X1: D1 = 1 << 10; break;
1427 case KW_A: D1 = 2 << 10; break;
1428 case KW_B: D1 = 3 << 10; break;
1429 default: return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
1434 case KW_A: S2 = 0 << 9; break;
1435 case KW_B: S2 = 1 << 9; break;
1436 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
1440 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1442 if (*tok == KW_Y0 || *tok == KW_Y1)
1444 if (*tok++ == KW_Y0)
1450 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1452 inst = B16(00010000, 00000000) | (W << 7);
1453 inst |= ea1 | D1 | S2 | D2;
1457 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1461 // Check to see if we got eax (which is a subset of ea)
1464 if ((inst = check_x_y(ea1, 0)) != 0)
1468 // Rewind pointer as it might be an expression and check for it
1470 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1472 // Yes, we have an expression, so we now check for
1473 // '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'
1478 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1480 // Check for immediate address
1481 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1484 // We set ea1 here - if it's aa instead of ea
1485 // then it won't be used anyway
1487 if (!(dspImmedEXATTR&DEFINED))
1489 force_imm = NUM_FORCE_LONG;
1490 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1495 else if (*tok == '>')
1497 // Check for immediate address forced long
1499 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1501 if (dspImmedEXATTR & DEFINED)
1502 if (dspImmedEXVAL > 0xffffff)
1503 return error("long address is bigger than $ffffff");
1505 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1507 force_imm = NUM_FORCE_LONG;
1511 else if (*tok == '<')
1513 // Check for immediate address forced short
1515 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1517 force_imm = NUM_FORCE_SHORT;
1518 if (dspImmedEXATTR & DEFINED)
1520 if (dspImmedEXVAL > 0x3f)
1522 warn("short addressing mode forced but address is bigger than $3f - switching to long");
1523 force_imm = NUM_FORCE_LONG;
1524 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1530 // This might end up as something like 'move Y:<adr,register'
1531 // so let's mark it as an extra aa fixup here.
1532 // Note: we are branching to x_check_immed without a
1533 // defined dspImmed so it's going to be 0. It probably
1534 // doesn't harm anything.
1535 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1540 return error("unknown x: addressing mode");
1545 // Parse Y: addressing space parallel moves
1547 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1549 int immreg; // Immediate register destination
1550 LONG D2; // Destination
1551 LONG ea1; // ea bitfields
1552 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1555 if (tok[1] == CONST || tok[1] == FCONST)
1558 dspImmedEXVAL = *tok++;
1561 // This could be either -(Rn), -aa or -ea. Check for immediate first
1562 if (*tok == SYMBOL || tok[1] == SYMBOL)
1564 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1566 // Only check for aa if we have a defined number in our hands or we've
1567 // been asked to use a short number format. The former case we'll just test
1568 // it to see if it's small enough. The later - it's the programmer's call
1569 // so he'd better have a small address or the fixups will bite him/her in the arse!
1570 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1572 // It's an immediate, so ea is probably an absolute address
1573 // (unless it's aa if the immediate is small enough)
1574 // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
1576 // Check for aa (which is 6 bits zero extended)
1577 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1579 // It might be Y:aa but we're not 100% sure yet.
1580 // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
1581 // So check ahead to see if EOL follows D, then we're good to go.
1582 if (*tok == EOL && S1 != 0)
1585 inst = B16(01001000, 00000000);
1586 inst |= dspImmedEXVAL;
1587 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1590 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)
1592 // Yup, we're good to go - 'Y:aa,D' it is
1594 immreg = SDreg(*tok++);
1595 inst |= dspImmedEXVAL;
1596 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1601 // Well, that settles it - we do have a ea in our hands
1602 if (*tok == EOL && S1 != 0)
1605 inst = B16(01001000, 01110000);
1607 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1608 if (ea1 == DSP_EA_ABS)
1609 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1613 return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1614 if (D1 == 0 && S1 == 0)
1617 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1621 return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1622 inst |= B16(00000000, 01110000);
1624 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1625 if (ea1 == DSP_EA_ABS)
1626 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1630 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,'");
1635 if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1640 inst |= (S1 & 1) << 11;
1641 inst |= (D1 & 1) << 10;
1642 inst |= (D2 & 8) << (9 - 3);
1643 inst |= (D2 & 1) << 8;
1647 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1655 // It's not an immediate, check for '-(Rn)'
1656 ea1 = checkea(',', Y_ERRORS);
1665 else if (*tok == '#')
1668 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1670 // Okay so we have immediate data - mark it down
1672 // Now, proceed to the main code for this branch
1675 else if (*tok == '(')
1677 // Maybe we got an expression here, check for it
1678 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1680 // Evaluate the expression and go to immediate code path
1681 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1685 // Nope, let's check for ea then
1686 if (S1 == 0 || (S1 != 0 && D1 != 0))
1687 ea1 = checkea(',', Y_ERRORS);
1689 ea1 = checkea(EOL, Y_ERRORS);
1695 if (S1 != 0 && *tok == EOL)
1698 inst = B16(01001000, 01000000);
1700 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1703 else if (S1 != 0 && D1 != 0 && S2 == 0)
1708 case 14: S1 = 0 << 11; break; // A
1709 case 15: S1 = 1 << 11; break; // B
1710 default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
1714 case 4: D1 = 0 << 10; break; // X0
1715 case 5: D1 = 1 << 10; break; // X1
1716 default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
1719 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1722 case KW_Y0: D2 = 0 << 8; break;
1723 case KW_Y1: D2 = 1 << 8; break;
1724 case KW_A: D2 = 2 << 8; break;
1725 case KW_B: D2 = 3 << 8; break;
1726 default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
1728 inst = B16(00010000, 11000000);
1729 inst |= S1 | D1 | D2;
1734 return error("Comma expected after 'Y:(Rn)')");
1735 // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
1736 // If it is, the only possible syntax here is 'Y:ea,D'.
1737 // So check ahead to see if EOL follows D, then we're good to go.
1738 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1742 inst |= B16(00000000, 01000000);
1744 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1748 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1750 // Check for immediate address
1751 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1754 // Yes, we have an expression, so we now check for
1755 // 'Y:ea,D' or 'Y:aa,D'
1756 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1757 if (!(dspImmedEXATTR&DEFINED))
1759 force_imm = NUM_FORCE_LONG;
1760 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1765 else if (*tok == '>')
1767 // Check for immediate address forced long
1769 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1771 if (dspImmedEXATTR & DEFINED)
1772 if (dspImmedEXVAL > 0xffffff)
1773 return error("long address is bigger than $ffffff");
1775 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1777 force_imm = NUM_FORCE_LONG;
1781 else if (*tok == '<')
1784 if (S1 != 0 && D1 != 0)
1786 // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
1787 // there's no Y:aa mode here, so we'll force long
1788 warn("forced short addressing in R:Y mode is not allowed - switching to long");
1790 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1795 force_imm = NUM_FORCE_LONG;
1796 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1801 // Check for immediate address forced short
1802 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1804 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1806 force_imm = NUM_FORCE_SHORT;
1807 if (dspImmedEXATTR & DEFINED)
1809 if (dspImmedEXVAL > 0xfff)
1811 warn("short addressing mode forced but address is bigger than $fff - switching to long");
1813 force_imm = NUM_FORCE_LONG;
1814 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1819 // This might end up as something like 'move Y:<adr,register'
1820 // so let's mark it as an extra aa fixup here.
1821 // Note: we are branching to y_check_immed without a
1822 // defined dspImmed so it's going to be 0. It probably
1823 // doesn't harm anything.
1824 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1831 return error("unrecognised Y: parallel move syntax");
1836 // Parse L: addressing space parallel moves
1838 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1840 int immreg; // Immediate register destination
1841 LONG D1; // Source and Destinations
1842 LONG ea1; // ea bitfields
1843 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1846 if (*tok == CONST || tok[1] == FCONST)
1849 dspImmedEXVAL = *tok++;
1852 // This could be either -(Rn), -aa or -ea. Check for immediate first
1853 // Maybe we got an expression here, check for it
1854 if (*tok == SYMBOL || tok[1] == SYMBOL)
1856 // Evaluate the expression and go to immediate code path
1857 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1859 // Only check for aa if we have a defined number in our hands or we've
1860 // been asked to use a short number format. The former case we'll just test
1861 // it to see if it's small enough. The later - it's the programmer's call
1862 // so he'd better have a small address or the fixups will bite him/her in the arse!
1863 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1865 // It's an immediate, so ea is probably an absolute address
1866 // (unless it's aa if the immediate is small enough)
1867 // 'L:ea,D' or 'L:aa,D'
1869 // Check for aa (which is 6 bits zero extended)
1873 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1878 else if (S1 == KW_B)
1883 inst = B16(01000000, 00000000);
1884 inst |= dspImmedEXVAL;
1885 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1893 else if (S1 == KW_B)
1898 if (ea1 == DSP_EA_ABS)
1899 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1901 inst |= B16(01000000, 01110000);
1902 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1909 return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
1910 // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
1911 if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
1912 return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
1914 if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
1921 else if (immreg == KW_B)
1927 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
1929 inst &= B16(11111111, 10111111);
1930 inst |= dspImmedEXVAL;
1931 inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
1936 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
1938 // Hang on, we've got a L:<aa here, let's do that instead
1942 // Well, that settles it - we do have a ea in our hands
1947 else if (D1 == KW_B)
1953 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
1955 inst |= B16(00000000, 00110000);
1956 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
1962 //It's not an immediate, check for '-(Rn)'
1963 ea1 = checkea(',', L_ERRORS);
1972 else if (*tok == '(')
1974 // Maybe we got an expression here, check for it
1975 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1977 // Evaluate the expression and go to immediate code path
1978 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1982 //Nope, let's check for ea then
1984 ea1 = checkea(',', L_ERRORS);
1986 ea1 = checkea(EOL, L_ERRORS);
1995 inst = B16(01000000, 01000000);
1998 else if (S1 == KW_B)
2004 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2007 else if (*tok++ != ',')
2008 return error("Comma expected after 'L:(Rn)')");
2010 // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
2011 // If it is, the only possible syntax here is 'L:ea,D'.
2012 // So check ahead to see if EOL follows D, then we're good to go.
2013 if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
2019 else if (D1 == KW_B)
2025 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2029 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2031 // Check for immediate address
2032 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2035 // We set ea1 here - if it's aa instead of ea
2036 // then it won't be used anyway
2038 if (!(dspImmedEXATTR & DEFINED))
2040 force_imm = NUM_FORCE_LONG;
2041 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2043 else if (dspImmedEXVAL > 0x3f)
2045 // Definitely no aa material, so it's going to be a long
2046 // Mark that we need to deposit an extra word
2047 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2050 // Yes, we have an expression, so we now check for
2051 // 'L:ea,D' or 'L:aa,D'
2054 else if (*tok == '>')
2056 // Check for immediate address forced long
2058 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2060 if (dspImmedEXATTR & DEFINED)
2061 if (dspImmedEXVAL > 0xffffff)
2062 return error("long address is bigger than $ffffff");
2064 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2066 force_imm = NUM_FORCE_LONG;
2069 else if (*tok == '<')
2071 // Check for immediate address forced short
2073 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2075 if (dspImmedEXATTR & DEFINED)
2077 if (dspImmedEXVAL > 0xfff)
2078 return error("short addressing mode forced but address is bigger than $fff");
2082 // This might end up as something like 'move Y:<adr,register'
2083 // so let's mark it as an extra aa fixup here.
2084 // Note: we are branching to l_check_immed without a
2085 // defined dspImmed so it's going to be 0. It probably
2086 // doesn't harm anything.
2087 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
2090 force_imm = NUM_FORCE_SHORT;
2094 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");
2099 // Checks for all ea cases where indexed addressing is concenred
2101 static inline LONG checkea(const uint32_t termchar, const int strings)
2109 return error(ea_errors[strings][0]);
2110 if (*tok >= KW_R0 && *tok <= KW_R7)
2112 // We got '-(Rn' so mark it down
2113 ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2115 return error(ea_errors[strings][1]);
2116 // Now, proceed to the main code for this branch
2120 return error(ea_errors[strings][2]);
2122 else if (*tok == '(')
2124 // Checking for ea of type (Rn)
2126 if (*tok >= KW_R0 && *tok <= KW_R7)
2128 // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2129 ea = *tok++ - KW_R0;
2134 if (*tok < KW_N0 || *tok > KW_N7)
2135 return error(ea_errors[strings][3]);
2136 if ((*tok++ & 7) != ea)
2137 return error(ea_errors[strings][4]);
2140 return error(ea_errors[strings][5]);
2143 else if (*tok == ')')
2145 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2150 if (termchar == ',')
2155 ea |= DSP_EA_POSTINC1;
2158 else if (*tok >= KW_N0 && *tok <= KW_N7)
2161 if ((*tok++ & 7) != ea)
2162 return error(ea_errors[strings][6]);
2163 ea |= DSP_EA_POSTINC;
2167 return error(ea_errors[strings][7]);
2171 if (*tok >= KW_N0 && *tok <= KW_N7)
2174 if ((*tok++ & 7) != ea)
2175 return error(ea_errors[strings][6]);
2176 ea |= DSP_EA_POSTINC;
2182 ea |= DSP_EA_POSTINC1;
2187 else if (*tok == '-')
2190 if (termchar == ',')
2195 ea |= DSP_EA_POSTDEC1;
2198 else if (*tok >= KW_N0 && *tok <= KW_N7)
2201 if ((*tok++ & 7) != ea)
2202 return error(ea_errors[strings][8]);
2203 ea |= DSP_EA_POSTDEC;
2207 return error(ea_errors[strings][9]);
2211 if (*tok >= KW_N0 && *tok <= KW_N7)
2214 if ((*tok++ & 7) != ea)
2215 return error(ea_errors[strings][8]);
2216 ea |= DSP_EA_POSTDEC;
2222 ea |= DSP_EA_POSTDEC1;
2227 else if (termchar == ',')
2236 return error(ea_errors[strings][10]);
2246 return error(ea_errors[strings][11]);
2249 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");
2254 // Checks for all ea cases, i.e. all addressing modes that checkea handles
2255 // plus immediate addresses included forced short/long ones.
2256 // In other words this is a superset of checkea (and in fact calls checkea).
2258 LONG checkea_full(const uint32_t termchar, const int strings)
2262 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2264 // Check for immediate address
2265 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2268 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2270 // Yes, we have an expression
2273 else if (*tok == '>')
2275 // Check for immediate address forced long
2277 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2279 if (dspImmedEXATTR & DEFINED)
2280 if (dspImmedEXVAL > 0xffffff)
2281 return error("long address is bigger than $ffffff");
2283 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2285 // Yes, we have an expression
2288 else if (*tok == '<')
2290 // Check for immediate address forced short
2292 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2294 if (dspImmedEXATTR & DEFINED)
2295 if (dspImmedEXVAL > 0xfff)
2296 return error("short addressing mode forced but address is bigger than $fff");
2298 // Yes, we have an expression
2303 ea1 = checkea(termchar, strings);
2313 // Main routine to check parallel move modes.
2314 // It's quite complex so it's split into a few procedures (in fact most of the above ones).
2315 // A big effort was made so this can be managable and not too hacky, however one look at
2316 // the 56001 manual regarding parallel moves and you'll know that this is not an easy
2317 // problem to deal with!
2318 // dest=destination register from the main opcode. This must not be the same as D1 or D2
2319 // and that even goes for stuff like dest=A, D1=A0/1/2!!!
2321 LONG parmoves(WORD dest)
2323 int force_imm; // Addressing mode force operator
2324 int immreg; // Immediate register destination
2325 LONG inst; // 16 bit bitfield that has the parallel move opcode
2326 LONG S1, S2, D1, D2; // Source and Destinations
2327 LONG ea1; // ea bitfields
2332 return B16(00100000, 00000000);
2336 // '#xxxxxx,D', '#xx,D'
2338 force_imm = NUM_NORMAL;
2341 force_imm = NUM_FORCE_LONG;
2344 else if (*tok == '<')
2346 force_imm = NUM_FORCE_SHORT;
2350 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2354 return error("expected comma");
2356 if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
2357 return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
2358 immreg = SDreg(*tok++);
2362 if (!(dspImmedEXATTR & FLOAT))
2364 if (dspImmedEXATTR & DEFINED)
2366 // From I parallel move:
2367 // "If the destination register D is X0, X1, Y0, Y1, A, or B, the 8-bit immediate short operand
2368 // is interpreted as a signed fraction and is stored in the specified destination register.
2369 // That is, the 8 - bit data is stored in the eight MS bits of the destination operand, and the
2370 // remaining bits of the destination operand D are zeroed."
2371 // The funny bit is that Motorola assembler can parse something like 'move #$FF0000,b' into an
2372 // I (immediate short move) - so let's do that as well then...
2373 if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
2375 if ((dspImmedEXVAL & 0xffff) == 0)
2377 dspImmedEXVAL >>= 16;
2380 if (force_imm == NUM_FORCE_SHORT)
2382 if (dspImmedEXVAL<0xff && (int32_t)dspImmedEXVAL>-0x100)
2385 // value fits in 8 bits - immediate move
2386 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2391 warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2392 force_imm = NUM_FORCE_LONG;
2395 if (force_imm == NUM_FORCE_LONG)
2399 // X or Y Data move. I don't think it matters much
2400 // which of the two it will be, so let's use X.
2401 deposit_immediate_long_with_register:
2402 inst = B16(01000000, 11110100);
2403 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2404 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2407 if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2409 // value fits in 8 bits - immediate move
2410 deposit_immediate_short_with_register:
2411 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2416 // value doesn't fit in 8 bits, so it can either be
2417 // X or Y Data move. I don't think it matters much
2418 // which of the two it will be, so let's use X:.
2419 // TODO: if we're just goto'ing perhaps the logic can be simplified
2420 goto deposit_immediate_long_with_register;
2425 if (force_imm != NUM_FORCE_SHORT)
2428 // TODO: if we're just goto'ing perhaps the logic can be simplified
2429 goto deposit_immediate_long_with_register;
2434 // No visibility of the number so let's add a fixup for this
2435 AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
2436 inst = B16(00100000, 00000000);
2437 inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
2446 if (dspImmedEXATTR & DEFINED)
2449 double f = *(double *)&dspImmedEXVAL;
2450 // Check direct.c for ossom comments regarding conversion!
2451 dspImmedEXVAL = ((uint32_t)(int32_t)round(f*(1 << 23))) & 0xffffff;
2456 if ((dspImmedEXVAL & 0xffff) == 0)
2458 // Value's 16 lower bits are not set so the value can fit in a single byte
2459 // (check parallel I move quoted above)
2460 warn("Immediate value fits inside 8 bits, so using instruction short format");
2461 dspImmedEXVAL >>= 16;
2462 goto deposit_immediate_short_with_register;
2465 if (force_imm == NUM_FORCE_SHORT)
2467 if ((dspImmedEXVAL & 0xffff) != 0)
2469 warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
2470 goto deposit_immediate_long_with_register;
2472 return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2474 // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
2475 goto deposit_immediate_long_with_register;
2479 if (force_imm == NUM_FORCE_SHORT)
2481 goto deposit_immediate_short_with_register;
2485 // Just deposit a float fixup
2486 AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
2487 inst = B16(00100000, 00000000);
2488 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2496 // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2500 case 4: D1 = 0 << 10;break; // X0
2501 case 5: D1 = 1 << 10;break; // X1
2502 case 14: D1 = 2 << 10;break; // A
2503 case 15: D1 = 3 << 10;break; // B
2504 default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
2509 case KW_A: S2 = 0 << 9; break;
2510 case KW_B: S2 = 1 << 9; break;
2511 default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
2515 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2519 case KW_Y0: D2 = 0 << 8; break;
2520 case KW_Y1: D2 = 1 << 8; break;
2521 default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
2525 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2527 inst = B16(00010000, 10110100) | D1 | S2 | D2;
2528 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2532 else if (*tok == KW_X)
2535 // Hey look, it's just the register X and not the addressing mode - fall through to general case
2536 goto parse_everything_else;
2541 return error("expected ':' after 'X' in parallel move (i.e. X:)");
2543 // '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'
2544 return parse_x(1, B16(01000000, 00000000), 0, 1);
2546 else if (*tok == KW_Y)
2549 // Hey look, it's just the register y and not the addressing mode - fall through to general case
2550 goto parse_everything_else;
2554 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2556 // 'Y:ea,D' or 'Y:aa,D'
2557 return parse_y(B16(01001000, 10000000), 0, 0, 0);
2559 else if (*tok == KW_L)
2561 // 'L:ea,D' or 'L:aa,D'
2564 return error("expected ':' after 'L' in parallel move (i.e. L:)");
2566 return parse_l(1, B16(01000000, 11000000), 0);
2568 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))
2570 // Everything else - brace for impact!
2572 // X: 'S,X:ea' 'S,X:aa'
2573 // X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
2574 // Y: 'S,Y:ea' 'S,Y:aa'
2575 // 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'
2576 // L: 'S,L:ea' 'S,L:aa'
2578 parse_everything_else:
2583 return error("Comma expected after 'S')");
2587 // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
2588 // 'A,X:ea X0,A' 'B,X:ea X0,B'
2591 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2592 return parse_x(0, B16(01000000, 00000000), S1, 1);
2594 else if (*tok == KW_Y)
2596 // 'S,Y:ea' 'S,Y:aa'
2599 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2600 return parse_y(B16(0000000, 00000000), S1, 0, 0);
2602 else if (*tok == KW_L)
2604 // 'S,L:ea' 'S,L:aa'
2607 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2608 return parse_l(1, B16(00000000, 00000000), L_S1);
2610 else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2613 // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
2614 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2619 inst = B16(00100000, 00000000);
2620 inst |= (S1 << 5) | (D1);
2623 else if (*tok == KW_Y)
2628 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2629 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2632 else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2634 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2636 if (S1 == 6 && D1 == 14 && S2 == 14)
2640 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2642 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2644 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2645 ea1 = checkea_full(EOL, Y_ERRORS);
2648 inst = B16(00001000, 10000000);
2653 else if (S1 == 6 && D1 == 15 && S2 == 15)
2657 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2659 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2661 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2662 ea1 = checkea_full(EOL, Y_ERRORS);
2665 inst = B16(00001000, 10000000);
2670 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2674 return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2676 return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2678 return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2679 ea1 = checkea_full(EOL, Y_ERRORS);
2682 inst = B16(00010000, 01000000);
2683 inst |= (S1 & 1) << 11;
2684 inst |= (D1 & 1) << 10;
2685 inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2690 return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2693 else if (*tok == '#')
2695 // R:Y: 'S1,D1 #xxxxxx,D2'
2699 // Well, forcing an immediate to be 24 bits is legal here
2700 // but then it's the only available option so my guess is that this
2701 // is simply superfluous. So let's just eat the character
2704 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2706 if (dspImmedEXATTR & DEFINED)
2707 if (dspImmedEXVAL > 0xffffff)
2708 return error("immediate is bigger than $ffffff");
2709 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2711 return error("Comma expected after 'S1,D1 #xxxxxx')");
2712 // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
2715 case KW_Y0: D2 = 0 << 8; break;
2716 case KW_Y1: D2 = 1 << 8; break;
2717 case KW_A: D2 = 2 << 8; break;
2718 case KW_B: D2 = 3 << 8; break;
2719 default: return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
2722 if (S1 == 14 || S1 == 15)
2724 if (D1 == 4 || D1 == 5)
2726 inst = B16(00010000, 11110100);
2727 inst |= (S1 & 1) << 11;
2728 inst |= (D1 & 1) << 10;
2730 dspImmedEXVAL = dspaaEXVAL;
2734 return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2737 return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2740 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2743 return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2745 else if (*tok == '(')
2748 // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2750 if (*tok >= KW_R0 && *tok <= KW_R7)
2752 ea1 = (*tok++ - KW_R0);
2755 return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
2757 return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
2764 else if (*tok >= KW_N0 && *tok <= KW_N7)
2767 if ((*tok++ & 7) != ea1)
2768 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
2771 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
2774 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
2777 else if (*tok == '-')
2786 else if (*tok >= KW_N0 && *tok <= KW_N7)
2789 if ((*tok++ & 7) != ea1)
2790 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
2793 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
2797 inst = B16(00100000, 01000000);
2802 return error("extra (unexpected) text found");