]> Shamusworld >> Repos - rmac/blob - dsp56k_amode.c
6c8bc2597348cc32bc59ddfdc459bc34dafd5721
[rmac] / dsp56k_amode.c
1 //
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
7 //
8
9 #include "dsp56k_amode.h"
10 #include "error.h"
11 #include "token.h"
12 #include "expr.h"
13 #include "rmac.h"
14 #include "procln.h"
15 #include "sect.h"
16 #include "math.h"
17
18 #define DEF_KW
19 #include "kwtab.h"
20 #define DEF_MN
21 #include "mntab.h"
22
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
32
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
40
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
47
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
54
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
64
65 int dsp_k;                          // Multiplications sign
66
67 static inline LONG checkea(const uint32_t termchar, const int strings);
68
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)
72
73 #define X_ERRORS 0
74 #define Y_ERRORS 1
75 #define L_ERRORS 2
76 #define P_ERRORS 3
77
78 const char *ea_errors[][12] = {
79     // X:
80     {
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
93     },
94     // Y:
95     {
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
108     },
109     // L:
110     {
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
123     },
124     // P:
125     {
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
138     }
139 };
140
141 enum
142 {
143     NUM_NORMAL = 0,
144     NUM_FORCE_LONG = 1,
145     NUM_FORCE_SHORT = 2
146 };
147
148 //
149 // Parse a single addressing mode
150 //
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)
152 {
153     if (*tok == KW_A || *tok == KW_B)
154     {
155         *am = M_ACC56;
156         *areg = *tok++;
157         return OK;
158     }
159     else if (*tok == '#')
160     {
161         tok++;
162
163         if (*tok == '<')
164         {
165             // Immediate Short Addressing Mode Force Operator
166             tok++;
167             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
168                 return ERROR;
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)
172             {
173                 *am = M_DSPIM8;
174                 return OK;
175             }
176             *am = M_DSPIM12;
177             return OK;
178         }
179         else if (*tok == '>')
180         {
181             // Immediate Long Addressing Mode Force Operator
182             tok++;
183             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
184                 return ERROR;
185             if ((int32_t)*AnEXVAL > 0xffffff || (int32_t)*AnEXVAL < -0xffffff)
186                 return error("long immediate is bigger than $ffffff");
187             *am = M_DSPIM;
188             return OK;
189         }
190
191         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
192             return ERROR;
193
194         if (*AnEXATTR & DEFINED)
195         {
196                         if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
197                         {
198                                 *AnEXVAL &= 0xff;
199                                 *am = M_DSPIM8;
200                         }
201             else if (*AnEXVAL < 0x1000)
202                 *am = M_DSPIM12;
203             else
204                 *am = M_DSPIM;
205         }
206         else
207         {
208             // We have no clue what size our immediate will be
209             // so we have to assume the worst
210             *am = M_DSPIM;
211         }
212         return OK;
213     }
214     else if (*tok >= KW_X0 && *tok <= KW_Y1)
215     {
216         *am = M_ALU24;
217         *areg = *tok++;
218         return OK;
219     }
220     else if (*tok == KW_X && *(tok + 1) == ':')
221     {
222         tok = tok + 2;
223         if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
224         {
225             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
226                 return ERROR;
227                         if (*AnEXATTR & DEFINED)
228                         {
229                                 if (*AnEXVAL > 0xffffff)
230                                         return error("long address is bigger than $ffffff");
231                                 *memspace = 0 << 6;     // Mark we're on X memory space
232
233                                 // Check if value is between $ffc0 and $ffff, AKA X:pp
234                                 {
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*/
239                                         {
240                                                 *AnEXVAL = temp;
241                                                 *am = M_DSPPP;
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...
245                                                 return OK;
246                                         }
247
248                                 }
249
250                                 // If the symbol/expression is defined then check for valid range.
251                                 // Otherwise the value had better fit or Fixups will bark!
252                                 if (*AnEXVAL > 0x3f)
253                                 {
254                                         *am = M_DSPEA;
255                                         *areg = DSP_EA_ABS;
256                                 }
257                                 else
258                                 {
259                                         *am = M_DSPAA;
260                                 }
261                         }
262                         else
263                         {
264                                 // Assume the worst
265                                 *memspace = 0 << 6;     // Mark we're on X memory space
266                                 *am = M_DSPEA;
267                                 *areg = DSP_EA_ABS;
268                         }
269             return OK;
270         }
271         else if (*tok == '<')
272         {
273             // X:aa
274             // Short Addressing Mode Force Operator in the case of '<'
275             tok++;
276             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
277                 return ERROR;
278
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)
282                         {
283                                 if (*AnEXVAL > 0x3f)
284                                         return error("short addressing mode forced but address is bigger than $3f");
285                         }
286             else
287             {
288                 // Mark it as a fixup
289                 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
290             }
291             *am = M_DSPAA;
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...
294             return OK;
295         }
296                 else if (*tok == '>')
297                 {
298                         // Long Addressing Mode Force Operator
299                         tok++;
300
301                         if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
302                         {
303                                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
304                                         return ERROR;
305                                 if (*AnEXATTR&DEFINED)
306                                 {
307                                         if (*AnEXVAL > 0xffffff)
308                                                 return error("long address is bigger than $ffffff");
309                                         *memspace = 0 << 6;     // Mark we're on X memory space
310
311                                         *am = M_DSPEA;
312                                         *areg = DSP_EA_ABS;
313                                 }
314                                 else
315                                 {
316                                         // Assume the worst
317                                         *memspace = 0 << 6;     // Mark we're on X memory space
318                                         *am = M_DSPEA;
319                                         *areg = DSP_EA_ABS;
320                                 }
321                                 return OK;
322                         }
323                 }
324         else if (*tok == SHL)  // '<<'
325         {
326             // I/O Short Addressing Mode Force Operator
327             // X:pp
328             tok++;
329             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
330                 return ERROR;
331
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)
335                         {
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");
339                         }
340             *am = M_DSPPP;
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...
344             return OK;
345         }
346
347         if ((*areg = checkea(0, X_ERRORS)) != ERROR)
348         {
349             // TODO: what if we need M_DSPAA here????
350             *memspace = 0 << 6;     // Mark we're on X memory space
351             *am = M_DSPEA;
352             return OK;
353         }
354         else
355             return ERROR;
356
357     }
358     else if (*tok == KW_Y && *(tok + 1) == ':')
359     {
360         tok = tok + 2;
361
362         if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
363         {
364             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
365                 return ERROR;
366             if (*AnEXVAL > 0xffffff)
367                 return error("long address is bigger than $ffffff");
368             *memspace = 1 << 6;     // Mark we're on Y memory space
369
370                         // Check if value is between $ffc0 and $ffff, AKA Y:pp
371                         {
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*/
376                                 {
377                                         *AnEXVAL = temp;
378                                         *am = M_DSPPP;
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...
381                                         return OK;
382                                 }
383
384                         }
385
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)
389                         {
390                                 if (*AnEXVAL > 0x3f)
391                                 {
392                                         *am = M_DSPEA;
393                                         *areg = DSP_EA_ABS;
394                                 }
395                                 else
396                                 {
397                                         *am = M_DSPAA;
398                                 }
399                         }
400                         else
401                         {
402                                 *am = M_DSPEA;
403                                 *areg = DSP_EA_ABS;
404                         }
405
406             return OK;
407         }
408         else if (*tok == '<')
409         {
410             // Y:aa
411             // Short Addressing Mode Force Operator in the case of '<'
412             tok++;
413             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
414                 return ERROR;
415
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)
419                         {
420                                 if (*AnEXVAL > 0x3f)
421                                 {
422                                         warn("short addressing mode forced but address is bigger than $3f - switching to long");
423                                         *am = M_DSPEA;
424                                         *memspace = 1 << 6;     // Mark we're on Y memory space
425                                         *areg = DSP_EA_ABS;
426                                         return OK;
427                                 }
428                         }
429             else
430             {
431                 // Mark it as a fixup
432                 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
433             }
434
435             *am = M_DSPAA;
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...
438             return OK;
439         }
440         else if (*tok == '>')
441         {
442             // Long Addressing Mode Force Operator
443                         tok++;
444
445                         if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
446                         {
447                                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
448                                         return ERROR;
449                                 if (*AnEXATTR&DEFINED)
450                                 {
451                                         if (*AnEXVAL > 0xffffff)
452                                                 return error("long address is bigger than $ffffff");
453                                         *memspace = 1 << 6;     // Mark we're on Y memory space
454
455                                         *am = M_DSPEA;
456                                         *areg = DSP_EA_ABS;
457                                 }
458                                 else
459                                 {
460                                         // Assume the worst
461                                         *memspace = 1 << 6;     // Mark we're on Y memory space
462                                         *am = M_DSPEA;
463                                         *areg = DSP_EA_ABS;
464                                 }
465                                 return OK;
466                         }
467                 }
468         else if (*tok == SHL)  // '<<'
469         {
470             // I/O Short Addressing Mode Force Operator
471             // Y:pp
472             tok++;
473             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
474                 return ERROR;
475
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)
479                         {
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");
483                         }
484                 *am = M_DSPPP;
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...
488             return OK;
489         }
490
491         if ((*areg = checkea(0, X_ERRORS)) != ERROR)
492         {
493             *memspace = 1 << 6;     // Mark we're on Y memory space
494             *am = M_DSPEA;
495             return OK;
496         }
497         else
498             return ERROR;
499         // TODO: add absolute address checks
500
501     }
502     else if (*tok >= KW_X&&*tok <= KW_Y)
503     {
504         *am = M_INP48;
505         *areg = *tok++;
506         return OK;
507     }
508     else if (*tok >= KW_M0 && *tok <= KW_M7)
509     {
510         *am = M_DSPM;
511         *areg = (*tok++) & 7;
512         return OK;
513     }
514     else if (*tok >= KW_R0 && *tok <= KW_R7)
515     {
516         *am = M_DSPR;
517         *areg = (*tok++) - KW_R0;
518         return OK;
519     }
520     else if (*tok >= KW_N0 && *tok <= KW_N7)
521     {
522         *am = M_DSPN;
523         *areg = (*tok++) & 7;
524         return OK;
525     }
526     else if (*tok == KW_A0 || *tok == KW_A1 || *tok == KW_B0 || *tok == KW_B1)
527     {
528         *am = M_ACC24;
529         *areg = *tok++;
530         return OK;
531     }
532     else if (*tok == KW_A2 || *tok == KW_B2)
533     {
534         *am = M_ACC8;
535         *areg = *tok++;
536         return OK;
537     }
538     else if (*tok == '-' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
539     {
540         // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
541         tok++;
542
543         // Check to see if this is the first operand
544         if (operand != 0)
545             return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
546
547         *am = M_ALU24;
548         *areg = *tok++;
549         dsp_k = 1 << 2;
550         return OK;
551     }
552     else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
553     {
554         // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
555         tok++;
556
557         // Check to see if this is the first operand
558         if (operand != 0)
559             return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
560
561         *am = M_ALU24;
562         *areg = *tok++;
563         dsp_k = 0 << 2;
564         return OK;
565     }
566     else if (*tok == '(' || *tok == '-')
567     {
568         // Could be either an expression or ea mode
569         if (*tok + 1 == SYMBOL)
570         {
571             tok++;
572
573             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
574                 return ERROR;
575
576             *am = M_DSPIM;
577             return OK;
578         }
579         if ((*areg = checkea(0, P_ERRORS)) != ERROR)
580         {
581             *am = M_DSPEA;
582             return OK;
583         }
584         else
585             return ERROR;
586         // TODO: add absolute address checks
587         return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
588     }
589     else if (*tok == KW_P && *(tok + 1) == ':')
590     {
591         tok = tok + 2;
592                 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
593         {
594             // Address
595             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
596                 return ERROR;
597             if (*AnEXVAL > 0xffffff)
598                 return error("long address is bigger than $ffffff");
599             if (*AnEXVAL > 0x3f)
600             {
601                 *am = M_DSPEA;
602                 *areg = DSP_EA_ABS;
603             }
604             else
605             {
606                 *areg = (int)*AnEXVAL;     // Lame, but what the hell
607                 *am = M_DSPAA;
608             }
609             return OK;
610         }
611         else if (*tok == '<')
612         {
613             // X:aa
614             // Short Addressing Mode Force Operator in the case of '<'
615             tok++;
616             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
617                 return ERROR;
618             if (*AnEXVAL > 0x3f)
619                 return error("short addressing mode forced but address is bigger than $3f");
620             *am = M_DSPAA;
621             *areg = (int)*AnEXVAL;     // Since this is only going to get used in dsp_ea_imm5...
622             return OK;
623         }
624         else if (*tok == '>')
625         {
626             // Long Addressing Mode Force Operator
627             tok++;
628             // Immediate Short Addressing Mode Force Operator
629             if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
630                 return ERROR;
631             if (*AnEXATTR & DEFINED)
632             {
633                 if (*AnEXVAL > 0xffffff)
634                     return error("long address is bigger than $ffffff");
635             }
636             *am = M_DSPEA;
637             *areg = DSP_EA_ABS;
638             return OK;
639         }
640
641         if ((*areg = checkea(0, P_ERRORS)) != ERROR)
642         {
643             *am = M_DSPEA;
644             return OK;
645         }
646         else
647             return ERROR;
648
649     }
650     else if (*tok == SHL)
651     {
652         // I/O Short Addressing Mode Force Operator
653         tok++;
654         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
655             return ERROR;
656         if (*AnEXVAL > 0xfff)
657             return error("I/O short addressing mode forced but address is bigger than $fff");
658         *am = M_DSPABS06;
659         return OK;
660     }
661     else if (*tok == '<')
662     {
663         // Short Addressing Mode Force Operator
664         tok++;
665         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
666             return ERROR;
667         if (*AnEXATTR & DEFINED)
668         {
669             if (*AnEXVAL > 0xfff)
670                 return error("short addressing mode forced but address is bigger than $fff");
671         }
672         *am = M_DSPABS12;
673         return OK;
674     }
675     else if (*tok == '>')
676     {
677         // Long Addressing Mode Force Operator
678         tok++;
679         // Immediate Short Addressing Mode Force Operator
680         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
681             return ERROR;
682         if (*AnEXATTR & DEFINED)
683         {
684             if (*AnEXVAL > 0xffffff)
685                 return error("long address is bigger than $ffffff");
686         }
687         *am = M_DSPEA;
688         *areg = DSP_EA_ABS;
689         return OK;
690     }
691
692     else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
693     {
694         *areg = *tok++;
695         *am = M_DSPPCU;
696         return OK;
697     }
698     // expr
699     else
700     {
701         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
702             return ERROR;
703
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)
707         {
708             *areg = DSP_EA_ABS;
709             if (*AnEXVAL < 0x1000)
710                 *am = M_DSPABS12;
711             else if (*AnEXVAL < 0x10000)
712                 *am = M_DSPABS16;
713             else if (*AnEXVAL < 0x1000000)
714                 *am = M_DSPABS24;
715             else
716                 return error("address must be smaller than $1000000");
717             return OK;
718         }
719         else
720         {
721             // Well, we have no opinion on the expression's size, so let's assume the worst
722             *areg = DSP_EA_ABS;
723             *am = M_DSPABS24;
724             return OK;
725         }
726     }
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
728 }
729
730 //
731 // Parse all addressing modes except parallel moves
732 //
733 int dsp_amode(int maxea)
734 {
735     LONG dummy;
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;
740     dsp_a0exval = 0;
741     dsp_a1exval = 0;
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;
746     dsp_k = 0;
747
748     // If at EOL, then no addr modes at all
749     if (*tok == EOL)
750         return 0;
751
752     if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
753         return ERROR;
754
755
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.
758     nmodes = 1;
759
760     if (*tok != ',')
761     {
762         if (dsp_k != 0)
763             return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
764
765         return 1;
766     }
767
768     // Eat the comma
769     tok++;
770
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)
773         return ERROR;
774
775     if (maxea == 2 || *tok == EOL)
776     {
777         if (dsp_k != 0)
778             return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
779
780         nmodes = 2;
781         return 2;
782     }
783
784     if (*tok == ',')
785     {
786         // Only MAC-like or jsset/clr/tst/chg instructions here
787         tok++;
788         if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
789             return ERROR;
790         if (maxea == 3)
791             return 3;
792         if (*tok != EOL)
793             return error(extra_stuff);
794         nmodes = 3;
795         return 3;
796
797     }
798
799     // Only Tcc instructions here, and then only those that accept 4 operands
800
801     if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
802         return ERROR;
803
804     if (*tok++ != ',')
805         return error("expected 4 parameters");
806
807     if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
808         return ERROR;
809
810     if (*tok == EOL)
811     {
812         if (dsp_k != 0)
813             return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
814
815         nmodes = 4;
816         return 4;
817     }
818     else
819     {
820         // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
821         return error(extra_stuff);
822     }
823
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
825
826 }
827
828
829 //
830 // Helper function which gives us the encoding of a DSP register
831 //
832 static inline int SDreg(int reg)
833 {
834     if (reg >= KW_X0 && reg <= KW_N7)
835         return reg & 0xff;
836     else if (reg >= KW_A0&&reg <= KW_A2)
837         return (8 >> (reg & 7)) | 8;
838     else //if (reg>=KW_R0&&reg<=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
843     //  x0      | 260   | 4
844     //  x1      | 261   | 5
845     //  y0      | 262   | 6
846     //  y1      | 263   | 7
847     //  b0      | 265   | 8
848     //  b2      | 267   | 9
849     //  b1      | 269   | 10
850     //  a       | 270   | 14
851     //  b       | 271   | 15
852     //  n0      | 280   | 24
853     //  n1      | 281   | 25
854     //  n2      | 282   | 26
855     //  n3      | 283   | 27
856     //  n4      | 284   | 28
857     //  n5      | 285   | 29
858     //  n6      | 286   | 30
859     //  n7      | 287   | 31
860     //  a0          | 136   | 0
861     //  a1          | 137   | 1
862     //  a2      | 138   | 2
863     //  r0          | 151   | 16
864     //  r1          | 152   | 17
865     //  r2          | 153   | 18
866     //  r3          | 154   | 19
867     //  r4          | 155   | 20
868     //  r5          | 156   | 21
869     //  r6          | 157   | 22
870     //  r7          | 158   | 23
871 }
872
873
874 //
875 // Check for X:Y: parallel mode syntax
876 //
877 static inline LONG check_x_y(LONG ea1, LONG S1)
878 {
879     LONG inst;
880     LONG eax_temp, eay_temp;
881     LONG D1, D2, S2, ea2;
882     LONG K_D1, K_D2;
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)
886     {
887
888         switch (ea1 & 0x38)
889         {
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;
894         }
895
896         if (S1 == 0)
897         {
898             // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
899             // Check for D1
900             switch (K_D1 = *tok++)
901             {
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,'");
907             }
908         }
909         else
910         {
911             // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
912             w = 0;
913             switch (S1)
914             {
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'");
920             }
921         }
922
923         if (*tok == KW_Y)
924         {
925             tok++;
926             // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
927             if (*tok++ != ':')
928                 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
929             if (*tok++ == '(')
930             {
931                 if (*tok >= KW_R0 && *tok <= KW_R7)
932                 {
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'");
936                 }
937                 else
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
942                 if (*tok++ != ')')
943                     return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
944                 if (*tok == '+')
945                 {
946                     tok++;
947                     if (*tok == ',')
948                     {
949                         // (Rn)+
950                         ea2 = 3 << 12;
951                         tok++;
952                     }
953                     else if (*tok >= KW_N0 && *tok <= KW_N7)
954                     {
955                         // (Rn)+Nn
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')");
958                         ea2 = 1 << 12;
959                         if (*tok++ != ',')
960                             return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
961                     }
962                     else
963                         return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
964
965                 }
966                 else if (*tok == '-')
967                 {
968                     // (Rn)-
969                     ea2 = 2 << 12;
970                     tok++;
971                     if (*tok++ != ',')
972                         return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
973                 }
974                 else if (*tok++ == ',')
975                 {
976                     // (Rn)
977                     ea2 = 0 << 12;
978                 }
979                 else
980                     return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
981
982                 ea2 |= eax_temp; // OR eay back from temp
983
984                 switch (K_D2 = *tok++)
985                 {
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,'");
991                 }
992
993                 if (*tok != EOL)
994                     return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
995
996                 if (S1 == 0)
997                     if (K_D1 == K_D2)
998                         return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
999
1000                 inst = B16(11000000, 00000000) | w;
1001                 inst |= ea1 | D1 | ea2 | D2;
1002                 return inst;
1003             }
1004             else
1005                 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1006         }
1007         else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1008         {
1009             // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1010             switch (*tok++)
1011             {
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,'");
1017             }
1018
1019             if (*tok++ != ',')
1020                 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1021
1022             if (*tok++ == KW_Y)
1023             {
1024                 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1025                 if (*tok++ != ':')
1026                     return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1027                 if (*tok++ == '(')
1028                 {
1029                     if (*tok >= KW_R0 && *tok <= KW_R7)
1030                     {
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'");
1034                     }
1035                     else
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
1040                     if (*tok++ != ')')
1041                         return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1042                     if (*tok == '+')
1043                     {
1044                         tok++;
1045                         if (*tok == EOL)
1046                             // (Rn)+
1047                             ea2 = 3 << 12;
1048                         else if (*tok >= KW_N0 && *tok <= KW_N7)
1049                         {
1050                             // (Rn)+Nn
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')");
1053                             ea2 = 1 << 12;
1054                             if (*tok != EOL)
1055                                 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1056                         }
1057                         else
1058                             return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1059
1060                     }
1061                     else if (*tok == '-')
1062                     {
1063                         // (Rn)-
1064                         ea2 = 2 << 12;
1065                         tok++;
1066                         if (*tok != EOL)
1067                             return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1068                     }
1069                     else if (*tok == EOL)
1070                     {
1071                         // (Rn)
1072                         ea2 = 0 << 12;
1073                     }
1074                     else
1075                         return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1076
1077                     ea2 |= eay_temp; //OR eay back from temp
1078
1079                     inst = B16(10000000, 00000000) | w;
1080                     inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1081                     return inst;
1082                 }
1083                 else
1084                     return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1085
1086             }
1087             else
1088                 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1089         }
1090         else
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,'");
1092
1093
1094     }
1095     return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1096 }
1097
1098 //
1099 // Parse X: addressing space parallel moves
1100 //
1101 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1102 {
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)
1109     if (W == 0)
1110         termchar = EOL;
1111     if (*tok == '-')
1112     {
1113         if (tok[1] == CONST || tok[1] == FCONST)
1114         {
1115             tok++;
1116             dspImmedEXVAL = *tok++;
1117             goto x_check_immed;
1118         }
1119         // This could be either -(Rn), -aa or -ea. Check for immediate first
1120         if (tok[1] == SYMBOL)
1121         {
1122             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1123             {
1124                 if (S1 != 0)
1125                 {
1126                 x_checkea_right:
1127
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)
1130                     {
1131                         // 'A,X:ea X0,A'
1132                         if (ea1 == DSP_EA_ABS)
1133                             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1134                         if (S1 != 14)
1135                             return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1136                         if (ea1 == -1)
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);
1141                         return inst;
1142                     }
1143                     else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1144                     {
1145                         // 'B,X:ea X0,B'
1146                         if (ea1 == DSP_EA_ABS)
1147                             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1148                         if (S1 != 15)
1149                             return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1150                         if (ea1 == -1)
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);
1155                         return inst;
1156                     }
1157                     else if (*tok == KW_A || *tok == KW_B)
1158                     {
1159                         // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1160
1161                         switch (S1)
1162                         {
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'");
1168                         }
1169
1170                         if (tok[1] == ',' && tok[2] == KW_Y)
1171                         {
1172                             // 'S1,X:eax S2,Y:eay'
1173                             return check_x_y(ea1, S1);
1174                         }
1175
1176                         // 'S1,X:ea S2,D2'
1177                         if (ea1 == DSP_EA_ABS)
1178                             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1179
1180                         switch (*tok++)
1181                         {
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'");
1185                         }
1186                         if (*tok++ != ',')
1187                             return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1188
1189                         if (*tok == KW_Y0 || *tok == KW_Y1)
1190                         {
1191                             if (*tok++ == KW_Y0)
1192                                 D2 = 0 << 8;
1193                             else
1194                                 D2 = 1 << 8;
1195
1196                             if (*tok != EOL)
1197                                 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1198
1199                             inst = B16(00010000, 00000000) | (0 << 7);
1200                             inst |= ea1 | D1 | S2 | D2;
1201                             return inst;
1202                         }
1203                         else
1204                             return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1205
1206                     }
1207                     else if (*tok == KW_Y)
1208                     {
1209                         // 'S1,X:eax Y:eay,D2'
1210                         return check_x_y(ea1, S1);
1211                     }
1212                     else if (*tok == KW_Y0 || *tok == KW_Y1)
1213                     {
1214                         // 'S1,X:eax S2,Y:eay'
1215                         return check_x_y(ea1, S1);
1216                     }
1217                     else
1218                         return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1219                 }
1220                 else
1221                 {
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)
1227                     {
1228
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'
1232                     x_check_immed:
1233                         // Check for aa (which is 6 bits zero extended)
1234                         if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1235                         {
1236                             if (W == 1)
1237                             {
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)
1242                                 {
1243                                     // Yup, we're good to go - 'X:aa,D' it is
1244                                     tok++;
1245                                     immreg = SDreg(*tok++);
1246                                     inst = inst | (uint32_t)dspImmedEXVAL;
1247                                     inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1248                                     inst |= 1 << 7; // W
1249                                     return inst;
1250                                 }
1251                             }
1252                             else
1253                             {
1254                                 if (*tok == EOL)
1255                                 {
1256                                     // 'S,X:aa'
1257                                     inst = inst | (uint32_t)dspImmedEXVAL;
1258                                     inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1259                                     return inst;
1260                                 }
1261                                 else
1262                                 {
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'
1265                                     ea1 = DSP_EA_ABS;
1266                                     deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1267                                     goto x_checkea_right;
1268                                 }
1269                             }
1270                         }
1271                     }
1272
1273                     // Well, that settles it - we do have an ea in our hands
1274                     if (W == 1)
1275                     {
1276                         // 'X:ea,D' [... S2,d2]
1277                         if (*tok++ != ',')
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))
1280                         {
1281                             D1 = SDreg(*tok++);
1282                             if (*tok == EOL)
1283                             {
1284                                 // 'X:ea,D'
1285                                 inst = inst | B8(01000000) | (1 << 7);
1286                                 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1287                                 inst |= ea1;
1288                                 if (ea1 == DSP_EA_ABS)
1289                                     deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1290                                 return inst;
1291                             }
1292                             else
1293                             {
1294                                 // 'X:ea,D1 S2,D2'
1295                                 if (*tok == KW_A || *tok == KW_B)
1296                                 {
1297                                     S2 = SDreg(*tok++);
1298                                     if (*tok++ != ',')
1299                                         return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1300                                     if (*tok == KW_Y0 || *tok == KW_Y1)
1301                                     {
1302                                         D2 = SDreg(*tok++);
1303                                         if (*tok != EOL)
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;
1309                                         inst |= ea1;
1310                                         return inst;
1311                                     }
1312                                     else
1313                                         return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1314                                 }
1315                                 else
1316                                     return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1317                             }
1318                         }
1319                         else
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,'");
1321                     }
1322                     else
1323                     {
1324                         if (*tok == EOL)
1325                         {
1326                             // 'S,X:ea'
1327                             inst = inst | B8(01000000) | (0 << 7);
1328                             inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1329                             inst |= ea1;
1330                             if (ea1 == DSP_EA_ABS)
1331                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1332                             return inst;
1333                         }
1334                         else
1335                         {
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;
1339                         }
1340                     }
1341
1342                 }
1343             }
1344         }
1345         else
1346         {
1347             // It's not an immediate, check for '-(Rn)'
1348             ea1 = checkea(termchar, X_ERRORS);
1349
1350             if (ea1 == ERROR)
1351                 return ERROR;
1352
1353             goto x_gotea1;
1354
1355         }
1356     }
1357     else if (*tok == '#')
1358     {
1359         tok++;
1360         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1361             return ERROR;
1362         // Okay so we have immediate data - mark it down
1363         ea1 = DSP_EA_IMM;
1364         // Now, proceed to the main code for this branch
1365         goto x_gotea1;
1366     }
1367     else if (*tok == '(')
1368     {
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)
1371         {
1372             // Evaluate the expression and go to immediate code path
1373             expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1374             goto x_check_immed;
1375         }
1376
1377         // Nope, let's check for ea then
1378         ea1 = checkea(termchar, X_ERRORS);
1379         if (ea1 == ERROR)
1380             return ERROR;
1381
1382     x_gotea1:
1383         if (W == 1)
1384         {
1385             if (*tok++ != ',')
1386                 return error("Comma expected after 'X:(Rn)')");
1387
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)
1392             {
1393                 //'X:ea,D'
1394                 D1 = SDreg(*tok++);
1395
1396                 inst = inst | B8(01000000) | (1 << 7);
1397                 inst |= ea1;
1398                 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1399                 return inst;
1400             }
1401         }
1402         else
1403         {
1404             if (*tok == EOL)
1405             {
1406                 //'S,X:ea'
1407                 inst = inst | B8(01000000) | (0 << 7);
1408                 inst |= ea1;
1409                 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1410                 return inst;
1411             }
1412             else
1413             {
1414                 goto x_checkea_right;
1415             }
1416         }
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)))
1420         {
1421             // 'X:ea,D1 S2,D2'
1422             // Check if D1 is x0, x1, a or b
1423             switch (*tok++)
1424             {
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,'");
1430             }
1431
1432             switch (*tok++)
1433             {
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 '");
1437             }
1438
1439             if (*tok++ != ',')
1440                 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1441
1442             if (*tok == KW_Y0 || *tok == KW_Y1)
1443             {
1444                 if (*tok++ == KW_Y0)
1445                     D2 = 0 << 8;
1446                 else
1447                     D2 = 1 << 8;
1448
1449                 if (*tok != EOL)
1450                     return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1451
1452                 inst = B16(00010000, 00000000) | (W << 7);
1453                 inst |= ea1 | D1 | S2 | D2;
1454                 return inst;
1455             }
1456             else
1457                 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1458
1459         }
1460
1461         // Check to see if we got eax (which is a subset of ea)
1462         if (check_for_x_y)
1463         {
1464             if ((inst = check_x_y(ea1, 0)) != 0)
1465                 return inst;
1466             else
1467             {
1468                 // Rewind pointer as it might be an expression and check for it
1469                 tok--;
1470                 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1471                     return ERROR;
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'
1474                 goto x_check_immed;
1475             }
1476         }
1477     }
1478     else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1479     {
1480         // Check for immediate address
1481         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1482             return ERROR;
1483
1484         // We set ea1 here - if it's aa instead of ea
1485         // then it won't be used anyway
1486         ea1 = DSP_EA_ABS;
1487         if (!(dspImmedEXATTR&DEFINED))
1488         {
1489             force_imm = NUM_FORCE_LONG;
1490             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1491         }
1492
1493         goto x_check_immed;
1494     }
1495     else if (*tok == '>')
1496     {
1497         // Check for immediate address forced long
1498         tok++;
1499         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1500             return ERROR;
1501         if (dspImmedEXATTR & DEFINED)
1502             if (dspImmedEXVAL > 0xffffff)
1503                 return error("long address is bigger than $ffffff");
1504
1505         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1506
1507         force_imm = NUM_FORCE_LONG;
1508         ea1 = DSP_EA_ABS;
1509         goto x_check_immed;
1510     }
1511     else if (*tok == '<')
1512     {
1513         // Check for immediate address forced short
1514         tok++;
1515         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1516             return ERROR;
1517         force_imm = NUM_FORCE_SHORT;
1518         if (dspImmedEXATTR & DEFINED)
1519         {
1520             if (dspImmedEXVAL > 0x3f)
1521             {
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;
1525                 ea1 = DSP_EA_ABS;
1526             }
1527         }
1528         else
1529         {
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;
1536         }
1537
1538         goto x_check_immed;
1539     }
1540     return error("unknown x: addressing mode");
1541 }
1542
1543
1544 //
1545 // Parse Y: addressing space parallel moves
1546 //
1547 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1548 {
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 '>')
1553     if (*tok == '-')
1554     {
1555         if (tok[1] == CONST || tok[1] == FCONST)
1556         {
1557             tok++;
1558             dspImmedEXVAL = *tok++;
1559             goto y_check_immed;
1560         }
1561         // This could be either -(Rn), -aa or -ea. Check for immediate first
1562                 if (*tok == SYMBOL || tok[1] == SYMBOL)
1563                 {
1564                         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1565                         {
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)
1571                                 {
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'
1575                                 y_check_immed:
1576                                         // Check for aa (which is 6 bits zero extended)
1577                                         if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1578                                         {
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)
1583                                                 {
1584                                                         // 'S,Y:aa'
1585                                                         inst = B16(01001000, 00000000);
1586                                                         inst |= dspImmedEXVAL;
1587                                                         inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1588                                                         return inst;
1589                                                 }
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)
1591                                                 {
1592                                                         // Yup, we're good to go - 'Y:aa,D' it is
1593                                                         tok++;
1594                                                         immreg = SDreg(*tok++);
1595                                                         inst |= dspImmedEXVAL;
1596                                                         inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1597                                                         return inst;
1598                                                 }
1599                                         }
1600                                 }
1601                                 // Well, that settles it - we do have a ea in our hands
1602                                 if (*tok == EOL && S1 != 0)
1603                                 {
1604                                         // 'S,Y:ea'
1605                                         inst = B16(01001000, 01110000);
1606                                         inst |= ea1;
1607                                         inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1608                                         if (ea1 == DSP_EA_ABS)
1609                                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1610                                         return inst;
1611                                 }
1612                                 if (*tok++ != ',')
1613                                         return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1614                                 if (D1 == 0 && S1 == 0)
1615                                 {
1616                                         // 'Y:ea,D'
1617                                         if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1618                                         {
1619                                                 D1 = SDreg(*tok++);
1620                                                 if (*tok != EOL)
1621                                                         return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1622                                                 inst |= B16(00000000, 01110000);
1623                                                 inst |= ea1;
1624                                                 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1625                                                 if (ea1 == DSP_EA_ABS)
1626                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1627                                                 return inst;
1628                                         }
1629                                         else
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,'");
1631                                 }
1632                                 else
1633                                 {
1634                                         // 'S1,D1 Y:ea,D2'
1635                                         if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1636                                         {
1637                                                 D2 = SDreg(*tok++);
1638                                                 inst |= ea1;
1639                                                 inst |= 1 << 7;
1640                                                 inst |= (S1 & 1) << 11;
1641                                                 inst |= (D1 & 1) << 10;
1642                                                 inst |= (D2 & 8) << (9 - 3);
1643                                                 inst |= (D2 & 1) << 8;
1644                                                 return inst;
1645                                         }
1646                                         else
1647                                                 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1648                                 }
1649                         }
1650                         else
1651                                 return ERROR;
1652                 }
1653         else
1654         {
1655             // It's not an immediate, check for '-(Rn)'
1656             ea1 = checkea(',', Y_ERRORS);
1657
1658             if (ea1 == ERROR)
1659                 return ERROR;
1660
1661             goto y_gotea1;
1662
1663         }
1664     }
1665     else if (*tok == '#')
1666     {
1667         tok++;
1668         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1669             return ERROR;
1670         // Okay so we have immediate data - mark it down
1671         ea1 = DSP_EA_IMM;
1672         // Now, proceed to the main code for this branch
1673         goto y_gotea1;
1674     }
1675     else if (*tok == '(')
1676     {
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)
1679         {
1680             // Evaluate the expression and go to immediate code path
1681             expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1682             goto y_check_immed;
1683         }
1684
1685         // Nope, let's check for ea then
1686         if (S1 == 0 || (S1 != 0 && D1 != 0))
1687             ea1 = checkea(',', Y_ERRORS);
1688         else
1689             ea1 = checkea(EOL, Y_ERRORS);
1690
1691         if (ea1 == ERROR)
1692             return ERROR;
1693
1694     y_gotea1:
1695         if (S1 != 0 && *tok == EOL)
1696         {
1697             // 'S,Y:ea'
1698             inst = B16(01001000, 01000000);
1699             inst |= ea1;
1700             inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1701             return inst;
1702         }
1703         else if (S1 != 0 && D1 != 0 && S2 == 0)
1704         {
1705             // 'S1,D1 Y:ea,D2'
1706             switch (S1)
1707             {
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;
1711             }
1712             switch (D1)
1713             {
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;
1717             }
1718             if (*tok++ != ',')
1719                 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1720             switch (*tok++)
1721             {
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'");
1727             }
1728             inst = B16(00010000, 11000000);
1729             inst |= S1 | D1 | D2;
1730             inst |= ea1;
1731             return inst;
1732         }
1733         if (*tok++ != ',')
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)
1739         {
1740             //'Y:ea,D'
1741             D1 = SDreg(*tok++);
1742             inst |= B16(00000000, 01000000);
1743             inst |= ea1;
1744             inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1745             return inst;
1746         }
1747     }
1748     else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1749     {
1750         // Check for immediate address
1751         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1752             return ERROR;
1753
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))
1758         {
1759             force_imm = NUM_FORCE_LONG;
1760             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1761         }
1762
1763         goto y_check_immed;
1764     }
1765     else if (*tok == '>')
1766     {
1767         // Check for immediate address forced long
1768         tok++;
1769         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1770             return ERROR;
1771         if (dspImmedEXATTR & DEFINED)
1772             if (dspImmedEXVAL > 0xffffff)
1773                 return error("long address is bigger than $ffffff");
1774
1775         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1776
1777         force_imm = NUM_FORCE_LONG;
1778         ea1 = DSP_EA_ABS;
1779         goto y_check_immed;
1780     }
1781     else if (*tok == '<')
1782     {
1783         tok++;
1784         if (S1 != 0 && D1 != 0)
1785         {
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");
1789
1790             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1791                 return ERROR;
1792
1793             ea1 = DSP_EA_ABS;
1794
1795             force_imm = NUM_FORCE_LONG;
1796             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1797             goto y_check_immed;
1798         }
1799         else
1800         {
1801             // Check for immediate address forced short
1802             ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1803
1804             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1805                 return ERROR;
1806             force_imm = NUM_FORCE_SHORT;
1807             if (dspImmedEXATTR & DEFINED)
1808             {
1809                 if (dspImmedEXVAL > 0xfff)
1810                 {
1811                     warn("short addressing mode forced but address is bigger than $fff - switching to long");
1812                     ea1 = DSP_EA_ABS;
1813                     force_imm = NUM_FORCE_LONG;
1814                     deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1815                 }
1816             }
1817             else
1818             {
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;
1825             }
1826
1827             goto y_check_immed;
1828         }
1829     }
1830
1831     return error("unrecognised Y: parallel move syntax");
1832 }
1833
1834
1835 //
1836 // Parse L: addressing space parallel moves
1837 //
1838 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1839 {
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 '>')
1844     if (*tok == '-')
1845     {
1846         if (*tok == CONST || tok[1] == FCONST)
1847         {
1848             tok++;
1849             dspImmedEXVAL = *tok++;
1850             goto l_check_immed;
1851         }
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)
1855         {
1856             // Evaluate the expression and go to immediate code path
1857             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1858             {
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)
1864                 {
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'
1868                 l_check_immed:
1869                     // Check for aa (which is 6 bits zero extended)
1870                     if (*tok == EOL)
1871                     {
1872                         // 'S,L:aa'
1873                         if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1874                         {
1875                             // 'S,L:aa'
1876                             if (S1 == KW_A)
1877                                 S1 = 4;
1878                             else if (S1 == KW_B)
1879                                 S1 = 5;
1880                             else
1881                                 S1 &= 7;
1882
1883                             inst = B16(01000000, 00000000);
1884                             inst |= dspImmedEXVAL;
1885                             inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1886                             return inst;
1887                         }
1888                         else
1889                         {
1890                             // 'S,L:ea'
1891                             if (S1 == KW_A)
1892                                 S1 = 4;
1893                             else if (S1 == KW_B)
1894                                 S1 = 5;
1895                             else
1896                                 S1 &= 7;
1897
1898                             if (ea1 == DSP_EA_ABS)
1899                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1900
1901                             inst |= B16(01000000, 01110000);
1902                             inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1903                             inst |= ea1;
1904                             return inst;
1905                         }
1906
1907                     }
1908                     if (*tok++ != ',')
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'");
1913
1914                     if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
1915                     {
1916                         // 'L:aa,D'
1917                         l_aa:
1918                         immreg = *tok++;
1919                         if (immreg == KW_A)
1920                             immreg = 4;
1921                         else if (immreg == KW_B)
1922                             immreg = 5;
1923                         else
1924                             immreg &= 7;
1925
1926                         if (*tok != EOL)
1927                             return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
1928
1929                         inst &= B16(11111111, 10111111);
1930                         inst |= dspImmedEXVAL;
1931                         inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
1932                         return inst;
1933                     }
1934                 }
1935
1936                 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
1937                 {
1938                     // Hang on, we've got a L:<aa here, let's do that instead
1939                     goto l_aa;
1940                 }
1941
1942                 // Well, that settles it - we do have a ea in our hands
1943                 // 'L:ea,D'
1944                 D1 = *tok++;
1945                 if (D1 == KW_A)
1946                     D1 = 4;
1947                 else if (D1 == KW_B)
1948                     D1 = 5;
1949                 else
1950                     D1 &= 7;
1951
1952                 if (*tok != EOL)
1953                     return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
1954
1955                 inst |= B16(00000000, 00110000);
1956                 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
1957                 return inst;
1958             }
1959         }
1960         else
1961         {
1962             //It's not an immediate, check for '-(Rn)'
1963             ea1 = checkea(',', L_ERRORS);
1964
1965             if (ea1 == ERROR)
1966                 return ERROR;
1967
1968             goto l_gotea1;
1969
1970         }
1971     }
1972     else if (*tok == '(')
1973     {
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)
1976         {
1977             // Evaluate the expression and go to immediate code path
1978             expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1979             goto l_check_immed;
1980         }
1981
1982         //Nope, let's check for ea then
1983         if (S1 == 0)
1984             ea1 = checkea(',', L_ERRORS);
1985         else
1986             ea1 = checkea(EOL, L_ERRORS);
1987
1988         if (ea1 == ERROR)
1989             return ERROR;
1990
1991     l_gotea1:
1992         if (*tok == EOL)
1993         {
1994             // 'S,L:ea'
1995             inst = B16(01000000, 01000000);
1996             if (S1 == KW_A)
1997                 S1 = 4;
1998             else if (S1 == KW_B)
1999                 S1 = 5;
2000             else
2001                 S1 &= 7;
2002
2003             inst |= ea1;
2004             inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2005             return inst;
2006         }
2007         else if (*tok++ != ',')
2008             return error("Comma expected after 'L:(Rn)')");
2009
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)
2014         {
2015             //'L:ea,D'
2016             D1 = *tok++;
2017             if (D1 == KW_A)
2018                 D1 = 4;
2019             else if (D1 == KW_B)
2020                 D1 = 5;
2021             else
2022                 D1 &= 7;
2023
2024             inst |= ea1;
2025             inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2026             return inst;
2027         }
2028     }
2029     else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2030     {
2031         // Check for immediate address
2032         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2033             return ERROR;
2034
2035         // We set ea1 here - if it's aa instead of ea
2036         // then it won't be used anyway
2037         ea1 = DSP_EA_ABS;
2038         if (!(dspImmedEXATTR & DEFINED))
2039         {
2040             force_imm = NUM_FORCE_LONG;
2041             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2042         }
2043                 else if (dspImmedEXVAL > 0x3f)
2044                 {
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;
2048                 }
2049
2050         // Yes, we have an expression, so we now check for
2051         // 'L:ea,D' or 'L:aa,D'
2052         goto l_check_immed;
2053     }
2054     else if (*tok == '>')
2055     {
2056         // Check for immediate address forced long
2057         tok++;
2058         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2059             return ERROR;
2060         if (dspImmedEXATTR & DEFINED)
2061             if (dspImmedEXVAL > 0xffffff)
2062                 return error("long address is bigger than $ffffff");
2063
2064         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2065
2066         force_imm = NUM_FORCE_LONG;
2067         goto l_check_immed;
2068     }
2069     else if (*tok == '<')
2070     {
2071         // Check for immediate address forced short
2072         tok++;
2073         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2074             return ERROR;
2075         if (dspImmedEXATTR & DEFINED)
2076         {
2077             if (dspImmedEXVAL > 0xfff)
2078                 return error("short addressing mode forced but address is bigger than $fff");
2079         }
2080         else
2081         {
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;
2088         }
2089
2090         force_imm = NUM_FORCE_SHORT;
2091         goto l_check_immed;
2092     }
2093
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");
2095 }
2096
2097
2098 //
2099 // Checks for all ea cases where indexed addressing is concenred
2100 //
2101 static inline LONG checkea(const uint32_t termchar, const int strings)
2102 {
2103     LONG ea;
2104     if (*tok == '-')
2105     {
2106         // -(Rn)
2107         tok++;
2108         if (*tok++ != '(')
2109             return error(ea_errors[strings][0]);
2110         if (*tok >= KW_R0 && *tok <= KW_R7)
2111         {
2112             // We got '-(Rn' so mark it down
2113             ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2114             if (*tok++ != ')')
2115                 return error(ea_errors[strings][1]);
2116             // Now, proceed to the main code for this branch
2117             return ea;
2118         }
2119         else
2120             return error(ea_errors[strings][2]);
2121     }
2122     else if (*tok == '(')
2123     {
2124         // Checking for ea of type (Rn)
2125         tok++;
2126         if (*tok >= KW_R0 && *tok <= KW_R7)
2127         {
2128             // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2129             ea = *tok++ - KW_R0;
2130             if (*tok == '+')
2131             {
2132                 // '(Rn+Nn)'
2133                 tok++;
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]);
2138                 ea |= DSP_EA_INDEX;
2139                 if (*tok++ != ')')
2140                     return error(ea_errors[strings][5]);
2141                 return ea;
2142             }
2143             else if (*tok == ')')
2144             {
2145                 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2146                 tok++;
2147                 if (*tok == '+')
2148                 {
2149                     tok++;
2150                     if (termchar == ',')
2151                     {
2152                         if (*tok == ',')
2153                         {
2154                             // (Rn)+
2155                             ea |= DSP_EA_POSTINC1;
2156                             return ea;
2157                         }
2158                         else if (*tok >= KW_N0 && *tok <= KW_N7)
2159                         {
2160                             // (Rn)+Nn
2161                             if ((*tok++ & 7) != ea)
2162                                 return error(ea_errors[strings][6]);
2163                             ea |= DSP_EA_POSTINC;
2164                             return ea;
2165                         }
2166                         else
2167                             return error(ea_errors[strings][7]);
2168                     }
2169                     else
2170                     {
2171                         if (*tok >= KW_N0 && *tok <= KW_N7)
2172                         {
2173                             // (Rn)+Nn
2174                             if ((*tok++ & 7) != ea)
2175                                 return error(ea_errors[strings][6]);
2176                             ea |= DSP_EA_POSTINC;
2177                             return ea;
2178                         }
2179                         else
2180                         {
2181                             // (Rn)+
2182                             ea |= DSP_EA_POSTINC1;
2183                             return ea;
2184                         }
2185                     }
2186                 }
2187                 else if (*tok == '-')
2188                 {
2189                     tok++;
2190                     if (termchar == ',')
2191                     {
2192                         if (*tok == ',')
2193                         {
2194                             // (Rn)-
2195                             ea |= DSP_EA_POSTDEC1;
2196                             return ea;
2197                         }
2198                         else if (*tok >= KW_N0 && *tok <= KW_N7)
2199                         {
2200                             // (Rn)-Nn
2201                             if ((*tok++ & 7) != ea)
2202                                 return error(ea_errors[strings][8]);
2203                             ea |= DSP_EA_POSTDEC;
2204                             return ea;
2205                         }
2206                         else
2207                             return error(ea_errors[strings][9]);
2208                     }
2209                     else
2210                     {
2211                         if (*tok >= KW_N0 && *tok <= KW_N7)
2212                         {
2213                             // (Rn)-Nn
2214                             if ((*tok++ & 7) != ea)
2215                                 return error(ea_errors[strings][8]);
2216                             ea |= DSP_EA_POSTDEC;
2217                             return ea;
2218                         }
2219                         else
2220                         {
2221                             // (Rn)-
2222                             ea |= DSP_EA_POSTDEC1;
2223                             return ea;
2224                         }
2225                     }
2226                 }
2227                 else if (termchar == ',')
2228                 {
2229                     if (*tok == ',')
2230                     {
2231                         // (Rn)
2232                         ea |= DSP_EA_NOUPD;
2233                         return ea;
2234                     }
2235                     else
2236                         return error(ea_errors[strings][10]);
2237                 }
2238                 else
2239                 {
2240                     // (Rn)
2241                     ea |= DSP_EA_NOUPD;
2242                     return ea;
2243                 }
2244             }
2245             else
2246                 return error(ea_errors[strings][11]);
2247         }
2248     }
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");
2250 }
2251
2252
2253 //
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).
2257 //
2258 LONG checkea_full(const uint32_t termchar, const int strings)
2259 {
2260     LONG ea1;
2261
2262     if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2263     {
2264         // Check for immediate address
2265         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2266             return ERROR;
2267
2268         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2269
2270         // Yes, we have an expression
2271         return DSP_EA_ABS;
2272     }
2273     else if (*tok == '>')
2274     {
2275         // Check for immediate address forced long
2276         tok++;
2277         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2278             return ERROR;
2279         if (dspImmedEXATTR & DEFINED)
2280             if (dspImmedEXVAL > 0xffffff)
2281                 return error("long address is bigger than $ffffff");
2282
2283         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2284
2285         // Yes, we have an expression
2286         return DSP_EA_ABS;
2287     }
2288     else if (*tok == '<')
2289     {
2290         // Check for immediate address forced short
2291         tok++;
2292         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2293             return ERROR;
2294         if (dspImmedEXATTR & DEFINED)
2295             if (dspImmedEXVAL > 0xfff)
2296                 return error("short addressing mode forced but address is bigger than $fff");
2297
2298         // Yes, we have an expression
2299         return DSP_EA_ABS;
2300     }
2301     else
2302     {
2303         ea1 = checkea(termchar, strings);
2304         if (ea1 == ERROR)
2305             return ERROR;
2306         else
2307             return ea1;
2308     }
2309
2310 }
2311
2312 //
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!!!
2320 //
2321 LONG parmoves(WORD dest)
2322 {
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
2328
2329     if (*tok == EOL)
2330     {
2331         // No parallel move
2332         return B16(00100000, 00000000);
2333     }
2334     if (*tok == '#')
2335     {
2336         // '#xxxxxx,D', '#xx,D'
2337         tok++;
2338         force_imm = NUM_NORMAL;
2339         if (*tok == '>')
2340         {
2341             force_imm = NUM_FORCE_LONG;
2342             tok++;
2343         }
2344         else if (*tok == '<')
2345         {
2346             force_imm = NUM_FORCE_SHORT;
2347             tok++;
2348         }
2349
2350         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2351             return ERROR;
2352
2353         if (*tok++ != ',')
2354             return error("expected comma");
2355
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++);
2359
2360         if (*tok == EOL)
2361         {
2362             if (!(dspImmedEXATTR & FLOAT))
2363             {
2364                 if (dspImmedEXATTR & DEFINED)
2365                 {
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)
2374                     {
2375                         if ((dspImmedEXVAL & 0xffff) == 0)
2376                         {
2377                             dspImmedEXVAL >>= 16;
2378                         }
2379                     }
2380                     if (force_imm == NUM_FORCE_SHORT)
2381                     {
2382                         if (dspImmedEXVAL<0xff && (int32_t)dspImmedEXVAL>-0x100)
2383                         {
2384                             // '#xx,D'
2385                             // value fits in 8 bits - immediate move
2386                             inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2387                             return inst;
2388                         }
2389                         else
2390                         {
2391                             warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2392                             force_imm = NUM_FORCE_LONG;
2393                         }
2394                     }
2395                     if (force_imm == NUM_FORCE_LONG)
2396                     {
2397                         // '#xxxxxx,D'
2398                         // it can either be
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;
2405                         return inst;
2406                     }
2407                     if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2408                     {
2409                         // value fits in 8 bits - immediate move
2410                     deposit_immediate_short_with_register:
2411                         inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2412                         return inst;
2413                     }
2414                     else
2415                     {
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;
2421                     }
2422                 }
2423                 else
2424                 {
2425                     if (force_imm != NUM_FORCE_SHORT)
2426                     {
2427                         // '#xxxxxx,D'
2428                         // TODO: if we're just goto'ing perhaps the logic can be simplified
2429                         goto deposit_immediate_long_with_register;
2430                     }
2431                     else
2432                     {
2433                         // '#xx,D' - I mode
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);
2438                         return inst;
2439                     }
2440
2441                 }
2442             }
2443             else
2444             {
2445                 // Float constant
2446                 if (dspImmedEXATTR & DEFINED)
2447                 {
2448
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;
2452                     double g;
2453                     g = f*(1 << 23);
2454                     g = round(g);
2455
2456                     if ((dspImmedEXVAL & 0xffff) == 0)
2457                     {
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;
2463                     }
2464
2465                     if (force_imm == NUM_FORCE_SHORT)
2466                     {
2467                         if ((dspImmedEXVAL & 0xffff) != 0)
2468                         {
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;
2471                         }
2472                         return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2473                     }
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;
2476                 }
2477                 else
2478                 {
2479                     if (force_imm == NUM_FORCE_SHORT)
2480                     {
2481                                                 goto deposit_immediate_short_with_register;
2482                     }
2483                     else
2484                     {
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);
2489                         return inst;
2490                     }
2491                 }
2492             }
2493         }
2494         else
2495         {
2496             // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2497
2498             switch (immreg)
2499             {
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;
2505             }
2506
2507             switch (*tok++)
2508             {
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;
2512             }
2513
2514             if (*tok++ != ',')
2515                 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2516
2517             switch (*tok++)
2518             {
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;
2522             }
2523
2524             if (*tok != EOL)
2525                 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2526
2527             inst = B16(00010000, 10110100) | D1 | S2 | D2;
2528             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2529             return inst;
2530         }
2531     }
2532     else if (*tok == KW_X)
2533     {
2534                 if (tok[1] == ',')
2535                         // Hey look, it's just the register X and not the addressing mode - fall through to general case
2536                         goto parse_everything_else;
2537
2538                 tok++;
2539
2540                 if (*tok++ != ':')
2541             return error("expected ':' after 'X' in parallel move (i.e. X:)");
2542
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);
2545     }
2546     else if (*tok == KW_Y)
2547     {
2548                 if (tok[1] == ',')
2549                         // Hey look, it's just the register y and not the addressing mode - fall through to general case
2550                         goto parse_everything_else;
2551
2552                 tok++;
2553                 if (*tok++ != ':')
2554             return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2555
2556                 // 'Y:ea,D' or 'Y:aa,D'
2557         return parse_y(B16(01001000, 10000000), 0, 0, 0);
2558     }
2559     else if (*tok == KW_L)
2560     {
2561         // 'L:ea,D' or 'L:aa,D'
2562         tok++;
2563         if (*tok++ != ':')
2564             return error("expected ':' after 'L' in parallel move (i.e. L:)");
2565
2566         return parse_l(1, B16(01000000, 11000000), 0);
2567     }
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))
2569     {
2570         // Everything else - brace for impact!
2571         // R:   'S,D'
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'
2577                 LONG L_S1;
2578 parse_everything_else:
2579                 L_S1 = *tok++;
2580                 S1 = SDreg(L_S1);
2581
2582         if (*tok++ != ',')
2583             return error("Comma expected after 'S')");
2584
2585         if (*tok == KW_X)
2586         {
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'
2589             tok++;
2590             if (*tok++ != ':')
2591                 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2592             return parse_x(0, B16(01000000, 00000000), S1, 1);
2593         }
2594         else if (*tok == KW_Y)
2595         {
2596             // 'S,Y:ea' 'S,Y:aa'
2597             tok++;
2598             if (*tok++ != ':')
2599                 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2600             return parse_y(B16(0000000, 00000000), S1, 0, 0);
2601         }
2602         else if (*tok == KW_L)
2603         {
2604             // 'S,L:ea' 'S,L:aa'
2605             tok++;
2606             if (*tok++ != ':')
2607                 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2608             return parse_l(1, B16(00000000, 00000000), L_S1);
2609         }
2610         else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2611         {
2612             // 'S,D'
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'
2615             D1 = SDreg(*tok++);
2616             if (*tok == EOL)
2617             {
2618                 // R 'S,D'
2619                 inst = B16(00100000, 00000000);
2620                 inst |= (S1 << 5) | (D1);
2621                 return inst;
2622             }
2623             else if (*tok == KW_Y)
2624             {
2625                 // 'S1,D1 Y:ea,D2'
2626                 tok++;
2627                 if (*tok++ != ':')
2628                     return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2629                 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2630
2631             }
2632             else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2633             {
2634                 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2635                 S2 = SDreg(*tok++);
2636                 if (S1 == 6 && D1 == 14 && S2 == 14)
2637                 {
2638                     // 'Y0,A A,Y:ea'
2639                     if (*tok++ != ',')
2640                         return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2641                     if (*tok++ != KW_Y)
2642                         return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2643                     if (*tok++ != ':')
2644                         return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2645                     ea1 = checkea_full(EOL, Y_ERRORS);
2646                     if (ea1 == ERROR)
2647                         return ERROR;
2648                     inst = B16(00001000, 10000000);
2649                     inst |= 0 << 8;
2650                     inst |= ea1;
2651                     return inst;
2652                 }
2653                 else if (S1 == 6 && D1 == 15 && S2 == 15)
2654                 {
2655                     // 'Y0,B B,Y:ea'
2656                     if (*tok++ != ',')
2657                         return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2658                     if (*tok++ != KW_Y)
2659                         return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2660                     if (*tok++ != ':')
2661                         return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2662                     ea1 = checkea_full(EOL, Y_ERRORS);
2663                     if (ea1 == ERROR)
2664                         return ERROR;
2665                     inst = B16(00001000, 10000000);
2666                     inst |= 1 << 8;
2667                     inst |= ea1;
2668                     return inst;
2669                 }
2670                 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2671                 {
2672                     //'S1,D1 S2,Y:ea'
2673                     if (*tok++ != ',')
2674                         return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2675                     if (*tok++ != KW_Y)
2676                         return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2677                     if (*tok++ != ':')
2678                         return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2679                     ea1 = checkea_full(EOL, Y_ERRORS);
2680                     if (ea1 == ERROR)
2681                         return ERROR;
2682                     inst = B16(00010000, 01000000);
2683                     inst |= (S1 & 1) << 11;
2684                     inst |= (D1 & 1) << 10;
2685                     inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2686                     inst |= ea1;
2687                     return inst;
2688                 }
2689                 else
2690                     return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2691                 // Check for Y:
2692             }
2693             else if (*tok == '#')
2694             {
2695                 // R:Y: 'S1,D1 #xxxxxx,D2'
2696                 tok++;
2697                 if (*tok == '>')
2698                 {
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
2702                     tok++;
2703                 }
2704                 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2705                     return ERROR;
2706                 if (dspImmedEXATTR & DEFINED)
2707                     if (dspImmedEXVAL > 0xffffff)
2708                         return error("immediate is bigger than $ffffff");
2709                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2710                 if (*tok++ != ',')
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
2713                 switch (*tok++)
2714                 {
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'");
2720                 }
2721
2722                 if (S1 == 14 || S1 == 15)
2723                 {
2724                     if (D1 == 4 || D1 == 5)
2725                     {
2726                         inst = B16(00010000, 11110100);
2727                         inst |= (S1 & 1) << 11;
2728                         inst |= (D1 & 1) << 10;
2729                         inst |= D2;
2730                         dspImmedEXVAL = dspaaEXVAL;
2731                         return inst;
2732                     }
2733                     else
2734                         return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2735                 }
2736                 else
2737                     return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2738             }
2739             else
2740                 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2741         }
2742         else
2743             return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2744     }
2745     else if (*tok == '(')
2746     {
2747         // U: 'ea'
2748         // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2749         tok++;
2750         if (*tok >= KW_R0 && *tok <= KW_R7)
2751         {
2752             ea1 = (*tok++ - KW_R0);
2753         }
2754         else
2755             return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
2756         if (*tok++ != ')')
2757             return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
2758         if (*tok == '+')
2759         {
2760             tok++;
2761             if (*tok == EOL)
2762                 // (Rn)+
2763                 ea1 |= 3 << 3;
2764             else if (*tok >= KW_N0 && *tok <= KW_N7)
2765             {
2766                 // (Rn)+Nn
2767                 if ((*tok++ & 7) != ea1)
2768                     return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
2769                 ea1 |= 1 << 3;
2770                 if (*tok != EOL)
2771                     return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
2772             }
2773             else
2774                 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
2775
2776         }
2777         else if (*tok == '-')
2778         {
2779             tok++;
2780             if (*tok == EOL)
2781             {
2782                 // (Rn)-
2783                 ea1 |= 2 << 3;
2784                 tok++;
2785             }
2786             else if (*tok >= KW_N0 && *tok <= KW_N7)
2787             {
2788                 // (Rn)-Nn
2789                 if ((*tok++ & 7) != ea1)
2790                     return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
2791                 ea1 |= 0 << 3;
2792                 if (*tok != EOL)
2793                     return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
2794             }
2795         }
2796
2797         inst = B16(00100000, 01000000);
2798         inst |= ea1;
2799         return inst;
2800     }
2801     else
2802         return error("extra (unexpected) text found");
2803
2804     return OK;
2805 }
2806