2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // AMODE.C - DSP 56001 Addressing Modes
4 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
9 #include "dsp56k_amode.h"
23 // Address-mode information
24 //int nmodes; // Number of addr'ing modes found
25 int dsp_am0; // Addressing mode
26 int dsp_a0reg; // Register
27 TOKEN dsp_a0expr[EXPRSIZE]; // Expression
28 uint64_t dsp_a0exval; // Expression's value
29 WORD dsp_a0exattr; // Expression's attribute
30 LONG dsp_a0memspace; // Addressing mode's memory space (P, X, Y)
31 SYM * dsp_a0esym; // External symbol involved in expr
33 int dsp_am1; // Addressing mode
34 int dsp_a1reg; // Register
35 TOKEN dsp_a1expr[EXPRSIZE]; // Expression
36 uint64_t dsp_a1exval; // Expression's value
37 WORD dsp_a1exattr; // Expression's attribute
38 LONG dsp_a1memspace; // Addressing mode's memory space (P, X, Y)
39 SYM * dsp_a1esym; // External symbol involved in expr
41 int dsp_am2; // Addressing mode
42 int dsp_a2reg; // Register
43 TOKEN dsp_a2expr[EXPRSIZE]; // Expression
44 uint64_t dsp_a2exval; // Expression's value
45 WORD dsp_a2exattr; // Expression's attribute
46 SYM * dsp_a2esym; // External symbol involved in expr
48 int dsp_am3; // Addressing mode
49 int dsp_a3reg; // Register
50 TOKEN dsp_a3expr[EXPRSIZE]; // Expression
51 uint64_t dsp_a3exval; // Expression's value
52 WORD dsp_a3exattr; // Expression's attribute
53 SYM * dsp_a3esym; // External symbol involved in expr
55 TOKEN dspImmedEXPR[EXPRSIZE]; // Expression
56 uint64_t dspImmedEXVAL; // Expression's value
57 WORD dspImmedEXATTR; // Expression's attribute
58 SYM * dspImmedESYM; // External symbol involved in expr
59 int deposit_extra_ea; // Optional effective address extension
60 TOKEN dspaaEXPR[EXPRSIZE]; // Expression
61 uint64_t dspaaEXVAL; // Expression's value
62 WORD dspaaEXATTR; // Expression's attribute
63 SYM * dspaaESYM; // External symbol involved in expr
65 LONG dsp_a0perspace; // Peripheral space (X, Y - used in movep)
66 LONG dsp_a1perspace; // Peripheral space (X, Y - used in movep)
68 int dsp_k; // Multiplications sign
70 static inline LONG checkea(const uint32_t termchar, const int strings);
72 // ea checking error strings put into a table because I'm not sure there's an
73 // easy way to do otherwise (the messages start getting differerent in many
74 // places so it will get awkward to code those in) (I'd rather burn some RAM
75 // in order to have more helpful error messages than the other way round)
82 const char *ea_errors[][12] = {
85 "unrecognised X: parallel move syntax: expected '(' after 'X:-'", // 0
86 "unrecognised X: parallel move syntax: expected ')' after 'X:-(Rn'", // 1
87 "unrecognised X: parallel move syntax: expected R0-R7 after 'X:-('", // 2
88 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn+'", // 3
89 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn+Nn)'", // 4
90 "unrecognised X: parallel move syntax: expected ')' after 'X:(Rn+Nn'", // 5
91 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)+Nn'", // 6
92 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)+'", // 7
93 "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)-Nn'", // 8
94 "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)-'", // 9
95 "unrecognised X: parallel move syntax: expected '+', '-' or ',' after 'X:(Rn)'", // 10
96 "unrecognised X: parallel move syntax: expected '+' or ')' after 'X:(Rn'", // 11
100 "unrecognised Y: parallel move syntax: expected '(' after 'Y:-'", // 0
101 "unrecognised Y: parallel move syntax: expected ')' after 'Y:-(Rn'", // 1
102 "unrecognised Y: parallel move syntax: expected R0-R7 after 'Y:-('", // 2
103 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn+'", // 3
104 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn+Nn)'", // 4
105 "unrecognised Y: parallel move syntax: expected ')' after 'Y:(Rn+Nn'", // 5
106 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)+Nn'", // 6
107 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)+'", // 7
108 "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)-Nn'", // 8
109 "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)-'", // 9
110 "unrecognised Y: parallel move syntax: expected '+', '-' or ',' after 'Y:(Rn)'", // 10
111 "unrecognised Y: parallel move syntax: expected '+' or ')' after 'Y:(Rn'", // 11
115 "unrecognised L: parallel move syntax: expected '(' after 'L:-'", // 0
116 "unrecognised L: parallel move syntax: expected ')' after 'L:-(Rn'", // 1
117 "unrecognised L: parallel move syntax: expected R0-R7 after 'L:-('", // 2
118 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn+'", // 3
119 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn+Nn)'", // 4
120 "unrecognised L: parallel move syntax: expected ')' after 'L:(Rn+Nn'", // 5
121 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)+Nn'", // 6
122 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)+'", // 7
123 "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)-Nn'", // 8
124 "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)-'", // 9
125 "unrecognised L: parallel move syntax: expected '+', '-' or ',' after 'L:(Rn)'", // 10
126 "unrecognised L: parallel move syntax: expected '+' or ')' after 'L:(Rn'", // 11
130 "unrecognised P: effective address syntax: expected '(' after 'P:-'", // 0
131 "unrecognised P: effective address syntax: expected ')' after 'P:-(Rn'", // 1
132 "unrecognised P: effective address syntax: expected R0-R7 after 'P:-('", // 2
133 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn+'", // 3
134 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn+Nn)'", // 4
135 "unrecognised P: effective address syntax: expected ')' after 'P:(Rn+Nn'", // 5
136 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)+Nn'", // 6
137 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)+'", // 7
138 "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)-Nn'", // 8
139 "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)-'", // 9
140 "unrecognised P: effective address syntax: expected '+', '-' or ',' after 'P:(Rn)'", // 10
141 "unrecognised P: effective address syntax: expected '+' or ')' after 'P:(Rn'", // 11
154 // Parse a single addressing mode
156 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)
158 if (*tok == KW_A || *tok == KW_B)
164 else if (*tok == '#')
170 // Immediate Short Addressing Mode Force Operator
172 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
175 if (*AnEXVAL > 0xFFF && *AnEXVAL < -4096)
176 return error("immediate short addressing mode forced but address is bigger than $FFF");
178 if ((int32_t)*AnEXVAL <= 0xFF && (int32_t)*AnEXVAL > -0x100)
187 else if (*tok == '>')
189 // Immediate Long Addressing Mode Force Operator
192 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
195 if ((int32_t)*AnEXVAL > 0xFFFFFF || (int32_t)*AnEXVAL < -0xFFFFFF)
196 return error("long immediate is bigger than $FFFFFF");
202 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
205 if (*AnEXATTR & DEFINED)
207 if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
212 else if (*AnEXVAL < 0x1000)
219 // We have no clue what size our immediate will be
220 // so we have to assume the worst
226 else if (*tok >= KW_X0 && *tok <= KW_Y1)
232 else if (*tok == KW_X && *(tok + 1) == ':')
236 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
238 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
241 if (*AnEXATTR & DEFINED)
243 if (*AnEXVAL > 0xFFFFFF)
244 return error("long address is bigger than $FFFFFF");
246 *memspace = 0 << 6; // Mark we're on X memory space
248 // Check if value is between $FFC0 and $FFFF, AKA X:pp
249 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
251 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
252 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
253 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
257 *memspace = 0 << 6; // Mark we're on X memory space
258 *perspace = 0 << 16; // Mark we're on X peripheral space
259 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
263 // If the symbol/expression is defined then check for valid range.
264 // Otherwise the value had better fit or Fixups will bark!
278 *memspace = 0 << 6; // Mark we're on X memory space
285 else if (*tok == '<')
288 // Short Addressing Mode Force Operator in the case of '<'
291 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
294 // If the symbol/expression is defined then check for valid range.
295 // Otherwise the value had better fit or Fixups will bark!
296 if (*AnEXATTR & DEFINED)
299 return error("short addressing mode forced but address is bigger than $3F");
303 // Mark it as a fixup
304 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
308 *memspace = 0 << 6; // Mark we're on X memory space
309 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
312 else if (*tok == '>')
314 // Long Addressing Mode Force Operator
317 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
319 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
322 if (*AnEXATTR&DEFINED)
324 if (*AnEXVAL > 0xFFFFFF)
325 return error("long address is bigger than $FFFFFF");
327 *memspace = 0 << 6; // Mark we're on X memory space
334 *memspace = 0 << 6; // Mark we're on X memory space
341 else if (*tok == SHL) // '<<'
343 // I/O Short Addressing Mode Force Operator
347 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
350 // If the symbol/expression is defined then check for valid range.
351 // Otherwise the value had better fit or Fixups will bark!
352 if (*AnEXATTR & DEFINED)
354 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
356 if (*AnEXVAL < 0xFFFFFFC0)
357 return error("I/O Short Addressing Mode addresses must be between $FFC0 and $FFFF");
361 *memspace = 0 << 6; // Mark we're on X memory space
362 *perspace = 0 << 16; // Mark we're on X peripheral space
363 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
367 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
369 // TODO: what if we need M_DSPAA here????
370 *memspace = 0 << 6; // Mark we're on X memory space
377 else if (*tok == KW_Y && *(tok + 1) == ':')
381 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
383 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
386 if (*AnEXVAL > 0xFFFFFF)
387 return error("long address is bigger than $FFFFFF");
389 *memspace = 1 << 6; // Mark we're on Y memory space
391 // Check if value is between $ffc0 and $ffff, AKA Y:pp
392 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
394 if ((temp >= 0xFFFFFFC0 /* Check for 32bit sign extended number */
395 && ((int32_t)*AnEXVAL < 0)) /* Check if 32bit signed number is negative*/
396 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
400 *perspace = 1 << 16; // Mark we're on X peripheral space
401 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
405 // If the symbol/expression is defined then check for valid range.
406 // Otherwise the value had better fit or Fixups will bark!
407 if (*AnEXATTR & DEFINED)
427 else if (*tok == '<')
430 // Short Addressing Mode Force Operator in the case of '<'
433 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
436 // If the symbol/expression is defined then check for valid range.
437 // Otherwise the value had better fit or Fixups will bark!
438 if (*AnEXATTR & DEFINED)
443 warn("short addressing mode forced but address is bigger than $3F - switching to long");
446 *memspace = 1 << 6; // Mark we're on Y memory space
453 // Mark it as a fixup
454 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
458 *memspace = 1 << 6; // Mark we're on Y memory space
459 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
462 else if (*tok == '>')
464 // Long Addressing Mode Force Operator
467 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
469 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
472 if (*AnEXATTR&DEFINED)
474 if (*AnEXVAL > 0xFFFFFF)
475 return error("long address is bigger than $FFFFFF");
477 *memspace = 1 << 6; // Mark we're on Y memory space
485 *memspace = 1 << 6; // Mark we're on Y memory space
492 else if (*tok == SHL) // '<<'
494 // I/O Short Addressing Mode Force Operator
498 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
501 // If the symbol/expression is defined then check for valid range.
502 // Otherwise the value had better fit or Fixups will bark!
503 if (*AnEXATTR & DEFINED)
505 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits
507 if (*AnEXVAL < 0xFFFFFFC0)
508 return error("I/O Short Addressing Mode addresses must be between $FFE0 and $1F");
512 *memspace = 1 << 6; // Mark we're on Y memory space
513 *perspace = 1 << 16; // Mark we're on Y peripheral space
514 *areg = *AnEXVAL & 0x3F; // Since this is only going to get used in dsp_ea_imm5...
518 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
520 *memspace = 1 << 6; // Mark we're on Y memory space
526 // TODO: add absolute address checks
528 else if ((*tok >= KW_X) && (*tok <= KW_Y))
534 else if ((*tok >= KW_M0) && (*tok <= KW_M7))
537 *areg = (*tok++) & 7;
540 else if ((*tok >= KW_R0) && (*tok <= KW_R7))
543 *areg = (*tok++) - KW_R0;
546 else if ((*tok >= KW_N0) && (*tok <= KW_N7))
549 *areg = (*tok++) & 7;
552 else if ((*tok == KW_A0) || (*tok == KW_A1) || (*tok == KW_B0)
559 else if ((*tok == KW_A2) || (*tok == KW_B2))
565 else if ((*tok == '-') && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
567 // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
570 // Check to see if this is the first operand
572 return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
579 else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
581 // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
584 // Check to see if this is the first operand
586 return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
593 else if (*tok == '(' || *tok == '-')
595 // Could be either an expression or ea mode
596 if (*tok + 1 == SYMBOL)
600 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
607 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
615 // TODO: add absolute address checks
616 return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
618 else if (*tok == KW_P && *(tok + 1) == ':')
622 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
625 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
628 if (*AnEXVAL > 0xFFFFFF)
629 return error("long address is bigger than $FFFFFF");
638 *areg = (int)*AnEXVAL; // Lame, but what the hell
644 else if (*tok == '<')
647 // Short Addressing Mode Force Operator in the case of '<'
650 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
654 return error("short addressing mode forced but address is bigger than $3F");
657 *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5...
660 else if (*tok == '>')
662 // Long Addressing Mode Force Operator
665 // Immediate Short Addressing Mode Force Operator
666 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
669 if (*AnEXATTR & DEFINED)
671 if (*AnEXVAL > 0xFFFFFF)
672 return error("long address is bigger than $FFFFFF");
680 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
688 else if (*tok == SHL)
690 // I/O Short Addressing Mode Force Operator
693 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
696 if (*AnEXVAL > 0xFFF)
697 return error("I/O short addressing mode forced but address is bigger than $FFF");
702 else if (*tok == '<')
704 // Short Addressing Mode Force Operator
707 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
710 if (*AnEXATTR & DEFINED)
712 if (*AnEXVAL > 0xFFF)
713 return error("short addressing mode forced but address is bigger than $FFF");
719 else if (*tok == '>')
721 // Long Addressing Mode Force Operator
724 // Immediate Short Addressing Mode Force Operator
725 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
728 if (*AnEXATTR & DEFINED)
730 if (*AnEXVAL > 0xFFFFFF)
731 return error("long address is bigger than $FFFFFF");
738 else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
747 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
750 // We'll store M_DSPEA_ABS in areg and if we have
751 // any extra info, it'll go in am
752 if (*AnEXATTR & DEFINED)
756 if (*AnEXVAL < 0x1000)
758 else if (*AnEXVAL < 0x10000)
760 else if (*AnEXVAL < 0x1000000)
763 return error("address must be smaller than $1000000");
769 // Well, we have no opinion on the expression's size, so let's assume the worst
776 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
781 // Parse all addressing modes except parallel moves
783 int dsp_amode(int maxea)
786 // Initialize global return values
787 nmodes = dsp_a0reg = dsp_a1reg = 0;
788 dsp_am0 = dsp_am1 = M_AM_NONE;
789 dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
792 dsp_a0exattr = dsp_a1exattr = 0;
793 dsp_a0esym = dsp_a1esym = (SYM *)NULL;
794 dsp_a0memspace = dsp_a1memspace = -1;
795 dsp_a0perspace = dsp_a1perspace = -1;
798 // If at EOL, then no addr modes at all
802 if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
806 // If caller wants only one mode, return just one (ignore comma);
807 // If there is no second addressing mode (no comma), then return just one anyway.
813 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
821 // Parse second addressing mode
822 if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
825 if (maxea == 2 || *tok == EOL)
828 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
836 // Only MAC-like or jsset/clr/tst/chg instructions here
838 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
843 return error(extra_stuff);
849 // Only Tcc instructions here, and then only those that accept 4 operands
851 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
855 return error("expected 4 parameters");
857 if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
863 return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
870 // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
871 return error(extra_stuff);
874 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
879 // Helper function which gives us the encoding of a DSP register
881 static inline int SDreg(int reg)
883 if (reg >= KW_X0 && reg <= KW_N7)
885 else if (reg >= KW_A0&® <= KW_A2)
886 return (8 >> (reg & 7)) | 8;
887 else //if (reg>=KW_R0&®<=KW_R7)
888 return reg - KW_R0 + 16;
889 // Handy map for the above:
890 // (values are of course taken from keytab)
891 // Register | Value | Return value
924 // Check for X:Y: parallel mode syntax
926 static inline LONG check_x_y(LONG ea1, LONG S1)
929 LONG eax_temp, eay_temp;
930 LONG D1, D2, S2, ea2;
932 LONG w = 1 << 7; // S1=0, D1=1<<14
934 if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
935 (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
939 case DSP_EA_POSTINC: ea1 = (ea1 & (~0x38)) | 0x8; break;
940 case DSP_EA_POSTINC1: ea1 = (ea1 & (~0x38)) | 0x18; break;
941 case DSP_EA_POSTDEC1: ea1 = (ea1 & (~0x38)) | 0x10; break;
942 case DSP_EA_NOUPD: ea1 = (ea1 & (~0x38)) | 0x00; break;
947 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
949 switch (K_D1 = *tok++)
951 case KW_X0: D1 = 0 << 10; break;
952 case KW_X1: D1 = 1 << 10; break;
953 case KW_A: D1 = 2 << 10; break;
954 case KW_B: D1 = 3 << 10; break;
955 default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
960 // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
965 case 4: D1 = 0 << 10; break;
966 case 5: D1 = 1 << 10; break;
967 case 14: D1 = 2 << 10; break;
968 case 15: D1 = 3 << 10; break;
969 default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
976 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
978 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
982 if (*tok >= KW_R0 && *tok <= KW_R7)
984 ea2 = (*tok++ - KW_R0);
986 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
987 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'");
990 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
992 // If eax register is r0-r3 then eay register is r4-r7.
993 // Encode that to 2 bits (i.e. eay value is 0-3)
994 eax_temp = (ea2 & 3) << 5; // Store register temporarily
997 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
1009 else if (*tok >= KW_N0 && *tok <= KW_N7)
1012 if ((*tok++ & 7) != ea2)
1013 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')");
1018 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
1021 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
1024 else if (*tok == '-')
1031 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
1033 else if (*tok++ == ',')
1039 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
1041 ea2 |= eax_temp; // OR eay back from temp
1043 switch (K_D2 = *tok++)
1045 case KW_Y0: D2 = 0 << 8; break;
1046 case KW_Y1: D2 = 1 << 8; break;
1047 case KW_A: D2 = 2 << 8; break;
1048 case KW_B: D2 = 3 << 8; break;
1049 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1053 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
1057 return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
1059 inst = B16(11000000, 00000000) | w;
1060 inst |= ea1 | D1 | ea2 | D2;
1064 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1066 else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1068 // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1071 case KW_Y0: S2 = 0 << 8; break;
1072 case KW_Y1: S2 = 1 << 8; break;
1073 case KW_A: S2 = 2 << 8; break;
1074 case KW_B: S2 = 3 << 8; break;
1075 default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1079 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1083 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1085 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1089 if (*tok >= KW_R0 && *tok <= KW_R7)
1091 ea2 = (*tok++ - KW_R0);
1093 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
1094 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'");
1097 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
1098 // If eax register is r0-r3 then eay register is r4-r7.
1099 // Encode that to 2 bits (i.e. eay value is 0-3)
1100 eay_temp = (ea2 & 3) << 5; //Store register temporarily
1103 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1112 else if (*tok >= KW_N0 && *tok <= KW_N7)
1115 if ((*tok++ & 7) != ea2)
1116 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')");
1121 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1124 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1127 else if (*tok == '-')
1133 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1135 else if (*tok == EOL)
1141 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1143 ea2 |= eay_temp; //OR eay back from temp
1145 inst = B16(10000000, 00000000) | w;
1146 inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1150 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1153 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1156 return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
1159 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1163 // Parse X: addressing space parallel moves
1165 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1167 int immreg; // Immediate register destination
1168 LONG S2, D1, D2; // Source and Destinations
1169 LONG ea1; // ea bitfields
1170 uint32_t termchar = ','; // Termination character for ea checks
1171 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1172 ea1 = -1; // initialise e1 (useful for some code paths)
1179 if (tok[1] == CONST || tok[1] == FCONST)
1182 dspImmedEXVAL = *tok++;
1186 // This could be either -(Rn), -aa or -ea. Check for immediate first
1187 if (tok[1] == SYMBOL)
1189 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1194 // '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'
1195 if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
1198 if (ea1 == DSP_EA_ABS)
1199 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1202 return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1205 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
1207 if (ea1 == B8(00110100))
1208 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
1210 inst = B16(00001000, 00000000) | ea1 | (0 << 8);
1213 else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1216 if (ea1 == DSP_EA_ABS)
1217 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1220 return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1223 return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
1225 if (ea1 == B8(00110100))
1226 return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
1228 inst = B16(00001001, 00000000) | ea1 | (1 << 8);
1231 else if (*tok == KW_A || *tok == KW_B)
1233 // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1236 case 4: D1 = 0 << 10; break;
1237 case 5: D1 = 1 << 10; break;
1238 case 14: D1 = 2 << 10; break;
1239 case 15: D1 = 3 << 10; break;
1240 default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
1243 if (tok[1] == ',' && tok[2] == KW_Y)
1245 // 'S1,X:eax S2,Y:eay'
1246 return check_x_y(ea1, S1);
1250 if (ea1 == DSP_EA_ABS)
1251 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1255 case KW_A: S2 = 0 << 9; break;
1256 case KW_B: S2 = 1 << 9; break;
1257 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
1261 return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1263 if (*tok == KW_Y0 || *tok == KW_Y1)
1265 if (*tok++ == KW_Y0)
1271 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1273 inst = B16(00010000, 00000000) | (0 << 7);
1274 inst |= ea1 | D1 | S2 | D2;
1278 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1280 else if (*tok == KW_Y)
1282 // 'S1,X:eax Y:eay,D2'
1283 return check_x_y(ea1, S1);
1285 else if (*tok == KW_Y0 || *tok == KW_Y1)
1287 // 'S1,X:eax S2,Y:eay'
1288 return check_x_y(ea1, S1);
1291 return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1295 // Only check for aa if we have a defined number in our hands or we've
1296 // been asked to use a short number format. The former case we'll just test
1297 // it to see if it's small enough. The later - it's the programmer's call
1298 // so he'd better have a small address or the fixups will bite him/her in the arse!
1299 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1302 // It's an immediate, so ea or eax is probably an absolute address
1303 // (unless it's aa if the immediate is small enough)
1304 // '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'
1306 // Check for aa (which is 6 bits zero extended)
1307 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1311 // It might be X:aa but we're not 100% sure yet.
1312 // If it is, the only possible syntax here is 'X:aa,D'.
1313 // So check ahead to see if EOL follows D, then we're good to go.
1314 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)
1316 // Yup, we're good to go - 'X:aa,D' it is
1318 immreg = SDreg(*tok++);
1319 inst = inst | (uint32_t)dspImmedEXVAL;
1320 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1321 inst |= 1 << 7; // W
1330 inst = inst | (uint32_t)dspImmedEXVAL;
1331 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
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'
1339 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1340 goto x_checkea_right;
1346 // Well, that settles it - we do have an ea in our hands
1349 // 'X:ea,D' [... S2,d2]
1351 return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
1353 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1360 inst = inst | B8(01000000) | (1 << 7);
1361 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1364 if (ea1 == DSP_EA_ABS)
1365 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1372 if (*tok == KW_A || *tok == KW_B)
1377 return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1379 if (*tok == KW_Y0 || *tok == KW_Y1)
1384 return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
1386 inst = B16(00010000, 00000000) | (1 << 7);
1387 inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
1388 inst |= (S2 & 1) << 9;
1389 inst |= (D2 & 1) << 8;
1394 return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1397 return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1401 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,'");
1408 inst = inst | B8(01000000) | (0 << 7);
1409 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1412 if (ea1 == DSP_EA_ABS)
1413 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1419 // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1420 // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1421 goto x_checkea_right;
1430 // It's not an immediate, check for '-(Rn)'
1431 ea1 = checkea(termchar, X_ERRORS);
1440 else if (*tok == '#')
1444 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1447 // Okay so we have immediate data - mark it down
1449 // Now, proceed to the main code for this branch
1452 else if (*tok == '(')
1454 // Maybe we got an expression here, check for it
1455 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1457 // Evaluate the expression and go to immediate code path
1458 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1462 // Nope, let's check for ea then
1463 ea1 = checkea(termchar, X_ERRORS);
1472 return error("Comma expected after 'X:(Rn)')");
1474 // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
1475 // If it is, the only possible syntax here is 'X:ea,D'.
1476 // So check ahead to see if EOL follows D, then we're good to go.
1477 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1482 inst = inst | B8(01000000) | (1 << 7);
1484 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1493 inst = inst | B8(01000000) | (0 << 7);
1495 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1500 goto x_checkea_right;
1504 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
1505 // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
1506 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)))
1509 // Check if D1 is x0, x1, a or b
1512 case KW_X0: D1 = 0 << 10; break;
1513 case KW_X1: D1 = 1 << 10; break;
1514 case KW_A: D1 = 2 << 10; break;
1515 case KW_B: D1 = 3 << 10; break;
1516 default: return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
1521 case KW_A: S2 = 0 << 9; break;
1522 case KW_B: S2 = 1 << 9; break;
1523 default: return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
1527 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1529 if (*tok == KW_Y0 || *tok == KW_Y1)
1531 if (*tok++ == KW_Y0)
1537 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1539 inst = B16(00010000, 00000000) | (W << 7);
1540 inst |= ea1 | D1 | S2 | D2;
1544 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1547 // Check to see if we got eax (which is a subset of ea)
1550 if ((inst = check_x_y(ea1, 0)) != 0)
1554 // Rewind pointer as it might be an expression and check for it
1557 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1560 // Yes, we have an expression, so we now check for
1561 // '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'
1566 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1568 // Check for immediate address
1569 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1572 // We set ea1 here - if it's aa instead of ea
1573 // then it won't be used anyway
1576 if (!(dspImmedEXATTR&DEFINED))
1578 force_imm = NUM_FORCE_LONG;
1579 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1584 else if (*tok == '>')
1586 // Check for immediate address forced long
1589 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1592 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
1593 return error("long address is bigger than $FFFFFF");
1595 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1597 force_imm = NUM_FORCE_LONG;
1601 else if (*tok == '<')
1603 // Check for immediate address forced short
1606 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1609 force_imm = NUM_FORCE_SHORT;
1611 if (dspImmedEXATTR & DEFINED)
1613 if (dspImmedEXVAL > 0x3F)
1615 if (optim_warn_flag)
1616 warn("short addressing mode forced but address is bigger than $3F - switching to long");
1618 force_imm = NUM_FORCE_LONG;
1619 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1625 // This might end up as something like 'move Y:<adr,register'
1626 // so let's mark it as an extra aa fixup here.
1627 // Note: we are branching to x_check_immed without a
1628 // defined dspImmed so it's going to be 0. It probably
1629 // doesn't harm anything.
1630 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1636 return error("unknown x: addressing mode");
1641 // Parse Y: addressing space parallel moves
1643 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1645 int immreg; // Immediate register destination
1646 LONG D2; // Destination
1647 LONG ea1; // ea bitfields
1648 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1651 if (tok[1] == CONST || tok[1] == FCONST)
1654 dspImmedEXVAL = *tok++;
1657 // This could be either -(Rn), -aa or -ea. Check for immediate first
1658 if (*tok == SYMBOL || tok[1] == SYMBOL)
1660 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1662 // Only check for aa if we have a defined number in our hands or we've
1663 // been asked to use a short number format. The former case we'll just test
1664 // it to see if it's small enough. The later - it's the programmer's call
1665 // so he'd better have a small address or the fixups will bite him/her in the arse!
1666 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1668 // It's an immediate, so ea is probably an absolute address
1669 // (unless it's aa if the immediate is small enough)
1670 // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
1672 // Check for aa (which is 6 bits zero extended)
1673 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1675 // It might be Y:aa but we're not 100% sure yet.
1676 // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
1677 // So check ahead to see if EOL follows D, then we're good to go.
1678 if (*tok == EOL && S1 != 0)
1681 inst = B16(01001000, 00000000);
1682 inst |= dspImmedEXVAL;
1683 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1687 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)
1689 // Yup, we're good to go - 'Y:aa,D' it is
1691 immreg = SDreg(*tok++);
1692 inst |= dspImmedEXVAL;
1693 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1698 // Well, that settles it - we do have a ea in our hands
1699 if (*tok == EOL && S1 != 0)
1702 inst = B16(01001000, 01110000);
1704 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1705 if (ea1 == DSP_EA_ABS)
1706 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1711 return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1713 if (D1 == 0 && S1 == 0)
1716 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1721 return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1723 inst |= B16(00000000, 01110000);
1725 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1726 if (ea1 == DSP_EA_ABS)
1727 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1731 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,'");
1736 if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1741 inst |= (S1 & 1) << 11;
1742 inst |= (D1 & 1) << 10;
1743 inst |= (D2 & 8) << (9 - 3);
1744 inst |= (D2 & 1) << 8;
1748 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1756 // It's not an immediate, check for '-(Rn)'
1757 ea1 = checkea(',', Y_ERRORS);
1766 else if (*tok == '#')
1770 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1773 // Okay so we have immediate data - mark it down
1775 // Now, proceed to the main code for this branch
1778 else if (*tok == '(')
1780 // Maybe we got an expression here, check for it
1781 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1783 // Evaluate the expression and go to immediate code path
1784 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1788 // Nope, let's check for ea then
1789 if (S1 == 0 || (S1 != 0 && D1 != 0))
1790 ea1 = checkea(',', Y_ERRORS);
1792 ea1 = checkea(EOL, Y_ERRORS);
1798 if (S1 != 0 && *tok == EOL)
1801 inst = B16(01001000, 01000000);
1803 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1806 else if (S1 != 0 && D1 != 0 && S2 == 0)
1811 case 14: S1 = 0 << 11; break; // A
1812 case 15: S1 = 1 << 11; break; // B
1813 default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
1818 case 4: D1 = 0 << 10; break; // X0
1819 case 5: D1 = 1 << 10; break; // X1
1820 default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
1824 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1828 case KW_Y0: D2 = 0 << 8; break;
1829 case KW_Y1: D2 = 1 << 8; break;
1830 case KW_A: D2 = 2 << 8; break;
1831 case KW_B: D2 = 3 << 8; break;
1832 default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
1835 inst = B16(00010000, 11000000);
1836 inst |= S1 | D1 | D2;
1842 return error("Comma expected after 'Y:(Rn)')");
1844 // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
1845 // If it is, the only possible syntax here is 'Y:ea,D'.
1846 // So check ahead to see if EOL follows D, then we're good to go.
1847 if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1851 inst |= B16(00000000, 01000000);
1853 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1857 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1859 // Check for immediate address
1860 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1863 // Yes, we have an expression, so we now check for
1864 // 'Y:ea,D' or 'Y:aa,D'
1865 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1867 if (!(dspImmedEXATTR&DEFINED))
1869 force_imm = NUM_FORCE_LONG;
1870 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1875 else if (*tok == '>')
1877 // Check for immediate address forced long
1880 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1883 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
1884 return error("long address is bigger than $FFFFFF");
1886 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1888 force_imm = NUM_FORCE_LONG;
1892 else if (*tok == '<')
1896 if (S1 != 0 && D1 != 0)
1898 // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
1899 // there's no Y:aa mode here, so we'll force long
1900 if (optim_warn_flag)
1901 warn("forced short addressing in R:Y mode is not allowed - switching to long");
1903 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1908 force_imm = NUM_FORCE_LONG;
1909 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1914 // Check for immediate address forced short
1915 ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1917 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1920 force_imm = NUM_FORCE_SHORT;
1922 if (dspImmedEXATTR & DEFINED)
1924 if (dspImmedEXVAL > 0xFFF)
1926 if (optim_warn_flag)
1927 warn("short addressing mode forced but address is bigger than $FFF - switching to long");
1930 force_imm = NUM_FORCE_LONG;
1931 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1936 // This might end up as something like 'move Y:<adr,register'
1937 // so let's mark it as an extra aa fixup here.
1938 // Note: we are branching to y_check_immed without a
1939 // defined dspImmed so it's going to be 0. It probably
1940 // doesn't harm anything.
1941 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1948 return error("unrecognised Y: parallel move syntax");
1953 // Parse L: addressing space parallel moves
1955 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1957 int immreg; // Immediate register destination
1958 LONG D1; // Source and Destinations
1959 LONG ea1; // ea bitfields
1960 int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1964 if (*tok == CONST || tok[1] == FCONST)
1967 dspImmedEXVAL = *tok++;
1971 // This could be either -(Rn), -aa or -ea. Check for immediate first
1972 // Maybe we got an expression here, check for it
1973 if (*tok == SYMBOL || tok[1] == SYMBOL)
1975 // Evaluate the expression and go to immediate code path
1976 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1978 // Only check for aa if we have a defined number in our hands
1979 // or we've been asked to use a short number format. The
1980 // former case we'll just test it to see if it's small enough.
1981 // The later - it's the programmer's call so he'd better have
1982 // a small address or the fixups will bite him/her in the arse!
1983 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1985 // It's an immediate, so ea is probably an absolute address
1986 // (unless it's aa if the immediate is small enough)
1987 // 'L:ea,D' or 'L:aa,D'
1989 // Check for aa (which is 6 bits zero extended)
1993 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1998 else if (S1 == KW_B)
2003 inst = B16(01000000, 00000000);
2004 inst |= dspImmedEXVAL;
2005 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2013 else if (S1 == KW_B)
2018 if (ea1 == DSP_EA_ABS)
2019 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2021 inst |= B16(01000000, 01110000);
2022 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2030 return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
2032 // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
2033 if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
2034 return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
2036 if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
2044 else if (immreg == KW_B)
2050 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
2052 inst &= B16(11111111, 10111111);
2053 inst |= dspImmedEXVAL;
2054 inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
2059 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
2061 // Hang on, we've got a L:<aa here, let's do that instead
2065 // Well, that settles it - we do have a ea in our hands
2071 else if (D1 == KW_B)
2077 return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
2079 inst |= B16(00000000, 00110000);
2080 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2086 //It's not an immediate, check for '-(Rn)'
2087 ea1 = checkea(',', L_ERRORS);
2096 else if (*tok == '(')
2098 // Maybe we got an expression here, check for it
2099 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
2101 // Evaluate the expression and go to immediate code path
2102 expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
2106 //Nope, let's check for ea then
2108 ea1 = checkea(',', L_ERRORS);
2110 ea1 = checkea(EOL, L_ERRORS);
2119 inst = B16(01000000, 01000000);
2123 else if (S1 == KW_B)
2129 inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2132 else if (*tok++ != ',')
2133 return error("Comma expected after 'L:(Rn)')");
2135 // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
2136 // If it is, the only possible syntax here is 'L:ea,D'.
2137 // So check ahead to see if EOL follows D, then we're good to go.
2138 if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
2145 else if (D1 == KW_B)
2151 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2155 else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2157 // Check for immediate address
2158 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2161 // We set ea1 here - if it's aa instead of ea
2162 // then it won't be used anyway
2165 if (!(dspImmedEXATTR & DEFINED))
2167 force_imm = NUM_FORCE_LONG;
2168 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2170 else if (dspImmedEXVAL > 0x3f)
2172 // Definitely no aa material, so it's going to be a long
2173 // Mark that we need to deposit an extra word
2174 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2177 // Yes, we have an expression, so we now check for
2178 // 'L:ea,D' or 'L:aa,D'
2181 else if (*tok == '>')
2183 // Check for immediate address forced long
2186 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2189 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
2190 return error("long address is bigger than $FFFFFF");
2192 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2194 force_imm = NUM_FORCE_LONG;
2197 else if (*tok == '<')
2199 // Check for immediate address forced short
2202 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2205 if (dspImmedEXATTR & DEFINED)
2207 if (dspImmedEXVAL > 0xFFF)
2208 return error("short addressing mode forced but address is bigger than $FFF");
2212 // This might end up as something like 'move Y:<adr,register'
2213 // so let's mark it as an extra aa fixup here.
2214 // Note: we are branching to l_check_immed without a
2215 // defined dspImmed so it's going to be 0. It probably
2216 // doesn't harm anything.
2217 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
2220 force_imm = NUM_FORCE_SHORT;
2224 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");
2229 // Checks for all ea cases where indexed addressing is concenred
2231 static inline LONG checkea(const uint32_t termchar, const int strings)
2241 return error(ea_errors[strings][0]);
2243 if (*tok >= KW_R0 && *tok <= KW_R7)
2245 // We got '-(Rn' so mark it down
2246 ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2249 return error(ea_errors[strings][1]);
2251 // Now, proceed to the main code for this branch
2255 return error(ea_errors[strings][2]);
2257 else if (*tok == '(')
2259 // Checking for ea of type (Rn)
2262 if (*tok >= KW_R0 && *tok <= KW_R7)
2264 // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2265 ea = *tok++ - KW_R0;
2272 if (*tok < KW_N0 || *tok > KW_N7)
2273 return error(ea_errors[strings][3]);
2275 if ((*tok++ & 7) != ea)
2276 return error(ea_errors[strings][4]);
2281 return error(ea_errors[strings][5]);
2285 else if (*tok == ')')
2287 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2294 if (termchar == ',')
2299 ea |= DSP_EA_POSTINC1;
2302 else if (*tok >= KW_N0 && *tok <= KW_N7)
2305 if ((*tok++ & 7) != ea)
2306 return error(ea_errors[strings][6]);
2308 ea |= DSP_EA_POSTINC;
2312 return error(ea_errors[strings][7]);
2316 if (*tok >= KW_N0 && *tok <= KW_N7)
2319 if ((*tok++ & 7) != ea)
2320 return error(ea_errors[strings][6]);
2322 ea |= DSP_EA_POSTINC;
2328 ea |= DSP_EA_POSTINC1;
2333 else if (*tok == '-')
2337 if (termchar == ',')
2342 ea |= DSP_EA_POSTDEC1;
2345 else if (*tok >= KW_N0 && *tok <= KW_N7)
2348 if ((*tok++ & 7) != ea)
2349 return error(ea_errors[strings][8]);
2351 ea |= DSP_EA_POSTDEC;
2355 return error(ea_errors[strings][9]);
2359 if (*tok >= KW_N0 && *tok <= KW_N7)
2362 if ((*tok++ & 7) != ea)
2363 return error(ea_errors[strings][8]);
2365 ea |= DSP_EA_POSTDEC;
2371 ea |= DSP_EA_POSTDEC1;
2376 else if (termchar == ',')
2385 return error(ea_errors[strings][10]);
2395 return error(ea_errors[strings][11]);
2399 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");
2404 // Checks for all ea cases, i.e. all addressing modes that checkea handles
2405 // plus immediate addresses included forced short/long ones.
2406 // In other words this is a superset of checkea (and in fact calls checkea).
2408 LONG checkea_full(const uint32_t termchar, const int strings)
2412 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2414 // Check for immediate address
2415 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2418 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2420 // Yes, we have an expression
2423 else if (*tok == '>')
2425 // Check for immediate address forced long
2428 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2431 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
2432 return error("long address is bigger than $FFFFFF");
2434 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2436 // Yes, we have an expression
2439 else if (*tok == '<')
2441 // Check for immediate address forced short
2444 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2447 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFF))
2448 return error("short addressing mode forced but address is bigger than $FFF");
2450 // Yes, we have an expression
2455 ea1 = checkea(termchar, strings);
2467 // Main routine to check parallel move modes.
2468 // It's quite complex so it's split into a few procedures (in fact most of the
2469 // above ones). A big effort was made so this can be managable and not too
2470 // hacky, however one look at the 56001 manual regarding parallel moves and
2471 // you'll know that this is not an easy // problem to deal with!
2472 // dest=destination register from the main opcode. This must not be the same
2473 // as D1 or D2 and that even goes for stuff like dest=A, D1=A0/1/2!!!
2475 LONG parmoves(WORD dest)
2477 int force_imm; // Addressing mode force operator
2478 int immreg; // Immediate register destination
2479 LONG inst; // 16 bit bitfield that has the parallel move opcode
2480 LONG S1, S2, D1, D2; // Source and Destinations
2481 LONG ea1; // ea bitfields
2486 return B16(00100000, 00000000);
2491 // '#xxxxxx,D', '#xx,D'
2493 force_imm = NUM_NORMAL;
2497 force_imm = NUM_FORCE_LONG;
2500 else if (*tok == '<')
2502 force_imm = NUM_FORCE_SHORT;
2506 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2510 return error("expected comma");
2512 if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
2513 return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
2515 immreg = SDreg(*tok++);
2519 if (!(dspImmedEXATTR & FLOAT))
2521 if (dspImmedEXATTR & DEFINED)
2523 // From I parallel move:
2524 // "If the destination register D is X0, X1, Y0, Y1, A, or
2525 // B, the 8-bit immediate short operand is interpreted as
2526 // a signed fraction and is stored in the specified
2527 // destination register. That is, the 8 - bit data is
2528 // stored in the eight MS bits of the destination operand,
2529 // and the remaining bits of the destination operand D are
2531 // The funny bit is that Motorola assembler can parse
2532 // something like 'move #$FF0000,b' into an I (immediate
2533 // short move) - so let's do that as well then...
2534 if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
2536 if ((dspImmedEXVAL & 0xFFFF) == 0)
2538 dspImmedEXVAL >>= 16;
2542 if (force_imm == NUM_FORCE_SHORT)
2544 if (dspImmedEXVAL < 0xFF && (int32_t)dspImmedEXVAL > -0x100)
2547 // value fits in 8 bits - immediate move
2548 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2553 if (optim_warn_flag)
2554 warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2555 force_imm = NUM_FORCE_LONG;
2559 if (force_imm == NUM_FORCE_LONG)
2563 // X or Y Data move. I don't think it matters much
2564 // which of the two it will be, so let's use X.
2565 deposit_immediate_long_with_register:
2566 inst = B16(01000000, 11110100);
2567 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2568 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2572 if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2574 // value fits in 8 bits - immediate move
2575 deposit_immediate_short_with_register:
2576 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2581 // value doesn't fit in 8 bits, so it can either be
2582 // X or Y Data move. I don't think it matters much
2583 // which of the two it will be, so let's use X:.
2584 // TODO: if we're just goto'ing perhaps the logic can be simplified
2585 goto deposit_immediate_long_with_register;
2590 if (force_imm != NUM_FORCE_SHORT)
2593 // TODO: if we're just goto'ing perhaps the logic can be simplified
2594 goto deposit_immediate_long_with_register;
2599 // No visibility of the number so let's add a fixup for this
2600 AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
2601 inst = B16(00100000, 00000000);
2602 inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
2610 if (dspImmedEXATTR & DEFINED)
2612 double f = *(double *)&dspImmedEXVAL;
2613 // Check direct.c for ossom comments regarding conversion!
2614 //N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
2615 dspImmedEXVAL = ((uint32_t)(int32_t)round(f * (1 << 23))) & 0xFFFFFF;
2620 if ((dspImmedEXVAL & 0xFFFF) == 0)
2622 // Value's 16 lower bits are not set so the value can
2623 // fit in a single byte (check parallel I move quoted
2625 if (optim_warn_flag)
2626 warn("Immediate value fits inside 8 bits, so using instruction short format");
2628 dspImmedEXVAL >>= 16;
2629 goto deposit_immediate_short_with_register;
2632 if (force_imm == NUM_FORCE_SHORT)
2634 if ((dspImmedEXVAL & 0xFFFF) != 0)
2636 if (optim_warn_flag)
2637 warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
2639 goto deposit_immediate_long_with_register;
2642 return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2645 // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
2646 goto deposit_immediate_long_with_register;
2650 if (force_imm == NUM_FORCE_SHORT)
2652 goto deposit_immediate_short_with_register;
2656 // Just deposit a float fixup
2657 AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
2658 inst = B16(00100000, 00000000);
2659 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2667 // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2670 case 4: D1 = 0 << 10;break; // X0
2671 case 5: D1 = 1 << 10;break; // X1
2672 case 14: D1 = 2 << 10;break; // A
2673 case 15: D1 = 3 << 10;break; // B
2674 default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
2679 case KW_A: S2 = 0 << 9; break;
2680 case KW_B: S2 = 1 << 9; break;
2681 default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
2685 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2689 case KW_Y0: D2 = 0 << 8; break;
2690 case KW_Y1: D2 = 1 << 8; break;
2691 default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
2695 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2697 inst = B16(00010000, 10110100) | D1 | S2 | D2;
2698 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2702 else if (*tok == KW_X)
2705 // Hey look, it's just the register X and not the addressing mode - fall through to general case
2706 goto parse_everything_else;
2711 return error("expected ':' after 'X' in parallel move (i.e. X:)");
2713 // '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'
2714 return parse_x(1, B16(01000000, 00000000), 0, 1);
2716 else if (*tok == KW_Y)
2719 // Hey look, it's just the register y and not the addressing mode - fall through to general case
2720 goto parse_everything_else;
2725 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2727 // 'Y:ea,D' or 'Y:aa,D'
2728 return parse_y(B16(01001000, 10000000), 0, 0, 0);
2730 else if (*tok == KW_L)
2732 // 'L:ea,D' or 'L:aa,D'
2735 return error("expected ':' after 'L' in parallel move (i.e. L:)");
2737 return parse_l(1, B16(01000000, 11000000), 0);
2739 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))
2741 // Everything else - brace for impact!
2743 // X: 'S,X:ea' 'S,X:aa'
2744 // X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
2745 // Y: 'S,Y:ea' 'S,Y:aa'
2746 // 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'
2747 // L: 'S,L:ea' 'S,L:aa'
2749 parse_everything_else:
2754 return error("Comma expected after 'S')");
2758 // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
2759 // 'A,X:ea X0,A' 'B,X:ea X0,B'
2763 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2765 return parse_x(0, B16(01000000, 00000000), S1, 1);
2767 else if (*tok == KW_Y)
2769 // 'S,Y:ea' 'S,Y:aa'
2773 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2775 return parse_y(B16(0000000, 00000000), S1, 0, 0);
2777 else if (*tok == KW_L)
2779 // 'S,L:ea' 'S,L:aa'
2783 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2785 return parse_l(1, B16(00000000, 00000000), L_S1);
2787 else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2790 // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
2791 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2797 inst = B16(00100000, 00000000);
2798 inst |= (S1 << 5) | (D1);
2801 else if (*tok == KW_Y)
2806 return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2807 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2810 else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2812 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2815 if (S1 == 6 && D1 == 14 && S2 == 14)
2819 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2822 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2825 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2827 ea1 = checkea_full(EOL, Y_ERRORS);
2832 inst = B16(00001000, 10000000);
2837 else if (S1 == 6 && D1 == 15 && S2 == 15)
2841 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2844 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2847 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2849 ea1 = checkea_full(EOL, Y_ERRORS);
2854 inst = B16(00001000, 10000000);
2859 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2863 return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2866 return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2869 return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2871 ea1 = checkea_full(EOL, Y_ERRORS);
2876 inst = B16(00010000, 01000000);
2877 inst |= (S1 & 1) << 11;
2878 inst |= (D1 & 1) << 10;
2879 inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2884 return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2887 else if (*tok == '#')
2889 // R:Y: 'S1,D1 #xxxxxx,D2'
2894 // Well, forcing an immediate to be 24 bits is legal here
2895 // but then it's the only available option so my guess is that this
2896 // is simply superfluous. So let's just eat the character
2900 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2903 if ((dspImmedEXATTR & DEFINED) && (dspImmedEXVAL > 0xFFFFFF))
2904 return error("immediate is bigger than $FFFFFF");
2906 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2909 return error("Comma expected after 'S1,D1 #xxxxxx')");
2911 // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
2914 case KW_Y0: D2 = 0 << 8; break;
2915 case KW_Y1: D2 = 1 << 8; break;
2916 case KW_A: D2 = 2 << 8; break;
2917 case KW_B: D2 = 3 << 8; break;
2918 default: return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
2921 if (S1 == 14 || S1 == 15)
2923 if (D1 == 4 || D1 == 5)
2925 inst = B16(00010000, 11110100);
2926 inst |= (S1 & 1) << 11;
2927 inst |= (D1 & 1) << 10;
2929 dspImmedEXVAL = dspaaEXVAL;
2933 return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2936 return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2939 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2942 return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2944 else if (*tok == '(')
2947 // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2950 if (*tok >= KW_R0 && *tok <= KW_R7)
2952 ea1 = (*tok++ - KW_R0);
2955 return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
2958 return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
2967 else if (*tok >= KW_N0 && *tok <= KW_N7)
2970 if ((*tok++ & 7) != ea1)
2971 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
2976 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
2979 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
2981 else if (*tok == '-')
2991 else if (*tok >= KW_N0 && *tok <= KW_N7)
2994 if ((*tok++ & 7) != ea1)
2995 return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
3000 return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
3004 inst = B16(00100000, 01000000);
3009 return error("extra (unexpected) text found");